diff options
873 files changed, 22977 insertions, 10054 deletions
@@ -2211,6 +2211,15 @@ D: OV511 driver S: (address available on request) S: USA +N: Ian McDonald +E: iam4@cs.waikato.ac.nz +E: imcdnzl@gmail.com +W: http://wand.net.nz/~iam4 +W: http://imcdnzl.blogspot.com +D: DCCP, CCID3 +S: Hamilton +S: New Zealand + N: Patrick McHardy E: kaber@trash.net P: 1024D/12155E80 B128 7DE6 FF0A C2B2 48BE AB4C C9D4 964E 1215 5E80 @@ -2246,19 +2255,12 @@ S: D-90453 Nuernberg S: Germany N: Arnaldo Carvalho de Melo -E: acme@conectiva.com.br -E: acme@kernel.org -E: acme@gnu.org -W: http://bazar2.conectiva.com.br/~acme -W: http://advogato.org/person/acme +E: acme@mandriva.com +E: acme@ghostprotocols.net +W: http://oops.ghostprotocols.net:81/blog/ P: 1024D/9224DF01 D5DF E3BB E3C8 BCBB F8AD 841A B6AB 4681 9224 DF01 -D: wanrouter hacking -D: misc Makefile, Config.in, drivers and network stacks fixes -D: IPX & LLC network stacks maintainer -D: Cyclom 2X synchronous card driver -D: wl3501 PCMCIA wireless card driver -D: i18n for minicom, net-tools, util-linux, fetchmail, etc -S: Conectiva S.A. +D: IPX, LLC, DCCP, cyc2x, wl3501_cs, net/ hacks +S: Mandriva S: R. Tocantins, 89 - Cristo Rei S: 80050-430 - Curitiba - Paraná S: Brazil diff --git a/Documentation/CodingStyle b/Documentation/CodingStyle index 22e5f90..eb7db3c 100644 --- a/Documentation/CodingStyle +++ b/Documentation/CodingStyle @@ -410,7 +410,26 @@ Kernel messages do not have to be terminated with a period. Printing numbers in parentheses (%d) adds no value and should be avoided. - Chapter 13: References + Chapter 13: Allocating memory + +The kernel provides the following general purpose memory allocators: +kmalloc(), kzalloc(), kcalloc(), and vmalloc(). Please refer to the API +documentation for further information about them. + +The preferred form for passing a size of a struct is the following: + + p = kmalloc(sizeof(*p), ...); + +The alternative form where struct name is spelled out hurts readability and +introduces an opportunity for a bug when the pointer variable type is changed +but the corresponding sizeof that is passed to a memory allocator is not. + +Casting the return value which is a void pointer is redundant. The conversion +from void pointer to any other pointer type is guaranteed by the C programming +language. + + + Chapter 14: References The C Programming Language, Second Edition by Brian W. Kernighan and Dennis M. Ritchie. diff --git a/Documentation/DocBook/kernel-hacking.tmpl b/Documentation/DocBook/kernel-hacking.tmpl index 6367bba..582032e 100644 --- a/Documentation/DocBook/kernel-hacking.tmpl +++ b/Documentation/DocBook/kernel-hacking.tmpl @@ -1105,7 +1105,7 @@ static struct block_device_operations opt_fops = { </listitem> <listitem> <para> - Function names as strings (__func__). + Function names as strings (__FUNCTION__). </para> </listitem> <listitem> diff --git a/Documentation/cciss.txt b/Documentation/cciss.txt index c8f9a73..68a711f 100644 --- a/Documentation/cciss.txt +++ b/Documentation/cciss.txt @@ -17,7 +17,9 @@ This driver is known to work with the following cards: * SA P600 * SA P800 * SA E400 - * SA E300 + * SA P400i + * SA E200 + * SA E200i If nodes are not already created in the /dev/cciss directory, run as root: diff --git a/Documentation/dell_rbu.txt b/Documentation/dell_rbu.txt index bcfa5c3..95d7f62 100644 --- a/Documentation/dell_rbu.txt +++ b/Documentation/dell_rbu.txt @@ -13,6 +13,8 @@ the BIOS on Dell servers (starting from servers sold since 1999), desktops and notebooks (starting from those sold in 2005). Please go to http://support.dell.com register and you can find info on OpenManage and Dell Update packages (DUP). +Libsmbios can also be used to update BIOS on Dell systems go to +http://linux.dell.com/libsmbios/ for details. Dell_RBU driver supports BIOS update using the monilothic image and packetized image methods. In case of moniolithic the driver allocates a contiguous chunk @@ -22,8 +24,8 @@ would place each packet in contiguous physical memory. The driver also maintains a link list of packets for reading them back. If the dell_rbu driver is unloaded all the allocated memory is freed. -The rbu driver needs to have an application which will inform the BIOS to -enable the update in the next system reboot. +The rbu driver needs to have an application (as mentioned above)which will +inform the BIOS to enable the update in the next system reboot. The user should not unload the rbu driver after downloading the BIOS image or updating. @@ -42,9 +44,11 @@ In case of packet mechanism the single memory can be broken in smaller chuks of contiguous memory and the BIOS image is scattered in these packets. By default the driver uses monolithic memory for the update type. This can be -changed to contiguous during the driver load time by specifying the load +changed to packets during the driver load time by specifying the load parameter image_type=packet. This can also be changed later as below echo packet > /sys/devices/platform/dell_rbu/image_type +Also echoing either mono ,packet or init in to image_type will free up the +memory allocated by the driver. Do the steps below to download the BIOS image. 1) echo 1 > /sys/class/firmware/dell_rbu/loading @@ -53,9 +57,13 @@ Do the steps below to download the BIOS image. The /sys/class/firmware/dell_rbu/ entries will remain till the following is done. -echo -1 > /sys/class/firmware/dell_rbu/loading - +echo -1 > /sys/class/firmware/dell_rbu/loading. Until this step is completed the drivr cannot be unloaded. +If an user by accident executes steps 1 and 3 above without executing step 2; +it will make the /sys/class/firmware/dell_rbu/ entries to disappear. +The entries can be recreated by doing the following +echo init > /sys/devices/platform/dell_rbu/image_type +NOTE: echoing init in image_type does not change it original value. Also the driver provides /sys/devices/platform/dell_rbu/data readonly file to read back the image downloaded. This is useful in case of packet update diff --git a/Documentation/device-mapper/snapshot.txt b/Documentation/device-mapper/snapshot.txt new file mode 100644 index 0000000..dca274f --- /dev/null +++ b/Documentation/device-mapper/snapshot.txt @@ -0,0 +1,73 @@ +Device-mapper snapshot support +============================== + +Device-mapper allows you, without massive data copying: + +*) To create snapshots of any block device i.e. mountable, saved states of +the block device which are also writable without interfering with the +original content; +*) To create device "forks", i.e. multiple different versions of the +same data stream. + + +In both cases, dm copies only the chunks of data that get changed and +uses a separate copy-on-write (COW) block device for storage. + + +There are two dm targets available: snapshot and snapshot-origin. + +*) snapshot-origin <origin> + +which will normally have one or more snapshots based on it. +You must create the snapshot-origin device before you can create snapshots. +Reads will be mapped directly to the backing device. For each write, the +original data will be saved in the <COW device> of each snapshot to keep +its visible content unchanged, at least until the <COW device> fills up. + + +*) snapshot <origin> <COW device> <persistent?> <chunksize> + +A snapshot is created of the <origin> block device. Changed chunks of +<chunksize> sectors will be stored on the <COW device>. Writes will +only go to the <COW device>. Reads will come from the <COW device> or +from <origin> for unchanged data. <COW device> will often be +smaller than the origin and if it fills up the snapshot will become +useless and be disabled, returning errors. So it is important to monitor +the amount of free space and expand the <COW device> before it fills up. + +<persistent?> is P (Persistent) or N (Not persistent - will not survive +after reboot). + + +How this is used by LVM2 +======================== +When you create the first LVM2 snapshot of a volume, four dm devices are used: + +1) a device containing the original mapping table of the source volume; +2) a device used as the <COW device>; +3) a "snapshot" device, combining #1 and #2, which is the visible snapshot + volume; +4) the "original" volume (which uses the device number used by the original + source volume), whose table is replaced by a "snapshot-origin" mapping + from device #1. + +A fixed naming scheme is used, so with the following commands: + +lvcreate -L 1G -n base volumeGroup +lvcreate -L 100M --snapshot -n snap volumeGroup/base + +we'll have this situation (with volumes in above order): + +# dmsetup table|grep volumeGroup + +volumeGroup-base-real: 0 2097152 linear 8:19 384 +volumeGroup-snap-cow: 0 204800 linear 8:19 2097536 +volumeGroup-snap: 0 2097152 snapshot 254:11 254:12 P 16 +volumeGroup-base: 0 2097152 snapshot-origin 254:11 + +# ls -lL /dev/mapper/volumeGroup-* +brw------- 1 root root 254, 11 29 ago 18:15 /dev/mapper/volumeGroup-base-real +brw------- 1 root root 254, 12 29 ago 18:15 /dev/mapper/volumeGroup-snap-cow +brw------- 1 root root 254, 13 29 ago 18:15 /dev/mapper/volumeGroup-snap +brw------- 1 root root 254, 10 29 ago 18:14 /dev/mapper/volumeGroup-base + diff --git a/Documentation/dontdiff b/Documentation/dontdiff index 96bea27..24adfe9 100644 --- a/Documentation/dontdiff +++ b/Documentation/dontdiff @@ -55,6 +55,7 @@ aic7*seq.h* aicasm aicdb.h* asm +asm-offsets.* asm_offsets.* autoconf.h* bbootsect diff --git a/Documentation/feature-removal-schedule.txt b/Documentation/feature-removal-schedule.txt index 784e08c..b67189a 100644 --- a/Documentation/feature-removal-schedule.txt +++ b/Documentation/feature-removal-schedule.txt @@ -17,15 +17,6 @@ Who: Greg Kroah-Hartman <greg@kroah.com> --------------------------- -What: io_remap_page_range() (macro or function) -When: September 2005 -Why: Replaced by io_remap_pfn_range() which allows more memory space - addressabilty (by using a pfn) and supports sparc & sparc64 - iospace as part of the pfn. -Who: Randy Dunlap <rddunlap@osdl.org> - ---------------------------- - What: RAW driver (CONFIG_RAW_DRIVER) When: December 2005 Why: declared obsolete since kernel 2.6.3 diff --git a/Documentation/filesystems/relayfs.txt b/Documentation/filesystems/relayfs.txt index d24e1b0..d803abe 100644 --- a/Documentation/filesystems/relayfs.txt +++ b/Documentation/filesystems/relayfs.txt @@ -15,7 +15,7 @@ retrieve the data as it becomes available. The format of the data logged into the channel buffers is completely up to the relayfs client; relayfs does however provide hooks which -allow clients to impose some stucture on the buffer data. Nor does +allow clients to impose some structure on the buffer data. Nor does relayfs implement any form of data filtering - this also is left to the client. The purpose is to keep relayfs as simple as possible. diff --git a/Documentation/ia64/mca.txt b/Documentation/ia64/mca.txt new file mode 100644 index 0000000..a71cc6a --- /dev/null +++ b/Documentation/ia64/mca.txt @@ -0,0 +1,194 @@ +An ad-hoc collection of notes on IA64 MCA and INIT processing. Feel +free to update it with notes about any area that is not clear. + +--- + +MCA/INIT are completely asynchronous. They can occur at any time, when +the OS is in any state. Including when one of the cpus is already +holding a spinlock. Trying to get any lock from MCA/INIT state is +asking for deadlock. Also the state of structures that are protected +by locks is indeterminate, including linked lists. + +--- + +The complicated ia64 MCA process. All of this is mandated by Intel's +specification for ia64 SAL, error recovery and and unwind, it is not as +if we have a choice here. + +* MCA occurs on one cpu, usually due to a double bit memory error. + This is the monarch cpu. + +* SAL sends an MCA rendezvous interrupt (which is a normal interrupt) + to all the other cpus, the slaves. + +* Slave cpus that receive the MCA interrupt call down into SAL, they + end up spinning disabled while the MCA is being serviced. + +* If any slave cpu was already spinning disabled when the MCA occurred + then it cannot service the MCA interrupt. SAL waits ~20 seconds then + sends an unmaskable INIT event to the slave cpus that have not + already rendezvoused. + +* Because MCA/INIT can be delivered at any time, including when the cpu + is down in PAL in physical mode, the registers at the time of the + event are _completely_ undefined. In particular the MCA/INIT + handlers cannot rely on the thread pointer, PAL physical mode can + (and does) modify TP. It is allowed to do that as long as it resets + TP on return. However MCA/INIT events expose us to these PAL + internal TP changes. Hence curr_task(). + +* If an MCA/INIT event occurs while the kernel was running (not user + space) and the kernel has called PAL then the MCA/INIT handler cannot + assume that the kernel stack is in a fit state to be used. Mainly + because PAL may or may not maintain the stack pointer internally. + Because the MCA/INIT handlers cannot trust the kernel stack, they + have to use their own, per-cpu stacks. The MCA/INIT stacks are + preformatted with just enough task state to let the relevant handlers + do their job. + +* Unlike most other architectures, the ia64 struct task is embedded in + the kernel stack[1]. So switching to a new kernel stack means that + we switch to a new task as well. Because various bits of the kernel + assume that current points into the struct task, switching to a new + stack also means a new value for current. + +* Once all slaves have rendezvoused and are spinning disabled, the + monarch is entered. The monarch now tries to diagnose the problem + and decide if it can recover or not. + +* Part of the monarch's job is to look at the state of all the other + tasks. The only way to do that on ia64 is to call the unwinder, + as mandated by Intel. + +* The starting point for the unwind depends on whether a task is + running or not. That is, whether it is on a cpu or is blocked. The + monarch has to determine whether or not a task is on a cpu before it + knows how to start unwinding it. The tasks that received an MCA or + INIT event are no longer running, they have been converted to blocked + tasks. But (and its a big but), the cpus that received the MCA + rendezvous interrupt are still running on their normal kernel stacks! + +* To distinguish between these two cases, the monarch must know which + tasks are on a cpu and which are not. Hence each slave cpu that + switches to an MCA/INIT stack, registers its new stack using + set_curr_task(), so the monarch can tell that the _original_ task is + no longer running on that cpu. That gives us a decent chance of + getting a valid backtrace of the _original_ task. + +* MCA/INIT can be nested, to a depth of 2 on any cpu. In the case of a + nested error, we want diagnostics on the MCA/INIT handler that + failed, not on the task that was originally running. Again this + requires set_curr_task() so the MCA/INIT handlers can register their + own stack as running on that cpu. Then a recursive error gets a + trace of the failing handler's "task". + +[1] My (Keith Owens) original design called for ia64 to separate its + struct task and the kernel stacks. Then the MCA/INIT data would be + chained stacks like i386 interrupt stacks. But that required + radical surgery on the rest of ia64, plus extra hard wired TLB + entries with its associated performance degradation. David + Mosberger vetoed that approach. Which meant that separate kernel + stacks meant separate "tasks" for the MCA/INIT handlers. + +--- + +INIT is less complicated than MCA. Pressing the nmi button or using +the equivalent command on the management console sends INIT to all +cpus. SAL picks one one of the cpus as the monarch and the rest are +slaves. All the OS INIT handlers are entered at approximately the same +time. The OS monarch prints the state of all tasks and returns, after +which the slaves return and the system resumes. + +At least that is what is supposed to happen. Alas there are broken +versions of SAL out there. Some drive all the cpus as monarchs. Some +drive them all as slaves. Some drive one cpu as monarch, wait for that +cpu to return from the OS then drive the rest as slaves. Some versions +of SAL cannot even cope with returning from the OS, they spin inside +SAL on resume. The OS INIT code has workarounds for some of these +broken SAL symptoms, but some simply cannot be fixed from the OS side. + +--- + +The scheduler hooks used by ia64 (curr_task, set_curr_task) are layer +violations. Unfortunately MCA/INIT start off as massive layer +violations (can occur at _any_ time) and they build from there. + +At least ia64 makes an attempt at recovering from hardware errors, but +it is a difficult problem because of the asynchronous nature of these +errors. When processing an unmaskable interrupt we sometimes need +special code to cope with our inability to take any locks. + +--- + +How is ia64 MCA/INIT different from x86 NMI? + +* x86 NMI typically gets delivered to one cpu. MCA/INIT gets sent to + all cpus. + +* x86 NMI cannot be nested. MCA/INIT can be nested, to a depth of 2 + per cpu. + +* x86 has a separate struct task which points to one of multiple kernel + stacks. ia64 has the struct task embedded in the single kernel + stack, so switching stack means switching task. + +* x86 does not call the BIOS so the NMI handler does not have to worry + about any registers having changed. MCA/INIT can occur while the cpu + is in PAL in physical mode, with undefined registers and an undefined + kernel stack. + +* i386 backtrace is not very sensitive to whether a process is running + or not. ia64 unwind is very, very sensitive to whether a process is + running or not. + +--- + +What happens when MCA/INIT is delivered what a cpu is running user +space code? + +The user mode registers are stored in the RSE area of the MCA/INIT on +entry to the OS and are restored from there on return to SAL, so user +mode registers are preserved across a recoverable MCA/INIT. Since the +OS has no idea what unwind data is available for the user space stack, +MCA/INIT never tries to backtrace user space. Which means that the OS +does not bother making the user space process look like a blocked task, +i.e. the OS does not copy pt_regs and switch_stack to the user space +stack. Also the OS has no idea how big the user space RSE and memory +stacks are, which makes it too risky to copy the saved state to a user +mode stack. + +--- + +How do we get a backtrace on the tasks that were running when MCA/INIT +was delivered? + +mca.c:::ia64_mca_modify_original_stack(). That identifies and +verifies the original kernel stack, copies the dirty registers from +the MCA/INIT stack's RSE to the original stack's RSE, copies the +skeleton struct pt_regs and switch_stack to the original stack, fills +in the skeleton structures from the PAL minstate area and updates the +original stack's thread.ksp. That makes the original stack look +exactly like any other blocked task, i.e. it now appears to be +sleeping. To get a backtrace, just start with thread.ksp for the +original task and unwind like any other sleeping task. + +--- + +How do we identify the tasks that were running when MCA/INIT was +delivered? + +If the previous task has been verified and converted to a blocked +state, then sos->prev_task on the MCA/INIT stack is updated to point to +the previous task. You can look at that field in dumps or debuggers. +To help distinguish between the handler and the original tasks, +handlers have _TIF_MCA_INIT set in thread_info.flags. + +The sos data is always in the MCA/INIT handler stack, at offset +MCA_SOS_OFFSET. You can get that value from mca_asm.h or calculate it +as KERNEL_STACK_SIZE - sizeof(struct pt_regs) - sizeof(struct +ia64_sal_os_state), with 16 byte alignment for all structures. + +Also the comm field of the MCA/INIT task is modified to include the pid +of the original task, for humans to use. For example, a comm field of +'MCA 12159' means that pid 12159 was running when the MCA was +delivered. diff --git a/Documentation/kdump/kdump.txt b/Documentation/kdump/kdump.txt index 1f5f7d2..5f08f9c 100644 --- a/Documentation/kdump/kdump.txt +++ b/Documentation/kdump/kdump.txt @@ -66,11 +66,11 @@ SETUP c) Enable "/proc/vmcore support" (Optional, in Pseudo filesystems). CONFIG_PROC_VMCORE=y d) Disable SMP support and build a UP kernel (Until it is fixed). - CONFIG_SMP=n + CONFIG_SMP=n e) Enable "Local APIC support on uniprocessors". - CONFIG_X86_UP_APIC=y + CONFIG_X86_UP_APIC=y f) Enable "IO-APIC support on uniprocessors" - CONFIG_X86_UP_IOAPIC=y + CONFIG_X86_UP_IOAPIC=y Note: i) Options a) and b) depend upon "Configure standard kernel features (for small systems)" (under General setup). @@ -95,6 +95,11 @@ SETUP hence have memory less than 4GB. iii) Specify "irqpoll" as command line parameter. This reduces driver initialization failures in second kernel due to shared interrupts. + iv) <root-dev> needs to be specified in a format corresponding to + the root device name in the output of mount command. + v) If you have built the drivers required to mount root file + system as modules in <second-kernel>, then, specify + --initrd=<initrd-for-second-kernel>. 5) System reboots into the second kernel when a panic occurs. A module can be written to force the panic or "ALT-SysRq-c" can be used initiate a crash diff --git a/Documentation/oops-tracing.txt b/Documentation/oops-tracing.txt index da71102..66eaaab 100644 --- a/Documentation/oops-tracing.txt +++ b/Documentation/oops-tracing.txt @@ -205,8 +205,8 @@ Phone: 701-234-7556 Tainted kernels: Some oops reports contain the string 'Tainted: ' after the program -counter, this indicates that the kernel has been tainted by some -mechanism. The string is followed by a series of position sensitive +counter. This indicates that the kernel has been tainted by some +mechanism. The string is followed by a series of position-sensitive characters, each representing a particular tainted value. 1: 'G' if all modules loaded have a GPL or compatible license, 'P' if @@ -214,16 +214,25 @@ characters, each representing a particular tainted value. MODULE_LICENSE or with a MODULE_LICENSE that is not recognised by insmod as GPL compatible are assumed to be proprietary. - 2: 'F' if any module was force loaded by insmod -f, ' ' if all + 2: 'F' if any module was force loaded by "insmod -f", ' ' if all modules were loaded normally. 3: 'S' if the oops occurred on an SMP kernel running on hardware that - hasn't been certified as safe to run multiprocessor. - Currently this occurs only on various Athlons that are not - SMP capable. + hasn't been certified as safe to run multiprocessor. + Currently this occurs only on various Athlons that are not + SMP capable. + + 4: 'R' if a module was force unloaded by "rmmod -f", ' ' if all + modules were unloaded normally. + + 5: 'M' if any processor has reported a Machine Check Exception, + ' ' if no Machine Check Exceptions have occurred. + + 6: 'B' if a page-release function has found a bad page reference or + some unexpected page flags. The primary reason for the 'Tainted: ' string is to tell kernel debuggers if this is a clean kernel or if anything unusual has -occurred. Tainting is permanent, even if an offending module is -unloading the tainted value remains to indicate that the kernel is not +occurred. Tainting is permanent: even if an offending module is +unloaded, the tainted value remains to indicate that the kernel is not trustworthy. diff --git a/Documentation/pm.txt b/Documentation/pm.txt index cc63ae1..2ea1149 100644 --- a/Documentation/pm.txt +++ b/Documentation/pm.txt @@ -38,6 +38,12 @@ system the associated daemon will exit gracefully. Driver Interface -- OBSOLETE, DO NOT USE! ----------------************************* + +Note: pm_register(), pm_access(), pm_dev_idle() and friends are +obsolete. Please do not use them. Instead you should properly hook +your driver into the driver model, and use its suspend()/resume() +callbacks to do this kind of stuff. + If you are writing a new driver or maintaining an old driver, it should include power management support. Without power management support, a single driver may prevent a system with power management diff --git a/Documentation/sound/alsa/ALSA-Configuration.txt b/Documentation/sound/alsa/ALSA-Configuration.txt index ebfcdf2..13cba95 100644 --- a/Documentation/sound/alsa/ALSA-Configuration.txt +++ b/Documentation/sound/alsa/ALSA-Configuration.txt @@ -75,7 +75,7 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed. adsp_map - PCM device number maps assigned to the 2st OSS device. - Default: 1 nonblock_open - - Don't block opening busy PCM devices. + - Don't block opening busy PCM devices. Default: 1 For example, when dsp_map=2, /dev/dsp will be mapped to PCM #2 of the card #0. Similarly, when adsp_map=0, /dev/adsp will be mapped @@ -148,6 +148,16 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed. Module supports up to 8 cards. This module does not support autoprobe thus main port must be specified!!! Other ports are optional. + Module snd-ad1889 + ----------------- + + Module for Analog Devices AD1889 chips. + + ac97_quirk - AC'97 workaround for strange hardware + See the description of intel8x0 module for details. + + This module supports up to 8 cards. + Module snd-ali5451 ------------------ @@ -189,15 +199,20 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed. Module snd-atiixp ----------------- - Module for ATI IXP 150/200/250 AC97 controllers. + Module for ATI IXP 150/200/250/400 AC97 controllers. - ac97_clock - AC'97 clock (defalut = 48000) + ac97_clock - AC'97 clock (default = 48000) ac97_quirk - AC'97 workaround for strange hardware - See the description of intel8x0 module for details. + See "AC97 Quirk Option" section below. spdif_aclink - S/PDIF transfer over AC-link (default = 1) This module supports up to 8 cards and autoprobe. + ATI IXP has two different methods to control SPDIF output. One is + over AC-link and another is over the "direct" SPDIF output. The + implementation depends on the motherboard, and you'll need to + choose the correct one via spdif_aclink module option. + Module snd-atiixp-modem ----------------------- @@ -230,7 +245,7 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed. The hardware EQ hardware and SPDIF is only present in the Vortex2 and Advantage. - Note: Some ALSA mixer applicactions don't handle the SPDIF samplerate + Note: Some ALSA mixer applications don't handle the SPDIF sample rate control correctly. If you have problems regarding this, try another ALSA compliant mixer (alsamixer works). @@ -302,7 +317,7 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed. mpu_port - 0x300,0x310,0x320,0x330, 0 = disable (default) fm_port - 0x388 (default), 0 = disable (default) - soft_ac3 - Sofware-conversion of raw SPDIF packets (model 033 only) + soft_ac3 - Software-conversion of raw SPDIF packets (model 033 only) (default = 1) joystick_port - Joystick port address (0 = disable, 1 = auto-detect) @@ -384,7 +399,7 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed. Module for PCI sound cards based on CS4610/CS4612/CS4614/CS4615/CS4622/ CS4624/CS4630/CS4280 PCI chips. - external_amp - Force to enable external amplifer. + external_amp - Force to enable external amplifier. thinkpad - Force to enable Thinkpad's CLKRUN control. mmap_valid - Support OSS mmap mode (default = 0). @@ -620,7 +635,7 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed. VIA VT8251/VT8237A model - force the model name - position_fix - Fix DMA pointer (0 = FIFO size, 1 = none, 2 = POSBUF) + position_fix - Fix DMA pointer (0 = auto, 1 = none, 2 = POSBUF, 3 = FIFO size) Module supports up to 8 cards. @@ -656,6 +671,11 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed. allout 5-jack in back, 2-jack in front, SPDIF out auto auto-config reading BIOS (default) + If the default configuration doesn't work and one of the above + matches with your device, report it together with the PCI + subsystem ID (output of "lspci -nv") to ALSA BTS or alsa-devel + ML (see the section "Links and Addresses"). + Note 2: If you get click noises on output, try the module option position_fix=1 or 2. position_fix=1 will use the SD_LPIB register value without FIFO size correction as the current @@ -783,20 +803,13 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed. ac97_clock - AC'97 codec clock base (0 = auto-detect) ac97_quirk - AC'97 workaround for strange hardware - The following strings are accepted: - default = don't override the default setting - disable = disable the quirk - hp_only = use headphone control as master - swap_hp = swap headphone and master controls - swap_surround = swap master and surround controls - ad_sharing = for AD1985, turn on OMS bit and use headphone - alc_jack = for ALC65x, turn on the jack sense mode - inv_eapd = inverted EAPD implementation - mute_led = bind EAPD bit for turning on/off mute LED - For backward compatibility, the corresponding integer - value -1, 0, ... are accepted, too. + See "AC97 Quirk Option" section below. buggy_irq - Enable workaround for buggy interrupts on some - motherboards (default off) + motherboards (default yes on nForce chips, + otherwise off) + buggy_semaphore - Enable workaround for hardwares with buggy + semaphores (e.g. on some ASUS laptops) + (default off) Module supports autoprobe and multiple bus-master chips (max 8). @@ -808,13 +821,6 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed. motherboard has these devices, use the ns558 or snd-mpu401 modules, respectively. - The ac97_quirk option is used to enable/override the workaround - for specific devices. Some hardware have swapped output pins - between Master and Headphone, or Surround. The driver provides - the auto-detection of known problematic devices, but some might - be unknown or wrongly detected. In such a case, pass the proper - value with this option. - The power-management is supported. Module snd-intel8x0m @@ -966,7 +972,7 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed. with machines with other (most likely CS423x or OPL3SAx) chips, even though the device is detected in lspci. In such a case, try other drivers, e.g. snd-cs4232 or snd-opl3sa2. Some has ISA-PnP - but some doesn't have ISA PnP. You'll need to speicfy isapnp=0 + but some doesn't have ISA PnP. You'll need to specify isapnp=0 and proper hardware parameters in the case without ISA PnP. Note: some laptops need a workaround for AC97 RESET. For the @@ -1302,7 +1308,7 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed. channels [VIA8233/C, 8235, 8237 only] ac97_quirk - AC'97 workaround for strange hardware - See the description of intel8x0 module for details. + See "AC97 Quirk Option" section below. Module supports autoprobe and multiple bus-master chips (max 8). @@ -1327,16 +1333,17 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed. "lspci -nv"). If dxs_support=5 does not work, try dxs_support=4; if it doesn't work too, try dxs_support=1. (dxs_support=1 is - usually for old motherboards. The correct implementated + usually for old motherboards. The correct implemented board should work with 4 or 5.) If it still doesn't work and the default setting is ok, dxs_support=3 is the right choice. If the default setting doesn't work at all, try dxs_support=2 to disable the DXS channels. In any cases, please let us know the result and the - subsystem vendor/device ids. + subsystem vendor/device ids. See "Links and Addresses" + below. Note: for the MPU401 on VIA823x, use snd-mpu401 driver - additonally. The mpu_port option is for VIA686 chips only. + additionally. The mpu_port option is for VIA686 chips only. Module snd-via82xx-modem ------------------------ @@ -1398,8 +1405,10 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed. Module supports up to 8 cards. The module is compiled only when PCMCIA is supported on kernel. - To activate the driver via the card manager, you'll need to set - up /etc/pcmcia/vxpocket.conf. See the sound/pcmcia/vx/vxpocket.c. + With the older 2.6.x kernel, to activate the driver via the card + manager, you'll need to set up /etc/pcmcia/vxpocket.conf. See the + sound/pcmcia/vx/vxpocket.c. 2.6.13 or later kernel requires no + longer require a config file. When the driver is compiled as a module and the hotplug firmware is supported, the firmware data is loaded via hotplug automatically. @@ -1411,6 +1420,9 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed. Note: the driver is build only when CONFIG_ISA is set. + Note2: snd-vxp440 driver is merged to snd-vxpocket driver since + ALSA 1.0.10. + Module snd-ymfpci ----------------- @@ -1436,6 +1448,37 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed. Note: the driver is build only when CONFIG_ISA is set. +AC97 Quirk Option +================= + +The ac97_quirk option is used to enable/override the workaround for +specific devices on drivers for on-board AC'97 controllers like +snd-intel8x0. Some hardware have swapped output pins between Master +and Headphone, or Surround (thanks to confusion of AC'97 +specifications from version to version :-) + +The driver provides the auto-detection of known problematic devices, +but some might be unknown or wrongly detected. In such a case, pass +the proper value with this option. + +The following strings are accepted: + - default Don't override the default setting + - disable Disable the quirk + - hp_only Bind Master and Headphone controls as a single control + - swap_hp Swap headphone and master controls + - swap_surround Swap master and surround controls + - ad_sharing For AD1985, turn on OMS bit and use headphone + - alc_jack For ALC65x, turn on the jack sense mode + - inv_eapd Inverted EAPD implementation + - mute_led Bind EAPD bit for turning on/off mute LED + +For backward compatibility, the corresponding integer value -1, 0, +... are accepted, too. + +For example, if "Master" volume control has no effect on your device +but only "Headphone" does, pass ac97_quirk=hp_only module option. + + Configuring Non-ISAPNP Cards ============================ @@ -1553,6 +1596,8 @@ Proc interfaces (/proc/asound) - whole-frag write only whole fragments (optimization affecting playback only) - no-silence do not fill silence ahead to avoid clicks + - buggy-ptr Returns the whitespace blocks in GETOPTR ioctl + instead of filled blocks Example: echo "x11amp 128 16384" > /proc/asound/card0/pcm0p/oss echo "squake 0 0 disable" > /proc/asound/card0/pcm0c/oss @@ -1589,9 +1634,14 @@ commands to the snd-page-alloc driver: use. -Links -===== +Links and Addresses +=================== ALSA project homepage http://www.alsa-project.org + ALSA Bug Tracking System + https://bugtrack.alsa-project.org/bugs/ + + ALSA Developers ML + mailto:alsa-devel@lists.sourceforge.net diff --git a/Documentation/sound/alsa/DocBook/writing-an-alsa-driver.tmpl b/Documentation/sound/alsa/DocBook/writing-an-alsa-driver.tmpl index 0475478..24e8552 100644 --- a/Documentation/sound/alsa/DocBook/writing-an-alsa-driver.tmpl +++ b/Documentation/sound/alsa/DocBook/writing-an-alsa-driver.tmpl @@ -447,7 +447,7 @@ .... /* allocate a chip-specific data with zero filled */ - chip = kcalloc(1, sizeof(*chip), GFP_KERNEL); + chip = kzalloc(sizeof(*chip), GFP_KERNEL); if (chip == NULL) return -ENOMEM; @@ -949,7 +949,7 @@ After allocating a card instance via <function>snd_card_new()</function> (with <constant>NULL</constant> on the 4th arg), call - <function>kcalloc()</function>. + <function>kzalloc()</function>. <informalexample> <programlisting> @@ -958,7 +958,7 @@ mychip_t *chip; card = snd_card_new(index[dev], id[dev], THIS_MODULE, NULL); ..... - chip = kcalloc(1, sizeof(*chip), GFP_KERNEL); + chip = kzalloc(sizeof(*chip), GFP_KERNEL); ]]> </programlisting> </informalexample> @@ -1136,7 +1136,7 @@ return -ENXIO; } - chip = kcalloc(1, sizeof(*chip), GFP_KERNEL); + chip = kzalloc(sizeof(*chip), GFP_KERNEL); if (chip == NULL) { pci_disable_device(pci); return -ENOMEM; @@ -1292,7 +1292,7 @@ need to initialize this number as -1 before actual allocation, since irq 0 is valid. The port address and its resource pointer can be initialized as null by - <function>kcalloc()</function> automatically, so you + <function>kzalloc()</function> automatically, so you don't have to take care of resetting them. </para> diff --git a/Documentation/sparse.txt b/Documentation/sparse.txt index 5df44dc..1829009 100644 --- a/Documentation/sparse.txt +++ b/Documentation/sparse.txt @@ -51,9 +51,9 @@ or you don't get any checking at all. Where to get sparse ~~~~~~~~~~~~~~~~~~~ -With BK, you can just get it from +With git, you can just get it from - bk://sparse.bkbits.net/sparse + rsync://rsync.kernel.org/pub/scm/devel/sparse/sparse.git and DaveJ has tar-balls at diff --git a/Documentation/usb/URB.txt b/Documentation/usb/URB.txt index d59b95c..a49e5f2 100644 --- a/Documentation/usb/URB.txt +++ b/Documentation/usb/URB.txt @@ -1,5 +1,6 @@ Revised: 2000-Dec-05. Again: 2002-Jul-06 +Again: 2005-Sep-19 NOTE: @@ -18,8 +19,8 @@ called USB Request Block, or URB for short. and deliver the data and status back. - Execution of an URB is inherently an asynchronous operation, i.e. the - usb_submit_urb(urb) call returns immediately after it has successfully queued - the requested action. + usb_submit_urb(urb) call returns immediately after it has successfully + queued the requested action. - Transfers for one URB can be canceled with usb_unlink_urb(urb) at any time. @@ -94,8 +95,9 @@ To free an URB, use void usb_free_urb(struct urb *urb) -You may not free an urb that you've submitted, but which hasn't yet been -returned to you in a completion callback. +You may free an urb that you've submitted, but which hasn't yet been +returned to you in a completion callback. It will automatically be +deallocated when it is no longer in use. 1.4. What has to be filled in? @@ -145,30 +147,36 @@ to get seamless ISO streaming. 1.6. How to cancel an already running URB? -For an URB which you've submitted, but which hasn't been returned to -your driver by the host controller, call +There are two ways to cancel an URB you've submitted but which hasn't +been returned to your driver yet. For an asynchronous cancel, call int usb_unlink_urb(struct urb *urb) It removes the urb from the internal list and frees all allocated -HW descriptors. The status is changed to reflect unlinking. After -usb_unlink_urb() returns with that status code, you can free the URB -with usb_free_urb(). +HW descriptors. The status is changed to reflect unlinking. Note +that the URB will not normally have finished when usb_unlink_urb() +returns; you must still wait for the completion handler to be called. -There is also an asynchronous unlink mode. To use this, set the -the URB_ASYNC_UNLINK flag in urb->transfer flags before calling -usb_unlink_urb(). When using async unlinking, the URB will not -normally be unlinked when usb_unlink_urb() returns. Instead, wait -for the completion handler to be called. +To cancel an URB synchronously, call + + void usb_kill_urb(struct urb *urb) + +It does everything usb_unlink_urb does, and in addition it waits +until after the URB has been returned and the completion handler +has finished. It also marks the URB as temporarily unusable, so +that if the completion handler or anyone else tries to resubmit it +they will get a -EPERM error. Thus you can be sure that when +usb_kill_urb() returns, the URB is totally idle. 1.7. What about the completion handler? The handler is of the following type: - typedef void (*usb_complete_t)(struct urb *); + typedef void (*usb_complete_t)(struct urb *, struct pt_regs *) -i.e. it gets just the URB that caused the completion call. +I.e., it gets the URB that caused the completion call, plus the +register values at the time of the corresponding interrupt (if any). In the completion handler, you should have a look at urb->status to detect any USB errors. Since the context parameter is included in the URB, you can pass information to the completion handler. @@ -176,17 +184,11 @@ you can pass information to the completion handler. Note that even when an error (or unlink) is reported, data may have been transferred. That's because USB transfers are packetized; it might take sixteen packets to transfer your 1KByte buffer, and ten of them might -have transferred succesfully before the completion is called. +have transferred succesfully before the completion was called. NOTE: ***** WARNING ***** -Don't use urb->dev field in your completion handler; it's cleared -as part of giving urbs back to drivers. (Addressing an issue with -ownership of periodic URBs, which was otherwise ambiguous.) Instead, -use urb->context to hold all the data your driver needs. - -NOTE: ***** WARNING ***** -Also, NEVER SLEEP IN A COMPLETION HANDLER. These are normally called +NEVER SLEEP IN A COMPLETION HANDLER. These are normally called during hardware interrupt processing. If you can, defer substantial work to a tasklet (bottom half) to keep system latencies low. You'll probably need to use spinlocks to protect data structures you manipulate @@ -229,24 +231,10 @@ ISO data with some other event stream. Interrupt transfers, like isochronous transfers, are periodic, and happen in intervals that are powers of two (1, 2, 4 etc) units. Units are frames for full and low speed devices, and microframes for high speed ones. - -Currently, after you submit one interrupt URB, that urb is owned by the -host controller driver until you cancel it with usb_unlink_urb(). You -may unlink interrupt urbs in their completion handlers, if you need to. - -After a transfer completion is called, the URB is automagically resubmitted. -THIS BEHAVIOR IS EXPECTED TO BE REMOVED!! - -Interrupt transfers may only send (or receive) the "maxpacket" value for -the given interrupt endpoint; if you need more data, you will need to -copy that data out of (or into) another buffer. Similarly, you can't -queue interrupt transfers. -THESE RESTRICTIONS ARE EXPECTED TO BE REMOVED!! - -Note that this automagic resubmission model does make it awkward to use -interrupt OUT transfers. The portable solution involves unlinking those -OUT urbs after the data is transferred, and perhaps submitting a final -URB for a short packet. - The usb_submit_urb() call modifies urb->interval to the implemented interval value that is less than or equal to the requested interval value. + +In Linux 2.6, unlike earlier versions, interrupt URBs are not automagically +restarted when they complete. They end when the completion handler is +called, just like other URBs. If you want an interrupt URB to be restarted, +your completion handler must resubmit it. diff --git a/MAINTAINERS b/MAINTAINERS index a67bf7d..7d1dd5b 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -370,7 +370,10 @@ W: http://atmelwlandriver.sourceforge.net/ S: Maintained AUDIT SUBSYSTEM -L: linux-audit@redhat.com (subscribers-only) +P: David Woodhouse +M: dwmw2@infradead.org +L: linux-audit@redhat.com +W: http://people.redhat.com/sgrubb/audit/ S: Maintained AX.25 NETWORK LAYER @@ -683,6 +686,13 @@ P: Guennadi Liakhovetski M: g.liakhovetski@gmx.de S: Maintained +DCCP PROTOCOL +P: Arnaldo Carvalho de Melo +M: acme@mandriva.com +L: dccp@vger.kernel.org +W: http://www.wlug.org.nz/DCCP +S: Maintained + DECnet NETWORK LAYER P: Patrick Caulfield M: patrick@tykepenguin.com @@ -1053,8 +1063,6 @@ M: wli@holomorphy.com S: Maintained I2C SUBSYSTEM -P: Greg Kroah-Hartman -M: greg@kroah.com P: Jean Delvare M: khali@linux-fr.org L: lm-sensors@lm-sensors.org @@ -1394,6 +1402,18 @@ L: linux-kernel@vger.kernel.org L: fastboot@osdl.org S: Maintained +KPROBES +P: Prasanna S Panchamukhi +M: prasanna@in.ibm.com +P: Ananth N Mavinakayanahalli +M: ananth@in.ibm.com +P: Anil S Keshavamurthy +M: anil.s.keshavamurthy@intel.com +P: David S. Miller +M: davem@davemloft.net +L: linux-kernel@vger.kernel.org +S: Maintained + LANMEDIA WAN CARD DRIVER P: Andrew Stanley-Jones M: asj@lanmedia.com @@ -2256,6 +2276,12 @@ M: kristen.c.accardi@intel.com L: pcihpd-discuss@lists.sourceforge.net S: Maintained +SKGE, SKY2 10/100/1000 GIGABIT ETHERNET DRIVERS +P: Stephen Hemminger +M: shemminger@osdl.org +L: netdev@vger.kernel.org +S: Maintained + SPARC (sparc32): P: William L. Irwin M: wli@holomorphy.com @@ -2268,12 +2294,6 @@ M: R.E.Wolff@BitWizard.nl L: linux-kernel@vger.kernel.org ? S: Supported -SPX NETWORK LAYER -P: Jay Schulist -M: jschlst@samba.org -L: netdev@vger.kernel.org -S: Supported - SRM (Alpha) environment access P: Jan-Benedict Glaw M: jbglaw@lug-owl.de @@ -1,7 +1,7 @@ VERSION = 2 PATCHLEVEL = 6 SUBLEVEL = 14 -EXTRAVERSION =-rc1 +EXTRAVERSION =-rc2 NAME=Affluent Albatross # *DOCUMENTATION* @@ -149,6 +149,9 @@ CONFIGURING the kernel: "make gconfig" X windows (Gtk) based configuration tool. "make oldconfig" Default all questions based on the contents of your existing ./.config file. + "make silentoldconfig" + Like above, but avoids cluttering the screen + with questions already answered. NOTES on "make config": - having unnecessary drivers will make the kernel bigger, and can @@ -169,9 +172,6 @@ CONFIGURING the kernel: should probably answer 'n' to the questions for "development", "experimental", or "debugging" features. - - Check the top Makefile for further site-dependent configuration - (default SVGA mode etc). - COMPILING the kernel: - Make sure you have gcc 2.95.3 available. @@ -199,6 +199,9 @@ COMPILING the kernel: are installing a new kernel with the same version number as your working kernel, make a backup of your modules directory before you do a "make modules_install". + Alternatively, before compiling, use the kernel config option + "LOCALVERSION" to append a unique suffix to the regular kernel version. + LOCALVERSION can be set in the "General Setup" menu. - In order to boot your new kernel, you'll need to copy the kernel image (e.g. .../linux/arch/i386/boot/bzImage after compilation) diff --git a/arch/alpha/kernel/osf_sys.c b/arch/alpha/kernel/osf_sys.c index 0636116..01fe990d 100644 --- a/arch/alpha/kernel/osf_sys.c +++ b/arch/alpha/kernel/osf_sys.c @@ -37,6 +37,7 @@ #include <linux/namei.h> #include <linux/uio.h> #include <linux/vfs.h> +#include <linux/rcupdate.h> #include <asm/fpu.h> #include <asm/io.h> @@ -975,6 +976,7 @@ osf_select(int n, fd_set __user *inp, fd_set __user *outp, fd_set __user *exp, long timeout; int ret = -EINVAL; struct fdtable *fdt; + int max_fdset; timeout = MAX_SCHEDULE_TIMEOUT; if (tvp) { @@ -996,8 +998,11 @@ osf_select(int n, fd_set __user *inp, fd_set __user *outp, fd_set __user *exp, } } + rcu_read_lock(); fdt = files_fdtable(current->files); - if (n < 0 || n > fdt->max_fdset) + max_fdset = fdt->max_fdset; + rcu_read_unlock(); + if (n < 0 || n > max_fdset) goto out_nofds; /* diff --git a/arch/alpha/kernel/process.c b/arch/alpha/kernel/process.c index fa98dae..eb20c3a 100644 --- a/arch/alpha/kernel/process.c +++ b/arch/alpha/kernel/process.c @@ -127,6 +127,10 @@ common_shutdown_1(void *generic_ptr) /* If booted from SRM, reset some of the original environment. */ if (alpha_using_srm) { #ifdef CONFIG_DUMMY_CONSOLE + /* If we've gotten here after SysRq-b, leave interrupt + context before taking over the console. */ + if (in_interrupt()) + irq_exit(); /* This has the effect of resetting the VGA video origin. */ take_over_console(&dummy_con, 0, MAX_NR_CONSOLES-1, 1); #endif diff --git a/arch/alpha/kernel/sys_dp264.c b/arch/alpha/kernel/sys_dp264.c index 9e36b07..d5da6b1 100644 --- a/arch/alpha/kernel/sys_dp264.c +++ b/arch/alpha/kernel/sys_dp264.c @@ -395,6 +395,22 @@ clipper_init_irq(void) */ static int __init +isa_irq_fixup(struct pci_dev *dev, int irq) +{ + u8 irq8; + + if (irq > 0) + return irq; + + /* This interrupt is routed via ISA bridge, so we'll + just have to trust whatever value the console might + have assigned. */ + pci_read_config_byte(dev, PCI_INTERRUPT_LINE, &irq8); + + return irq8 & 0xf; +} + +static int __init dp264_map_irq(struct pci_dev *dev, u8 slot, u8 pin) { static char irq_tab[6][5] __initdata = { @@ -407,25 +423,13 @@ dp264_map_irq(struct pci_dev *dev, u8 slot, u8 pin) { 16+ 3, 16+ 3, 16+ 2, 16+ 1, 16+ 0} /* IdSel 10 slot 3 */ }; const long min_idsel = 5, max_idsel = 10, irqs_per_slot = 5; - struct pci_controller *hose = dev->sysdata; int irq = COMMON_TABLE_LOOKUP; - if (irq > 0) { + if (irq > 0) irq += 16 * hose->index; - } else { - /* ??? The Contaq IDE controller on the ISA bridge uses - "legacy" interrupts 14 and 15. I don't know if anything - can wind up at the same slot+pin on hose1, so we'll - just have to trust whatever value the console might - have assigned. */ - - u8 irq8; - pci_read_config_byte(dev, PCI_INTERRUPT_LINE, &irq8); - irq = irq8; - } - return irq; + return isa_irq_fixup(dev, irq); } static int __init @@ -453,7 +457,8 @@ monet_map_irq(struct pci_dev *dev, u8 slot, u8 pin) { 24, 24, 25, 26, 27} /* IdSel 15 slot 5 PCI2*/ }; const long min_idsel = 3, max_idsel = 15, irqs_per_slot = 5; - return COMMON_TABLE_LOOKUP; + + return isa_irq_fixup(dev, COMMON_TABLE_LOOKUP); } static u8 __init @@ -507,7 +512,8 @@ webbrick_map_irq(struct pci_dev *dev, u8 slot, u8 pin) { 47, 47, 46, 45, 44}, /* IdSel 17 slot 3 */ }; const long min_idsel = 7, max_idsel = 17, irqs_per_slot = 5; - return COMMON_TABLE_LOOKUP; + + return isa_irq_fixup(dev, COMMON_TABLE_LOOKUP); } static int __init @@ -524,14 +530,13 @@ clipper_map_irq(struct pci_dev *dev, u8 slot, u8 pin) { -1, -1, -1, -1, -1} /* IdSel 7 ISA Bridge */ }; const long min_idsel = 1, max_idsel = 7, irqs_per_slot = 5; - struct pci_controller *hose = dev->sysdata; int irq = COMMON_TABLE_LOOKUP; if (irq > 0) irq += 16 * hose->index; - return irq; + return isa_irq_fixup(dev, irq); } static void __init diff --git a/arch/arm/boot/compressed/ofw-shark.c b/arch/arm/boot/compressed/ofw-shark.c index 7f6f5db..465c54b 100644 --- a/arch/arm/boot/compressed/ofw-shark.c +++ b/arch/arm/boot/compressed/ofw-shark.c @@ -256,5 +256,5 @@ asmlinkage void ofw_init(ofw_handle_t o, int *nomr, int *pointer) temp[11]='\0'; mem_len = OF_getproplen(o,phandle, temp); OF_getprop(o,phandle, temp, buffer, mem_len); - (unsigned char) pointer[32] = ((unsigned char *) buffer)[mem_len-2]; + * ((unsigned char *) &pointer[32]) = ((unsigned char *) buffer)[mem_len-2]; } diff --git a/arch/arm/common/locomo.c b/arch/arm/common/locomo.c index 2786f7c..a7bd857 100644 --- a/arch/arm/common/locomo.c +++ b/arch/arm/common/locomo.c @@ -551,7 +551,7 @@ struct locomo_save_data { u16 LCM_SPIMD; }; -static int locomo_suspend(struct device *dev, u32 pm_message_t, u32 level) +static int locomo_suspend(struct device *dev, pm_message_t state, u32 level) { struct locomo *lchip = dev_get_drvdata(dev); struct locomo_save_data *save; diff --git a/arch/arm/configs/enp2611_defconfig b/arch/arm/configs/enp2611_defconfig index f67ca01..30e6444 100644 --- a/arch/arm/configs/enp2611_defconfig +++ b/arch/arm/configs/enp2611_defconfig @@ -1,7 +1,7 @@ # # Automatically generated make config: don't edit -# Linux kernel version: 2.6.13-rc2 -# Thu Jul 7 16:41:21 2005 +# Linux kernel version: 2.6.13 +# Wed Sep 14 10:51:52 2005 # CONFIG_ARM=y CONFIG_MMU=y @@ -135,7 +135,6 @@ CONFIG_PCI_NAMES=y # # Kernel Features # -# CONFIG_SMP is not set # CONFIG_PREEMPT is not set # CONFIG_NO_IDLE_HZ is not set # CONFIG_ARCH_DISCONTIGMEM_ENABLE is not set @@ -179,6 +178,68 @@ CONFIG_BINFMT_ELF=y # CONFIG_PM is not set # +# Networking +# +CONFIG_NET=y + +# +# Networking options +# +CONFIG_PACKET=y +CONFIG_PACKET_MMAP=y +CONFIG_UNIX=y +# CONFIG_NET_KEY is not set +CONFIG_INET=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_RARP is not set +# CONFIG_NET_IPIP is not set +# CONFIG_NET_IPGRE is not set +# CONFIG_ARPD is not set +CONFIG_SYN_COOKIES=y +# CONFIG_INET_AH is not set +# CONFIG_INET_ESP is not set +# CONFIG_INET_IPCOMP is not set +# CONFIG_INET_TUNNEL is not set +# CONFIG_IP_TCPDIAG is not set +# CONFIG_IP_TCPDIAG_IPV6 is not set +# CONFIG_TCP_CONG_ADVANCED is not set +CONFIG_TCP_CONG_BIC=y +# CONFIG_IPV6 is not set +# CONFIG_NETFILTER is not set + +# +# SCTP Configuration (EXPERIMENTAL) +# +# CONFIG_IP_SCTP 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_NET_DIVERT is not set +# CONFIG_ECONET is not set +# CONFIG_WAN_ROUTER is not set +# CONFIG_NET_SCHED is not set +# CONFIG_NET_CLS_ROUTE 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 + +# # Device Drivers # @@ -248,6 +309,7 @@ CONFIG_MTD_COMPLEX_MAPPINGS=y CONFIG_MTD_IXP2000=y # CONFIG_MTD_EDB7312 is not set # CONFIG_MTD_PCI is not set +# CONFIG_MTD_PLATRAM is not set # # Self-contained MTD device drivers @@ -334,72 +396,8 @@ CONFIG_IOSCHED_CFQ=y # CONFIG_I2O is not set # -# Networking support -# -CONFIG_NET=y - -# -# Networking options -# -CONFIG_PACKET=y -CONFIG_PACKET_MMAP=y -CONFIG_UNIX=y -# CONFIG_NET_KEY is not set -CONFIG_INET=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_RARP is not set -# CONFIG_NET_IPIP is not set -# CONFIG_NET_IPGRE is not set -# CONFIG_ARPD is not set -CONFIG_SYN_COOKIES=y -# CONFIG_INET_AH is not set -# CONFIG_INET_ESP is not set -# CONFIG_INET_IPCOMP is not set -# CONFIG_INET_TUNNEL is not set -# CONFIG_IP_TCPDIAG is not set -# CONFIG_IP_TCPDIAG_IPV6 is not set -# CONFIG_TCP_CONG_ADVANCED is not set -CONFIG_TCP_CONG_BIC=y -# CONFIG_IPV6 is not set -# CONFIG_NETFILTER is not set - -# -# SCTP Configuration (EXPERIMENTAL) -# -# CONFIG_IP_SCTP 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_NET_DIVERT 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 is not set - -# -# Network testing +# Network device support # -# CONFIG_NET_PKTGEN is not set -# CONFIG_NETPOLL is not set -# CONFIG_NET_POLL_CONTROLLER is not set -# CONFIG_HAMRADIO is not set -# CONFIG_IRDA is not set -# CONFIG_BT is not set CONFIG_NETDEVICES=y CONFIG_DUMMY=y # CONFIG_BONDING is not set @@ -509,6 +507,8 @@ CONFIG_DLCI_MAX=8 # 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 @@ -635,7 +635,7 @@ CONFIG_I2C_ALGOBIT=y # CONFIG_I2C_I810 is not set # CONFIG_I2C_PIIX4 is not set # CONFIG_I2C_ISA is not set -# CONFIG_I2C_IXP2000 is not set +CONFIG_I2C_IXP2000=y # CONFIG_I2C_NFORCE2 is not set # CONFIG_I2C_PARPORT_LIGHT is not set # CONFIG_I2C_PROSAVAGE is not set @@ -649,11 +649,28 @@ CONFIG_I2C_ALGOBIT=y # CONFIG_I2C_VIAPRO is not set # CONFIG_I2C_VOODOO3 is not set # CONFIG_I2C_PCA_ISA is not set +CONFIG_I2C_SENSOR=y # -# Hardware Sensors Chip support +# Miscellaneous I2C Chip support # -CONFIG_I2C_SENSOR=y +# CONFIG_SENSORS_DS1337 is not set +# CONFIG_SENSORS_DS1374 is not set +CONFIG_SENSORS_EEPROM=y +# CONFIG_SENSORS_PCF8574 is not set +# CONFIG_SENSORS_PCA9539 is not set +# CONFIG_SENSORS_PCF8591 is not set +# CONFIG_SENSORS_RTC8564 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 + +# +# Hardware Monitoring support +# +CONFIG_HWMON=y # CONFIG_SENSORS_ADM1021 is not set # CONFIG_SENSORS_ADM1025 is not set # CONFIG_SENSORS_ADM1026 is not set @@ -679,30 +696,15 @@ CONFIG_I2C_SENSOR=y # CONFIG_SENSORS_LM92 is not set # CONFIG_SENSORS_MAX1619 is not set # CONFIG_SENSORS_PC87360 is not set -# CONFIG_SENSORS_SMSC47B397 is not set # CONFIG_SENSORS_SIS5595 is not set # CONFIG_SENSORS_SMSC47M1 is not set +# CONFIG_SENSORS_SMSC47B397 is not set # CONFIG_SENSORS_VIA686A is not set # CONFIG_SENSORS_W83781D is not set # CONFIG_SENSORS_W83L785TS is not set # CONFIG_SENSORS_W83627HF is not set # CONFIG_SENSORS_W83627EHF is not set - -# -# Other I2C Chip support -# -# CONFIG_SENSORS_DS1337 is not set -# CONFIG_SENSORS_DS1374 is not set -CONFIG_SENSORS_EEPROM=y -# CONFIG_SENSORS_PCF8574 is not set -# CONFIG_SENSORS_PCA9539 is not set -# CONFIG_SENSORS_PCF8591 is not set -# CONFIG_SENSORS_RTC8564 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 +# CONFIG_HWMON_DEBUG_CHIP is not set # # Misc devices @@ -770,6 +772,7 @@ CONFIG_FS_POSIX_ACL=y # CONFIG_XFS_FS is not set # CONFIG_MINIX_FS is not set # CONFIG_ROMFS_FS is not set +CONFIG_INOTIFY=y # CONFIG_QUOTA is not set CONFIG_DNOTIFY=y # CONFIG_AUTOFS_FS is not set @@ -812,8 +815,7 @@ CONFIG_RAMFS=y # CONFIG_JFFS_FS is not set CONFIG_JFFS2_FS=y CONFIG_JFFS2_FS_DEBUG=0 -# CONFIG_JFFS2_FS_NAND is not set -# CONFIG_JFFS2_FS_NOR_ECC is not set +CONFIG_JFFS2_FS_WRITEBUFFER=y # CONFIG_JFFS2_COMPRESSION_OPTIONS is not set CONFIG_JFFS2_ZLIB=y CONFIG_JFFS2_RTIME=y diff --git a/arch/arm/configs/ixdp2400_defconfig b/arch/arm/configs/ixdp2400_defconfig index 5c6c928..678720f 100644 --- a/arch/arm/configs/ixdp2400_defconfig +++ b/arch/arm/configs/ixdp2400_defconfig @@ -1,7 +1,7 @@ # # Automatically generated make config: don't edit -# Linux kernel version: 2.6.13-rc2 -# Thu Jul 7 16:49:01 2005 +# Linux kernel version: 2.6.13 +# Wed Sep 14 10:52:01 2005 # CONFIG_ARM=y CONFIG_MMU=y @@ -136,7 +136,6 @@ CONFIG_PCI_NAMES=y # # Kernel Features # -# CONFIG_SMP is not set # CONFIG_PREEMPT is not set # CONFIG_NO_IDLE_HZ is not set # CONFIG_ARCH_DISCONTIGMEM_ENABLE is not set @@ -180,6 +179,68 @@ CONFIG_BINFMT_ELF=y # CONFIG_PM is not set # +# Networking +# +CONFIG_NET=y + +# +# Networking options +# +CONFIG_PACKET=y +CONFIG_PACKET_MMAP=y +CONFIG_UNIX=y +# CONFIG_NET_KEY is not set +CONFIG_INET=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_RARP is not set +# CONFIG_NET_IPIP is not set +# CONFIG_NET_IPGRE is not set +# CONFIG_ARPD is not set +CONFIG_SYN_COOKIES=y +# CONFIG_INET_AH is not set +# CONFIG_INET_ESP is not set +# CONFIG_INET_IPCOMP is not set +# CONFIG_INET_TUNNEL is not set +# CONFIG_IP_TCPDIAG is not set +# CONFIG_IP_TCPDIAG_IPV6 is not set +# CONFIG_TCP_CONG_ADVANCED is not set +CONFIG_TCP_CONG_BIC=y +# CONFIG_IPV6 is not set +# CONFIG_NETFILTER is not set + +# +# SCTP Configuration (EXPERIMENTAL) +# +# CONFIG_IP_SCTP 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_NET_DIVERT is not set +# CONFIG_ECONET is not set +# CONFIG_WAN_ROUTER is not set +# CONFIG_NET_SCHED is not set +# CONFIG_NET_CLS_ROUTE 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 + +# # Device Drivers # @@ -249,6 +310,7 @@ CONFIG_MTD_COMPLEX_MAPPINGS=y CONFIG_MTD_IXP2000=y # CONFIG_MTD_EDB7312 is not set # CONFIG_MTD_PCI is not set +# CONFIG_MTD_PLATRAM is not set # # Self-contained MTD device drivers @@ -335,72 +397,8 @@ CONFIG_IOSCHED_CFQ=y # CONFIG_I2O is not set # -# Networking support -# -CONFIG_NET=y - -# -# Networking options -# -CONFIG_PACKET=y -CONFIG_PACKET_MMAP=y -CONFIG_UNIX=y -# CONFIG_NET_KEY is not set -CONFIG_INET=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_RARP is not set -# CONFIG_NET_IPIP is not set -# CONFIG_NET_IPGRE is not set -# CONFIG_ARPD is not set -CONFIG_SYN_COOKIES=y -# CONFIG_INET_AH is not set -# CONFIG_INET_ESP is not set -# CONFIG_INET_IPCOMP is not set -# CONFIG_INET_TUNNEL is not set -# CONFIG_IP_TCPDIAG is not set -# CONFIG_IP_TCPDIAG_IPV6 is not set -# CONFIG_TCP_CONG_ADVANCED is not set -CONFIG_TCP_CONG_BIC=y -# CONFIG_IPV6 is not set -# CONFIG_NETFILTER is not set - -# -# SCTP Configuration (EXPERIMENTAL) -# -# CONFIG_IP_SCTP 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_NET_DIVERT 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 is not set - -# -# Network testing +# Network device support # -# CONFIG_NET_PKTGEN is not set -# CONFIG_NETPOLL is not set -# CONFIG_NET_POLL_CONTROLLER is not set -# CONFIG_HAMRADIO is not set -# CONFIG_IRDA is not set -# CONFIG_BT is not set CONFIG_NETDEVICES=y CONFIG_DUMMY=y # CONFIG_BONDING is not set @@ -510,6 +508,8 @@ CONFIG_DLCI_MAX=8 # 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 @@ -636,7 +636,7 @@ CONFIG_I2C_ALGOBIT=y # CONFIG_I2C_I810 is not set # CONFIG_I2C_PIIX4 is not set # CONFIG_I2C_ISA is not set -# CONFIG_I2C_IXP2000 is not set +CONFIG_I2C_IXP2000=y # CONFIG_I2C_NFORCE2 is not set # CONFIG_I2C_PARPORT_LIGHT is not set # CONFIG_I2C_PROSAVAGE is not set @@ -650,11 +650,28 @@ CONFIG_I2C_ALGOBIT=y # CONFIG_I2C_VIAPRO is not set # CONFIG_I2C_VOODOO3 is not set # CONFIG_I2C_PCA_ISA is not set +CONFIG_I2C_SENSOR=y # -# Hardware Sensors Chip support +# Miscellaneous I2C Chip support # -CONFIG_I2C_SENSOR=y +# CONFIG_SENSORS_DS1337 is not set +# CONFIG_SENSORS_DS1374 is not set +CONFIG_SENSORS_EEPROM=y +# CONFIG_SENSORS_PCF8574 is not set +# CONFIG_SENSORS_PCA9539 is not set +# CONFIG_SENSORS_PCF8591 is not set +# CONFIG_SENSORS_RTC8564 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 + +# +# Hardware Monitoring support +# +CONFIG_HWMON=y # CONFIG_SENSORS_ADM1021 is not set # CONFIG_SENSORS_ADM1025 is not set # CONFIG_SENSORS_ADM1026 is not set @@ -680,30 +697,15 @@ CONFIG_I2C_SENSOR=y # CONFIG_SENSORS_LM92 is not set # CONFIG_SENSORS_MAX1619 is not set # CONFIG_SENSORS_PC87360 is not set -# CONFIG_SENSORS_SMSC47B397 is not set # CONFIG_SENSORS_SIS5595 is not set # CONFIG_SENSORS_SMSC47M1 is not set +# CONFIG_SENSORS_SMSC47B397 is not set # CONFIG_SENSORS_VIA686A is not set # CONFIG_SENSORS_W83781D is not set # CONFIG_SENSORS_W83L785TS is not set # CONFIG_SENSORS_W83627HF is not set # CONFIG_SENSORS_W83627EHF is not set - -# -# Other I2C Chip support -# -# CONFIG_SENSORS_DS1337 is not set -# CONFIG_SENSORS_DS1374 is not set -CONFIG_SENSORS_EEPROM=y -# CONFIG_SENSORS_PCF8574 is not set -# CONFIG_SENSORS_PCA9539 is not set -# CONFIG_SENSORS_PCF8591 is not set -# CONFIG_SENSORS_RTC8564 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 +# CONFIG_HWMON_DEBUG_CHIP is not set # # Misc devices @@ -771,6 +773,7 @@ CONFIG_FS_POSIX_ACL=y # CONFIG_XFS_FS is not set # CONFIG_MINIX_FS is not set # CONFIG_ROMFS_FS is not set +CONFIG_INOTIFY=y # CONFIG_QUOTA is not set CONFIG_DNOTIFY=y # CONFIG_AUTOFS_FS is not set @@ -813,8 +816,7 @@ CONFIG_RAMFS=y # CONFIG_JFFS_FS is not set CONFIG_JFFS2_FS=y CONFIG_JFFS2_FS_DEBUG=0 -# CONFIG_JFFS2_FS_NAND is not set -# CONFIG_JFFS2_FS_NOR_ECC is not set +CONFIG_JFFS2_FS_WRITEBUFFER=y # CONFIG_JFFS2_COMPRESSION_OPTIONS is not set CONFIG_JFFS2_ZLIB=y CONFIG_JFFS2_RTIME=y diff --git a/arch/arm/configs/ixdp2401_defconfig b/arch/arm/configs/ixdp2401_defconfig index 6dc40f6..38c9a72 100644 --- a/arch/arm/configs/ixdp2401_defconfig +++ b/arch/arm/configs/ixdp2401_defconfig @@ -1,7 +1,7 @@ # # Automatically generated make config: don't edit -# Linux kernel version: 2.6.13-rc2 -# Thu Jul 7 16:49:08 2005 +# Linux kernel version: 2.6.13 +# Wed Sep 14 10:52:10 2005 # CONFIG_ARM=y CONFIG_MMU=y @@ -136,7 +136,6 @@ CONFIG_PCI_NAMES=y # # Kernel Features # -# CONFIG_SMP is not set # CONFIG_PREEMPT is not set # CONFIG_NO_IDLE_HZ is not set # CONFIG_ARCH_DISCONTIGMEM_ENABLE is not set @@ -180,6 +179,68 @@ CONFIG_BINFMT_ELF=y # CONFIG_PM is not set # +# Networking +# +CONFIG_NET=y + +# +# Networking options +# +CONFIG_PACKET=y +CONFIG_PACKET_MMAP=y +CONFIG_UNIX=y +# CONFIG_NET_KEY is not set +CONFIG_INET=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_RARP is not set +# CONFIG_NET_IPIP is not set +# CONFIG_NET_IPGRE is not set +# CONFIG_ARPD is not set +CONFIG_SYN_COOKIES=y +# CONFIG_INET_AH is not set +# CONFIG_INET_ESP is not set +# CONFIG_INET_IPCOMP is not set +# CONFIG_INET_TUNNEL is not set +CONFIG_IP_TCPDIAG=y +# CONFIG_IP_TCPDIAG_IPV6 is not set +# CONFIG_TCP_CONG_ADVANCED is not set +CONFIG_TCP_CONG_BIC=y +# CONFIG_IPV6 is not set +# CONFIG_NETFILTER is not set + +# +# SCTP Configuration (EXPERIMENTAL) +# +# CONFIG_IP_SCTP 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_NET_DIVERT is not set +# CONFIG_ECONET is not set +# CONFIG_WAN_ROUTER is not set +# CONFIG_NET_SCHED is not set +# CONFIG_NET_CLS_ROUTE 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 + +# # Device Drivers # @@ -249,6 +310,7 @@ CONFIG_MTD_COMPLEX_MAPPINGS=y CONFIG_MTD_IXP2000=y # CONFIG_MTD_EDB7312 is not set # CONFIG_MTD_PCI is not set +# CONFIG_MTD_PLATRAM is not set # # Self-contained MTD device drivers @@ -335,72 +397,8 @@ CONFIG_IOSCHED_CFQ=y # CONFIG_I2O is not set # -# Networking support -# -CONFIG_NET=y - -# -# Networking options -# -CONFIG_PACKET=y -CONFIG_PACKET_MMAP=y -CONFIG_UNIX=y -# CONFIG_NET_KEY is not set -CONFIG_INET=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_RARP is not set -# CONFIG_NET_IPIP is not set -# CONFIG_NET_IPGRE is not set -# CONFIG_ARPD is not set -CONFIG_SYN_COOKIES=y -# CONFIG_INET_AH is not set -# CONFIG_INET_ESP is not set -# CONFIG_INET_IPCOMP is not set -# CONFIG_INET_TUNNEL is not set -CONFIG_IP_TCPDIAG=y -# CONFIG_IP_TCPDIAG_IPV6 is not set -# CONFIG_TCP_CONG_ADVANCED is not set -CONFIG_TCP_CONG_BIC=y -# CONFIG_IPV6 is not set -# CONFIG_NETFILTER is not set - -# -# SCTP Configuration (EXPERIMENTAL) -# -# CONFIG_IP_SCTP 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_NET_DIVERT 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 is not set - -# -# Network testing +# Network device support # -# CONFIG_NET_PKTGEN is not set -# CONFIG_NETPOLL is not set -# CONFIG_NET_POLL_CONTROLLER is not set -# CONFIG_HAMRADIO is not set -# CONFIG_IRDA is not set -# CONFIG_BT is not set CONFIG_NETDEVICES=y CONFIG_DUMMY=y # CONFIG_BONDING is not set @@ -511,6 +509,8 @@ CONFIG_DLCI_MAX=8 # 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 @@ -637,7 +637,7 @@ CONFIG_I2C_ALGOBIT=y # CONFIG_I2C_I810 is not set # CONFIG_I2C_PIIX4 is not set # CONFIG_I2C_ISA is not set -# CONFIG_I2C_IXP2000 is not set +CONFIG_I2C_IXP2000=y # CONFIG_I2C_NFORCE2 is not set # CONFIG_I2C_PARPORT_LIGHT is not set # CONFIG_I2C_PROSAVAGE is not set @@ -651,11 +651,28 @@ CONFIG_I2C_ALGOBIT=y # CONFIG_I2C_VIAPRO is not set # CONFIG_I2C_VOODOO3 is not set # CONFIG_I2C_PCA_ISA is not set +CONFIG_I2C_SENSOR=y # -# Hardware Sensors Chip support +# Miscellaneous I2C Chip support # -CONFIG_I2C_SENSOR=y +# CONFIG_SENSORS_DS1337 is not set +# CONFIG_SENSORS_DS1374 is not set +CONFIG_SENSORS_EEPROM=y +# CONFIG_SENSORS_PCF8574 is not set +# CONFIG_SENSORS_PCA9539 is not set +# CONFIG_SENSORS_PCF8591 is not set +# CONFIG_SENSORS_RTC8564 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 + +# +# Hardware Monitoring support +# +CONFIG_HWMON=y # CONFIG_SENSORS_ADM1021 is not set # CONFIG_SENSORS_ADM1025 is not set # CONFIG_SENSORS_ADM1026 is not set @@ -681,30 +698,15 @@ CONFIG_I2C_SENSOR=y # CONFIG_SENSORS_LM92 is not set # CONFIG_SENSORS_MAX1619 is not set # CONFIG_SENSORS_PC87360 is not set -# CONFIG_SENSORS_SMSC47B397 is not set # CONFIG_SENSORS_SIS5595 is not set # CONFIG_SENSORS_SMSC47M1 is not set +# CONFIG_SENSORS_SMSC47B397 is not set # CONFIG_SENSORS_VIA686A is not set # CONFIG_SENSORS_W83781D is not set # CONFIG_SENSORS_W83L785TS is not set # CONFIG_SENSORS_W83627HF is not set # CONFIG_SENSORS_W83627EHF is not set - -# -# Other I2C Chip support -# -# CONFIG_SENSORS_DS1337 is not set -# CONFIG_SENSORS_DS1374 is not set -CONFIG_SENSORS_EEPROM=y -# CONFIG_SENSORS_PCF8574 is not set -# CONFIG_SENSORS_PCA9539 is not set -# CONFIG_SENSORS_PCF8591 is not set -# CONFIG_SENSORS_RTC8564 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 +# CONFIG_HWMON_DEBUG_CHIP is not set # # Misc devices @@ -772,6 +774,7 @@ CONFIG_FS_POSIX_ACL=y # CONFIG_XFS_FS is not set # CONFIG_MINIX_FS is not set # CONFIG_ROMFS_FS is not set +CONFIG_INOTIFY=y # CONFIG_QUOTA is not set CONFIG_DNOTIFY=y # CONFIG_AUTOFS_FS is not set @@ -814,8 +817,7 @@ CONFIG_RAMFS=y # CONFIG_JFFS_FS is not set CONFIG_JFFS2_FS=y CONFIG_JFFS2_FS_DEBUG=0 -# CONFIG_JFFS2_FS_NAND is not set -# CONFIG_JFFS2_FS_NOR_ECC is not set +CONFIG_JFFS2_FS_WRITEBUFFER=y # CONFIG_JFFS2_COMPRESSION_OPTIONS is not set CONFIG_JFFS2_ZLIB=y CONFIG_JFFS2_RTIME=y diff --git a/arch/arm/configs/ixdp2800_defconfig b/arch/arm/configs/ixdp2800_defconfig index d2bb0b7..261e234 100644 --- a/arch/arm/configs/ixdp2800_defconfig +++ b/arch/arm/configs/ixdp2800_defconfig @@ -1,7 +1,7 @@ # # Automatically generated make config: don't edit -# Linux kernel version: 2.6.13-rc2 -# Thu Jul 7 16:49:20 2005 +# Linux kernel version: 2.6.13 +# Wed Sep 14 10:52:23 2005 # CONFIG_ARM=y CONFIG_MMU=y @@ -136,7 +136,6 @@ CONFIG_PCI_NAMES=y # # Kernel Features # -# CONFIG_SMP is not set # CONFIG_PREEMPT is not set # CONFIG_NO_IDLE_HZ is not set # CONFIG_ARCH_DISCONTIGMEM_ENABLE is not set @@ -180,6 +179,68 @@ CONFIG_BINFMT_ELF=y # CONFIG_PM is not set # +# Networking +# +CONFIG_NET=y + +# +# Networking options +# +CONFIG_PACKET=y +CONFIG_PACKET_MMAP=y +CONFIG_UNIX=y +# CONFIG_NET_KEY is not set +CONFIG_INET=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_RARP is not set +# CONFIG_NET_IPIP is not set +# CONFIG_NET_IPGRE is not set +# CONFIG_ARPD is not set +CONFIG_SYN_COOKIES=y +# CONFIG_INET_AH is not set +# CONFIG_INET_ESP is not set +# CONFIG_INET_IPCOMP is not set +# CONFIG_INET_TUNNEL is not set +# CONFIG_IP_TCPDIAG is not set +# CONFIG_IP_TCPDIAG_IPV6 is not set +# CONFIG_TCP_CONG_ADVANCED is not set +CONFIG_TCP_CONG_BIC=y +# CONFIG_IPV6 is not set +# CONFIG_NETFILTER is not set + +# +# SCTP Configuration (EXPERIMENTAL) +# +# CONFIG_IP_SCTP 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_NET_DIVERT is not set +# CONFIG_ECONET is not set +# CONFIG_WAN_ROUTER is not set +# CONFIG_NET_SCHED is not set +# CONFIG_NET_CLS_ROUTE 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 + +# # Device Drivers # @@ -249,6 +310,7 @@ CONFIG_MTD_COMPLEX_MAPPINGS=y CONFIG_MTD_IXP2000=y # CONFIG_MTD_EDB7312 is not set # CONFIG_MTD_PCI is not set +# CONFIG_MTD_PLATRAM is not set # # Self-contained MTD device drivers @@ -335,72 +397,8 @@ CONFIG_IOSCHED_CFQ=y # CONFIG_I2O is not set # -# Networking support -# -CONFIG_NET=y - -# -# Networking options -# -CONFIG_PACKET=y -CONFIG_PACKET_MMAP=y -CONFIG_UNIX=y -# CONFIG_NET_KEY is not set -CONFIG_INET=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_RARP is not set -# CONFIG_NET_IPIP is not set -# CONFIG_NET_IPGRE is not set -# CONFIG_ARPD is not set -CONFIG_SYN_COOKIES=y -# CONFIG_INET_AH is not set -# CONFIG_INET_ESP is not set -# CONFIG_INET_IPCOMP is not set -# CONFIG_INET_TUNNEL is not set -# CONFIG_IP_TCPDIAG is not set -# CONFIG_IP_TCPDIAG_IPV6 is not set -# CONFIG_TCP_CONG_ADVANCED is not set -CONFIG_TCP_CONG_BIC=y -# CONFIG_IPV6 is not set -# CONFIG_NETFILTER is not set - -# -# SCTP Configuration (EXPERIMENTAL) -# -# CONFIG_IP_SCTP 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_NET_DIVERT 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 is not set - -# -# Network testing +# Network device support # -# CONFIG_NET_PKTGEN is not set -# CONFIG_NETPOLL is not set -# CONFIG_NET_POLL_CONTROLLER is not set -# CONFIG_HAMRADIO is not set -# CONFIG_IRDA is not set -# CONFIG_BT is not set CONFIG_NETDEVICES=y CONFIG_DUMMY=y # CONFIG_BONDING is not set @@ -510,6 +508,8 @@ CONFIG_DLCI_MAX=8 # 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 @@ -636,7 +636,7 @@ CONFIG_I2C_ALGOBIT=y # CONFIG_I2C_I810 is not set # CONFIG_I2C_PIIX4 is not set # CONFIG_I2C_ISA is not set -# CONFIG_I2C_IXP2000 is not set +CONFIG_I2C_IXP2000=y # CONFIG_I2C_NFORCE2 is not set # CONFIG_I2C_PARPORT_LIGHT is not set # CONFIG_I2C_PROSAVAGE is not set @@ -650,11 +650,28 @@ CONFIG_I2C_ALGOBIT=y # CONFIG_I2C_VIAPRO is not set # CONFIG_I2C_VOODOO3 is not set # CONFIG_I2C_PCA_ISA is not set +CONFIG_I2C_SENSOR=y # -# Hardware Sensors Chip support +# Miscellaneous I2C Chip support # -CONFIG_I2C_SENSOR=y +# CONFIG_SENSORS_DS1337 is not set +# CONFIG_SENSORS_DS1374 is not set +CONFIG_SENSORS_EEPROM=y +# CONFIG_SENSORS_PCF8574 is not set +# CONFIG_SENSORS_PCA9539 is not set +# CONFIG_SENSORS_PCF8591 is not set +# CONFIG_SENSORS_RTC8564 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 + +# +# Hardware Monitoring support +# +CONFIG_HWMON=y # CONFIG_SENSORS_ADM1021 is not set # CONFIG_SENSORS_ADM1025 is not set # CONFIG_SENSORS_ADM1026 is not set @@ -680,30 +697,15 @@ CONFIG_I2C_SENSOR=y # CONFIG_SENSORS_LM92 is not set # CONFIG_SENSORS_MAX1619 is not set # CONFIG_SENSORS_PC87360 is not set -# CONFIG_SENSORS_SMSC47B397 is not set # CONFIG_SENSORS_SIS5595 is not set # CONFIG_SENSORS_SMSC47M1 is not set +# CONFIG_SENSORS_SMSC47B397 is not set # CONFIG_SENSORS_VIA686A is not set # CONFIG_SENSORS_W83781D is not set # CONFIG_SENSORS_W83L785TS is not set # CONFIG_SENSORS_W83627HF is not set # CONFIG_SENSORS_W83627EHF is not set - -# -# Other I2C Chip support -# -# CONFIG_SENSORS_DS1337 is not set -# CONFIG_SENSORS_DS1374 is not set -CONFIG_SENSORS_EEPROM=y -# CONFIG_SENSORS_PCF8574 is not set -# CONFIG_SENSORS_PCA9539 is not set -# CONFIG_SENSORS_PCF8591 is not set -# CONFIG_SENSORS_RTC8564 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 +# CONFIG_HWMON_DEBUG_CHIP is not set # # Misc devices @@ -771,6 +773,7 @@ CONFIG_FS_POSIX_ACL=y # CONFIG_XFS_FS is not set # CONFIG_MINIX_FS is not set # CONFIG_ROMFS_FS is not set +CONFIG_INOTIFY=y # CONFIG_QUOTA is not set CONFIG_DNOTIFY=y # CONFIG_AUTOFS_FS is not set @@ -813,8 +816,7 @@ CONFIG_RAMFS=y # CONFIG_JFFS_FS is not set CONFIG_JFFS2_FS=y CONFIG_JFFS2_FS_DEBUG=0 -# CONFIG_JFFS2_FS_NAND is not set -# CONFIG_JFFS2_FS_NOR_ECC is not set +CONFIG_JFFS2_FS_WRITEBUFFER=y # CONFIG_JFFS2_COMPRESSION_OPTIONS is not set CONFIG_JFFS2_ZLIB=y CONFIG_JFFS2_RTIME=y diff --git a/arch/arm/configs/ixdp2801_defconfig b/arch/arm/configs/ixdp2801_defconfig index 2d6f960..12ef23d 100644 --- a/arch/arm/configs/ixdp2801_defconfig +++ b/arch/arm/configs/ixdp2801_defconfig @@ -1,7 +1,7 @@ # # Automatically generated make config: don't edit -# Linux kernel version: 2.6.13-rc2 -# Thu Jul 7 16:49:13 2005 +# Linux kernel version: 2.6.13 +# Wed Sep 14 10:52:16 2005 # CONFIG_ARM=y CONFIG_MMU=y @@ -136,7 +136,6 @@ CONFIG_PCI_NAMES=y # # Kernel Features # -# CONFIG_SMP is not set # CONFIG_PREEMPT is not set # CONFIG_NO_IDLE_HZ is not set # CONFIG_ARCH_DISCONTIGMEM_ENABLE is not set @@ -180,6 +179,68 @@ CONFIG_BINFMT_ELF=y # CONFIG_PM is not set # +# Networking +# +CONFIG_NET=y + +# +# Networking options +# +CONFIG_PACKET=y +CONFIG_PACKET_MMAP=y +CONFIG_UNIX=y +# CONFIG_NET_KEY is not set +CONFIG_INET=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_RARP is not set +# CONFIG_NET_IPIP is not set +# CONFIG_NET_IPGRE is not set +# CONFIG_ARPD is not set +CONFIG_SYN_COOKIES=y +# CONFIG_INET_AH is not set +# CONFIG_INET_ESP is not set +# CONFIG_INET_IPCOMP is not set +# CONFIG_INET_TUNNEL is not set +# CONFIG_IP_TCPDIAG is not set +# CONFIG_IP_TCPDIAG_IPV6 is not set +# CONFIG_TCP_CONG_ADVANCED is not set +CONFIG_TCP_CONG_BIC=y +# CONFIG_IPV6 is not set +# CONFIG_NETFILTER is not set + +# +# SCTP Configuration (EXPERIMENTAL) +# +# CONFIG_IP_SCTP 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_NET_DIVERT is not set +# CONFIG_ECONET is not set +# CONFIG_WAN_ROUTER is not set +# CONFIG_NET_SCHED is not set +# CONFIG_NET_CLS_ROUTE 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 + +# # Device Drivers # @@ -249,6 +310,7 @@ CONFIG_MTD_COMPLEX_MAPPINGS=y CONFIG_MTD_IXP2000=y # CONFIG_MTD_EDB7312 is not set # CONFIG_MTD_PCI is not set +# CONFIG_MTD_PLATRAM is not set # # Self-contained MTD device drivers @@ -335,72 +397,8 @@ CONFIG_IOSCHED_CFQ=y # CONFIG_I2O is not set # -# Networking support -# -CONFIG_NET=y - -# -# Networking options -# -CONFIG_PACKET=y -CONFIG_PACKET_MMAP=y -CONFIG_UNIX=y -# CONFIG_NET_KEY is not set -CONFIG_INET=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_RARP is not set -# CONFIG_NET_IPIP is not set -# CONFIG_NET_IPGRE is not set -# CONFIG_ARPD is not set -CONFIG_SYN_COOKIES=y -# CONFIG_INET_AH is not set -# CONFIG_INET_ESP is not set -# CONFIG_INET_IPCOMP is not set -# CONFIG_INET_TUNNEL is not set -# CONFIG_IP_TCPDIAG is not set -# CONFIG_IP_TCPDIAG_IPV6 is not set -# CONFIG_TCP_CONG_ADVANCED is not set -CONFIG_TCP_CONG_BIC=y -# CONFIG_IPV6 is not set -# CONFIG_NETFILTER is not set - -# -# SCTP Configuration (EXPERIMENTAL) -# -# CONFIG_IP_SCTP 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_NET_DIVERT 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 is not set - -# -# Network testing +# Network device support # -# CONFIG_NET_PKTGEN is not set -# CONFIG_NETPOLL is not set -# CONFIG_NET_POLL_CONTROLLER is not set -# CONFIG_HAMRADIO is not set -# CONFIG_IRDA is not set -# CONFIG_BT is not set CONFIG_NETDEVICES=y CONFIG_DUMMY=y # CONFIG_BONDING is not set @@ -511,6 +509,8 @@ CONFIG_DLCI_MAX=8 # 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 @@ -637,7 +637,7 @@ CONFIG_I2C_ALGOBIT=y # CONFIG_I2C_I810 is not set # CONFIG_I2C_PIIX4 is not set # CONFIG_I2C_ISA is not set -# CONFIG_I2C_IXP2000 is not set +CONFIG_I2C_IXP2000=y # CONFIG_I2C_NFORCE2 is not set # CONFIG_I2C_PARPORT_LIGHT is not set # CONFIG_I2C_PROSAVAGE is not set @@ -651,11 +651,28 @@ CONFIG_I2C_ALGOBIT=y # CONFIG_I2C_VIAPRO is not set # CONFIG_I2C_VOODOO3 is not set # CONFIG_I2C_PCA_ISA is not set +CONFIG_I2C_SENSOR=y # -# Hardware Sensors Chip support +# Miscellaneous I2C Chip support # -CONFIG_I2C_SENSOR=y +# CONFIG_SENSORS_DS1337 is not set +# CONFIG_SENSORS_DS1374 is not set +CONFIG_SENSORS_EEPROM=y +# CONFIG_SENSORS_PCF8574 is not set +# CONFIG_SENSORS_PCA9539 is not set +# CONFIG_SENSORS_PCF8591 is not set +# CONFIG_SENSORS_RTC8564 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 + +# +# Hardware Monitoring support +# +CONFIG_HWMON=y # CONFIG_SENSORS_ADM1021 is not set # CONFIG_SENSORS_ADM1025 is not set # CONFIG_SENSORS_ADM1026 is not set @@ -681,30 +698,15 @@ CONFIG_I2C_SENSOR=y # CONFIG_SENSORS_LM92 is not set # CONFIG_SENSORS_MAX1619 is not set # CONFIG_SENSORS_PC87360 is not set -# CONFIG_SENSORS_SMSC47B397 is not set # CONFIG_SENSORS_SIS5595 is not set # CONFIG_SENSORS_SMSC47M1 is not set +# CONFIG_SENSORS_SMSC47B397 is not set # CONFIG_SENSORS_VIA686A is not set # CONFIG_SENSORS_W83781D is not set # CONFIG_SENSORS_W83L785TS is not set # CONFIG_SENSORS_W83627HF is not set # CONFIG_SENSORS_W83627EHF is not set - -# -# Other I2C Chip support -# -# CONFIG_SENSORS_DS1337 is not set -# CONFIG_SENSORS_DS1374 is not set -CONFIG_SENSORS_EEPROM=y -# CONFIG_SENSORS_PCF8574 is not set -# CONFIG_SENSORS_PCA9539 is not set -# CONFIG_SENSORS_PCF8591 is not set -# CONFIG_SENSORS_RTC8564 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 +# CONFIG_HWMON_DEBUG_CHIP is not set # # Misc devices @@ -772,6 +774,7 @@ CONFIG_FS_POSIX_ACL=y # CONFIG_XFS_FS is not set # CONFIG_MINIX_FS is not set # CONFIG_ROMFS_FS is not set +CONFIG_INOTIFY=y # CONFIG_QUOTA is not set CONFIG_DNOTIFY=y # CONFIG_AUTOFS_FS is not set @@ -814,8 +817,7 @@ CONFIG_RAMFS=y # CONFIG_JFFS_FS is not set CONFIG_JFFS2_FS=y CONFIG_JFFS2_FS_DEBUG=0 -# CONFIG_JFFS2_FS_NAND is not set -# CONFIG_JFFS2_FS_NOR_ECC is not set +CONFIG_JFFS2_FS_WRITEBUFFER=y # CONFIG_JFFS2_COMPRESSION_OPTIONS is not set CONFIG_JFFS2_ZLIB=y CONFIG_JFFS2_RTIME=y diff --git a/arch/arm/kernel/calls.S b/arch/arm/kernel/calls.S index 949ec44..2ad4aa2 100644 --- a/arch/arm/kernel/calls.S +++ b/arch/arm/kernel/calls.S @@ -131,7 +131,7 @@ __syscall_start: .long sys_wait4 /* 115 */ .long sys_swapoff .long sys_sysinfo - .long sys_ipc + .long sys_ipc_wrapper .long sys_fsync .long sys_sigreturn_wrapper /* 120 */ .long sys_clone_wrapper diff --git a/arch/arm/kernel/entry-armv.S b/arch/arm/kernel/entry-armv.S index 7152bfb..93b5e8e 100644 --- a/arch/arm/kernel/entry-armv.S +++ b/arch/arm/kernel/entry-armv.S @@ -537,7 +537,7 @@ ENTRY(__switch_to) #ifdef CONFIG_CPU_MPCORE clrex #else - strex r3, r4, [ip] @ Clear exclusive monitor + strex r5, r4, [ip] @ Clear exclusive monitor #endif #endif #if defined(CONFIG_CPU_XSCALE) && !defined(CONFIG_IWMMXT) diff --git a/arch/arm/kernel/entry-common.S b/arch/arm/kernel/entry-common.S index db302c6..81d450a 100644 --- a/arch/arm/kernel/entry-common.S +++ b/arch/arm/kernel/entry-common.S @@ -273,6 +273,10 @@ sys_mbind_wrapper: str r5, [sp, #4] b sys_mbind +sys_ipc_wrapper: + str r5, [sp, #4] @ push sixth arg + b sys_ipc + /* * Note: off_4k (r5) is always units of 4K. If we can't do the requested * offset, we return EINVAL. diff --git a/arch/arm/kernel/semaphore.c b/arch/arm/kernel/semaphore.c index ac423e3..4c31f29 100644 --- a/arch/arm/kernel/semaphore.c +++ b/arch/arm/kernel/semaphore.c @@ -178,7 +178,7 @@ int __down_trylock(struct semaphore * sem) * registers (r0 to r3 and lr), but not ip, as we use it as a return * value in some cases.. */ -asm(" .section .sched.text,\"ax\" \n\ +asm(" .section .sched.text,\"ax\",%progbits \n\ .align 5 \n\ .globl __down_failed \n\ __down_failed: \n\ diff --git a/arch/arm/kernel/traps.c b/arch/arm/kernel/traps.c index 4554c96..e7d22db 100644 --- a/arch/arm/kernel/traps.c +++ b/arch/arm/kernel/traps.c @@ -624,6 +624,9 @@ void __attribute__((noreturn)) __bug(const char *file, int line, void *data) printk(" - extra data = %p", data); printk("\n"); *(int *)0 = 0; + + /* Avoid "noreturn function does return" */ + for (;;); } EXPORT_SYMBOL(__bug); diff --git a/arch/arm/kernel/vmlinux.lds.S b/arch/arm/kernel/vmlinux.lds.S index ad2d66c..08e58ec 100644 --- a/arch/arm/kernel/vmlinux.lds.S +++ b/arch/arm/kernel/vmlinux.lds.S @@ -23,20 +23,20 @@ SECTIONS *(.init.text) _einittext = .; __proc_info_begin = .; - *(.proc.info) + *(.proc.info.init) __proc_info_end = .; __arch_info_begin = .; - *(.arch.info) + *(.arch.info.init) __arch_info_end = .; __tagtable_begin = .; - *(.taglist) + *(.taglist.init) __tagtable_end = .; . = ALIGN(16); __setup_start = .; *(.init.setup) __setup_end = .; __early_begin = .; - *(__early_param) + *(.early_param.init) __early_end = .; __initcall_start = .; *(.initcall1.init) diff --git a/arch/arm/mach-ixp4xx/ixdp425-setup.c b/arch/arm/mach-ixp4xx/ixdp425-setup.c index ae1fa09..39b06ed 100644 --- a/arch/arm/mach-ixp4xx/ixdp425-setup.c +++ b/arch/arm/mach-ixp4xx/ixdp425-setup.c @@ -123,6 +123,7 @@ static void __init ixdp425_init(void) platform_add_devices(ixdp425_devices, ARRAY_SIZE(ixdp425_devices)); } +#ifdef CONFIG_ARCH_IXDP465 MACHINE_START(IXDP425, "Intel IXDP425 Development Platform") /* Maintainer: MontaVista Software, Inc. */ .phys_ram = PHYS_OFFSET, @@ -134,7 +135,9 @@ MACHINE_START(IXDP425, "Intel IXDP425 Development Platform") .boot_params = 0x0100, .init_machine = ixdp425_init, MACHINE_END +#endif +#ifdef CONFIG_MACH_IXDP465 MACHINE_START(IXDP465, "Intel IXDP465 Development Platform") /* Maintainer: MontaVista Software, Inc. */ .phys_ram = PHYS_OFFSET, @@ -146,7 +149,9 @@ MACHINE_START(IXDP465, "Intel IXDP465 Development Platform") .boot_params = 0x0100, .init_machine = ixdp425_init, MACHINE_END +#endif +#ifdef CONFIG_ARCH_PRPMC1100 MACHINE_START(IXCDP1100, "Intel IXCDP1100 Development Platform") /* Maintainer: MontaVista Software, Inc. */ .phys_ram = PHYS_OFFSET, @@ -158,6 +163,7 @@ MACHINE_START(IXCDP1100, "Intel IXCDP1100 Development Platform") .boot_params = 0x0100, .init_machine = ixdp425_init, MACHINE_END +#endif /* * Avila is functionally equivalent to IXDP425 except that it adds diff --git a/arch/arm/mach-pxa/Kconfig b/arch/arm/mach-pxa/Kconfig index 405a55f..3e5f69b 100644 --- a/arch/arm/mach-pxa/Kconfig +++ b/arch/arm/mach-pxa/Kconfig @@ -20,40 +20,66 @@ config ARCH_PXA_IDP select PXA25x config PXA_SHARPSL - bool "SHARP SL-5600 and SL-C7xx Models" - select PXA25x + bool "SHARP Zaurus SL-5600, SL-C7xx and SL-Cxx00 Models" select SHARP_SCOOP select SHARP_PARAM help Say Y here if you intend to run this kernel on a - Sharp SL-5600 (Poodle), Sharp SL-C700 (Corgi), - SL-C750 (Shepherd) or a Sharp SL-C760 (Husky) - handheld computer. + Sharp Zaurus SL-5600 (Poodle), SL-C700 (Corgi), + SL-C750 (Shepherd), SL-C760 (Husky), SL-C1000 (Akita), + SL-C3000 (Spitz) or SL-C3100 (Borzoi) handheld computer. endchoice +if PXA_SHARPSL + +choice + prompt "Select target Sharp Zaurus device range" + +config PXA_SHARPSL_25x + bool "Sharp PXA25x models (SL-5600 and SL-C7xx)" + select PXA25x + +config PXA_SHARPSL_27x + bool "Sharp PXA270 models (SL-Cxx00)" + select PXA27x + +endchoice + +endif + endmenu config MACH_POODLE bool "Enable Sharp SL-5600 (Poodle) Support" - depends PXA_SHARPSL + depends PXA_SHARPSL_25x select SHARP_LOCOMO config MACH_CORGI bool "Enable Sharp SL-C700 (Corgi) Support" - depends PXA_SHARPSL + depends PXA_SHARPSL_25x select PXA_SHARP_C7xx config MACH_SHEPHERD bool "Enable Sharp SL-C750 (Shepherd) Support" - depends PXA_SHARPSL + depends PXA_SHARPSL_25x select PXA_SHARP_C7xx config MACH_HUSKY bool "Enable Sharp SL-C760 (Husky) Support" - depends PXA_SHARPSL + depends PXA_SHARPSL_25x select PXA_SHARP_C7xx +config MACH_SPITZ + bool "Enable Sharp Zaurus SL-3000 (Spitz) Support" + depends PXA_SHARPSL_27x + select PXA_SHARP_Cxx00 + +config MACH_BORZOI + bool "Enable Sharp Zaurus SL-3100 (Borzoi) Support" + depends PXA_SHARPSL_27x + select PXA_SHARP_Cxx00 + config PXA25x bool help @@ -74,4 +100,9 @@ config PXA_SHARP_C7xx help Enable support for all Sharp C7xx models +config PXA_SHARP_Cxx00 + bool + help + Enable common support for Sharp Cxx00 models + endif diff --git a/arch/arm/mach-pxa/Makefile b/arch/arm/mach-pxa/Makefile index 33dae99..f609a0f 100644 --- a/arch/arm/mach-pxa/Makefile +++ b/arch/arm/mach-pxa/Makefile @@ -12,6 +12,7 @@ obj-$(CONFIG_ARCH_LUBBOCK) += lubbock.o obj-$(CONFIG_MACH_MAINSTONE) += mainstone.o obj-$(CONFIG_ARCH_PXA_IDP) += idp.o obj-$(CONFIG_PXA_SHARP_C7xx) += corgi.o corgi_ssp.o corgi_lcd.o ssp.o +obj-$(CONFIG_PXA_SHARP_Cxx00) += spitz.o corgi_ssp.o corgi_lcd.o ssp.o obj-$(CONFIG_MACH_POODLE) += poodle.o # Support for blinky lights diff --git a/arch/arm/mach-pxa/corgi.c b/arch/arm/mach-pxa/corgi.c index 07b5dd4..be37586 100644 --- a/arch/arm/mach-pxa/corgi.c +++ b/arch/arm/mach-pxa/corgi.c @@ -41,6 +41,7 @@ #include <asm/hardware/scoop.h> #include "generic.h" +#include "sharpsl.h" /* @@ -94,14 +95,30 @@ struct platform_device corgissp_device = { .id = -1, }; +struct corgissp_machinfo corgi_ssp_machinfo = { + .port = 1, + .cs_lcdcon = CORGI_GPIO_LCDCON_CS, + .cs_ads7846 = CORGI_GPIO_ADS7846_CS, + .cs_max1111 = CORGI_GPIO_MAX1111_CS, + .clk_lcdcon = 76, + .clk_ads7846 = 2, + .clk_max1111 = 8, +}; + /* * Corgi Backlight Device */ +static struct corgibl_machinfo corgi_bl_machinfo = { + .max_intensity = 0x2f, + .set_bl_intensity = corgi_bl_set_intensity, +}; + static struct platform_device corgibl_device = { .name = "corgi-bl", .dev = { .parent = &corgifb_device.dev, + .platform_data = &corgi_bl_machinfo, }, .id = -1, }; @@ -119,12 +136,29 @@ static struct platform_device corgikbd_device = { /* * Corgi Touch Screen Device */ +static struct resource corgits_resources[] = { + [0] = { + .start = CORGI_IRQ_GPIO_TP_INT, + .end = CORGI_IRQ_GPIO_TP_INT, + .flags = IORESOURCE_IRQ, + }, +}; + +static struct corgits_machinfo corgi_ts_machinfo = { + .get_hsync_len = corgi_get_hsync_len, + .put_hsync = corgi_put_hsync, + .wait_hsync = corgi_wait_hsync, +}; + static struct platform_device corgits_device = { .name = "corgi-ts", .dev = { .parent = &corgissp_device.dev, + .platform_data = &corgi_ts_machinfo, }, .id = -1, + .num_resources = ARRAY_SIZE(corgits_resources), + .resource = corgits_resources, }; @@ -164,13 +198,10 @@ static void corgi_mci_setpower(struct device *dev, unsigned int vdd) { struct pxamci_platform_data* p_d = dev->platform_data; - if (( 1 << vdd) & p_d->ocr_mask) { - printk(KERN_DEBUG "%s: on\n", __FUNCTION__); + if (( 1 << vdd) & p_d->ocr_mask) GPSR1 = GPIO_bit(CORGI_GPIO_SD_PWR); - } else { - printk(KERN_DEBUG "%s: off\n", __FUNCTION__); + else GPCR1 = GPIO_bit(CORGI_GPIO_SD_PWR); - } } static int corgi_mci_get_ro(struct device *dev) @@ -225,7 +256,20 @@ static struct platform_device *devices[] __initdata = { static void __init corgi_init(void) { + /* setup sleep mode values */ + PWER = 0x00000002; + PFER = 0x00000000; + PRER = 0x00000002; + PGSR0 = 0x0158C000; + PGSR1 = 0x00FF0080; + PGSR2 = 0x0001C004; + /* Stop 3.6MHz and drive HIGH to PCMCIA and CS */ + PCFR |= PCFR_OPDE; + + corgi_ssp_set_machinfo(&corgi_ssp_machinfo); + pxa_gpio_mode(CORGI_GPIO_USB_PULLUP | GPIO_OUT); + pxa_gpio_mode(CORGI_GPIO_HSYNC | GPIO_IN); pxa_set_udc_info(&udc_info); pxa_set_mci_info(&corgi_mci_platform_data); @@ -248,42 +292,14 @@ static void __init fixup_corgi(struct machine_desc *desc, mi->bank[0].size = (64*1024*1024); } -static void __init corgi_init_irq(void) -{ - pxa_init_irq(); -} - -static struct map_desc corgi_io_desc[] __initdata = { -/* virtual physical length */ -/* { 0xf1000000, 0x08000000, 0x01000000, MT_DEVICE },*/ /* LCDC (readable for Qt driver) */ -/* { 0xef700000, 0x10800000, 0x00001000, MT_DEVICE },*/ /* SCOOP */ - { 0xef800000, 0x00000000, 0x00800000, MT_DEVICE }, /* Boot Flash */ -}; - -static void __init corgi_map_io(void) -{ - pxa_map_io(); - iotable_init(corgi_io_desc,ARRAY_SIZE(corgi_io_desc)); - - /* setup sleep mode values */ - PWER = 0x00000002; - PFER = 0x00000000; - PRER = 0x00000002; - PGSR0 = 0x0158C000; - PGSR1 = 0x00FF0080; - PGSR2 = 0x0001C004; - /* Stop 3.6MHz and drive HIGH to PCMCIA and CS */ - PCFR |= PCFR_OPDE; -} - #ifdef CONFIG_MACH_CORGI MACHINE_START(CORGI, "SHARP Corgi") .phys_ram = 0xa0000000, .phys_io = 0x40000000, .io_pg_offst = (io_p2v(0x40000000) >> 18) & 0xfffc, .fixup = fixup_corgi, - .map_io = corgi_map_io, - .init_irq = corgi_init_irq, + .map_io = pxa_map_io, + .init_irq = pxa_init_irq, .init_machine = corgi_init, .timer = &pxa_timer, MACHINE_END @@ -295,8 +311,8 @@ MACHINE_START(SHEPHERD, "SHARP Shepherd") .phys_io = 0x40000000, .io_pg_offst = (io_p2v(0x40000000) >> 18) & 0xfffc, .fixup = fixup_corgi, - .map_io = corgi_map_io, - .init_irq = corgi_init_irq, + .map_io = pxa_map_io, + .init_irq = pxa_init_irq, .init_machine = corgi_init, .timer = &pxa_timer, MACHINE_END @@ -308,8 +324,8 @@ MACHINE_START(HUSKY, "SHARP Husky") .phys_io = 0x40000000, .io_pg_offst = (io_p2v(0x40000000) >> 18) & 0xfffc, .fixup = fixup_corgi, - .map_io = corgi_map_io, - .init_irq = corgi_init_irq, + .map_io = pxa_map_io, + .init_irq = pxa_init_irq, .init_machine = corgi_init, .timer = &pxa_timer, MACHINE_END diff --git a/arch/arm/mach-pxa/corgi_lcd.c b/arch/arm/mach-pxa/corgi_lcd.c index deac29c..c5efcd0 100644 --- a/arch/arm/mach-pxa/corgi_lcd.c +++ b/arch/arm/mach-pxa/corgi_lcd.c @@ -1,10 +1,14 @@ /* * linux/drivers/video/w100fb.c * - * Corgi LCD Specific Code for ATI Imageon w100 (Wallaby) + * Corgi/Spitz LCD Specific Code * * Copyright (C) 2005 Richard Purdie * + * Connectivity: + * Corgi - LCD to ATI Imageon w100 (Wallaby) + * Spitz - LCD to PXA Framebuffer + * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. @@ -14,9 +18,17 @@ #include <linux/delay.h> #include <linux/kernel.h> #include <linux/device.h> +#include <linux/module.h> +#include <asm/mach-types.h> +#include <asm/arch/akita.h> #include <asm/arch/corgi.h> +#include <asm/arch/hardware.h> +#include <asm/arch/pxa-regs.h> +#include <asm/arch/sharpsl.h> +#include <asm/arch/spitz.h> +#include <asm/hardware/scoop.h> #include <asm/mach/sharpsl_param.h> -#include <video/w100fb.h> +#include "generic.h" /* Register Addresses */ #define RESCTL_ADRS 0x00 @@ -134,10 +146,10 @@ static void lcdtg_set_common_voltage(u8 base_data, u8 data) } /* Set Phase Adjuct */ -static void lcdtg_set_phadadj(struct w100fb_par *par) +static void lcdtg_set_phadadj(int mode) { int adj; - switch(par->xres) { + switch(mode) { case 480: case 640: /* Setting for VGA */ @@ -161,7 +173,7 @@ static void lcdtg_set_phadadj(struct w100fb_par *par) static int lcd_inited; -static void lcdtg_hw_init(struct w100fb_par *par) +static void lcdtg_hw_init(int mode) { if (!lcd_inited) { int comadj; @@ -215,7 +227,7 @@ static void lcdtg_hw_init(struct w100fb_par *par) corgi_ssp_lcdtg_send(PICTRL_ADRS, 0); /* Set Phase Adjuct */ - lcdtg_set_phadadj(par); + lcdtg_set_phadadj(mode); /* Initialize for Input Signals from ATI */ corgi_ssp_lcdtg_send(POLCTRL_ADRS, POLCTRL_SYNC_POL_RISE | POLCTRL_EN_POL_RISE @@ -224,10 +236,10 @@ static void lcdtg_hw_init(struct w100fb_par *par) lcd_inited=1; } else { - lcdtg_set_phadadj(par); + lcdtg_set_phadadj(mode); } - switch(par->xres) { + switch(mode) { case 480: case 640: /* Set Lcd Resolution (VGA) */ @@ -242,7 +254,7 @@ static void lcdtg_hw_init(struct w100fb_par *par) } } -static void lcdtg_suspend(struct w100fb_par *par) +static void lcdtg_suspend(void) { /* 60Hz x 2 frame = 16.7msec x 2 = 33.4 msec */ mdelay(34); @@ -276,15 +288,30 @@ static void lcdtg_suspend(struct w100fb_par *par) lcd_inited = 0; } -static struct w100_tg_info corgi_lcdtg_info = { - .change=lcdtg_hw_init, - .suspend=lcdtg_suspend, - .resume=lcdtg_hw_init, -}; /* * Corgi w100 Frame Buffer Device */ +#ifdef CONFIG_PXA_SHARP_C7xx + +#include <video/w100fb.h> + +static void w100_lcdtg_suspend(struct w100fb_par *par) +{ + lcdtg_suspend(); +} + +static void w100_lcdtg_init(struct w100fb_par *par) +{ + lcdtg_hw_init(par->xres); +} + + +static struct w100_tg_info corgi_lcdtg_info = { + .change = w100_lcdtg_init, + .suspend = w100_lcdtg_suspend, + .resume = w100_lcdtg_init, +}; static struct w100_mem_info corgi_fb_mem = { .ext_cntl = 0x00040003, @@ -394,3 +421,145 @@ struct platform_device corgifb_device = { }, }; +#endif + + +/* + * Spitz PXA Frame Buffer Device + */ +#ifdef CONFIG_PXA_SHARP_Cxx00 + +#include <asm/arch/pxafb.h> + +void spitz_lcd_power(int on) +{ + if (on) + lcdtg_hw_init(480); + else + lcdtg_suspend(); +} + +#endif + + +/* + * Corgi/Spitz Touchscreen to LCD interface + */ +static unsigned long (*get_hsync_time)(struct device *dev); + +static void inline sharpsl_wait_sync(int gpio) +{ + while((GPLR(gpio) & GPIO_bit(gpio)) == 0); + while((GPLR(gpio) & GPIO_bit(gpio)) != 0); +} + +#ifdef CONFIG_PXA_SHARP_C7xx +unsigned long corgi_get_hsync_len(void) +{ + if (!get_hsync_time) + get_hsync_time = symbol_get(w100fb_get_hsynclen); + if (!get_hsync_time) + return 0; + + return get_hsync_time(&corgifb_device.dev); +} + +void corgi_put_hsync(void) +{ + if (get_hsync_time) + symbol_put(w100fb_get_hsynclen); +} + +void corgi_wait_hsync(void) +{ + sharpsl_wait_sync(CORGI_GPIO_HSYNC); +} +#endif + +#ifdef CONFIG_PXA_SHARP_Cxx00 +unsigned long spitz_get_hsync_len(void) +{ + if (!get_hsync_time) + get_hsync_time = symbol_get(pxafb_get_hsync_time); + if (!get_hsync_time) + return 0; + + return pxafb_get_hsync_time(&pxafb_device.dev); +} + +void spitz_put_hsync(void) +{ + if (get_hsync_time) + symbol_put(pxafb_get_hsync_time); +} + +void spitz_wait_hsync(void) +{ + sharpsl_wait_sync(SPITZ_GPIO_HSYNC); +} +#endif + +/* + * Corgi/Spitz Backlight Power + */ +#ifdef CONFIG_PXA_SHARP_C7xx +void corgi_bl_set_intensity(int intensity) +{ + if (intensity > 0x10) + intensity += 0x10; + + /* Bits 0-4 are accessed via the SSP interface */ + corgi_ssp_blduty_set(intensity & 0x1f); + + /* Bit 5 is via SCOOP */ + if (intensity & 0x0020) + set_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_BACKLIGHT_CONT); + else + reset_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_BACKLIGHT_CONT); +} +#endif + + +#if defined(CONFIG_MACH_SPITZ) || defined(CONFIG_MACH_BORZOI) +void spitz_bl_set_intensity(int intensity) +{ + if (intensity > 0x10) + intensity += 0x10; + + /* Bits 0-4 are accessed via the SSP interface */ + corgi_ssp_blduty_set(intensity & 0x1f); + + /* Bit 5 is via SCOOP */ + if (intensity & 0x0020) + reset_scoop_gpio(&spitzscoop2_device.dev, SPITZ_SCP2_BACKLIGHT_CONT); + else + set_scoop_gpio(&spitzscoop2_device.dev, SPITZ_SCP2_BACKLIGHT_CONT); + + if (intensity) + set_scoop_gpio(&spitzscoop2_device.dev, SPITZ_SCP2_BACKLIGHT_ON); + else + reset_scoop_gpio(&spitzscoop2_device.dev, SPITZ_SCP2_BACKLIGHT_ON); +} +#endif + +#ifdef CONFIG_MACH_AKITA +void akita_bl_set_intensity(int intensity) +{ + if (intensity > 0x10) + intensity += 0x10; + + /* Bits 0-4 are accessed via the SSP interface */ + corgi_ssp_blduty_set(intensity & 0x1f); + + /* Bit 5 is via IO-Expander */ + if (intensity & 0x0020) + akita_reset_ioexp(&akitaioexp_device.dev, AKITA_IOEXP_BACKLIGHT_CONT); + else + akita_set_ioexp(&akitaioexp_device.dev, AKITA_IOEXP_BACKLIGHT_CONT); + + if (intensity) + akita_set_ioexp(&akitaioexp_device.dev, AKITA_IOEXP_BACKLIGHT_ON); + else + akita_reset_ioexp(&akitaioexp_device.dev, AKITA_IOEXP_BACKLIGHT_ON); +} +#endif diff --git a/arch/arm/mach-pxa/corgi_ssp.c b/arch/arm/mach-pxa/corgi_ssp.c index 366a9bd..0ef4282 100644 --- a/arch/arm/mach-pxa/corgi_ssp.c +++ b/arch/arm/mach-pxa/corgi_ssp.c @@ -1,7 +1,7 @@ /* * SSP control code for Sharp Corgi devices * - * Copyright (c) 2004 Richard Purdie + * Copyright (c) 2004-2005 Richard Purdie * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -17,14 +17,16 @@ #include <linux/delay.h> #include <linux/device.h> #include <asm/hardware.h> +#include <asm/mach-types.h> #include <asm/arch/ssp.h> -#include <asm/arch/corgi.h> #include <asm/arch/pxa-regs.h> +#include "sharpsl.h" static DEFINE_SPINLOCK(corgi_ssp_lock); static struct ssp_dev corgi_ssp_dev; static struct ssp_state corgi_ssp_state; +static struct corgissp_machinfo *ssp_machinfo; /* * There are three devices connected to the SSP interface: @@ -48,12 +50,12 @@ unsigned long corgi_ssp_ads7846_putget(ulong data) unsigned long ret,flag; spin_lock_irqsave(&corgi_ssp_lock, flag); - GPCR0 = GPIO_bit(CORGI_GPIO_ADS7846_CS); + GPCR(ssp_machinfo->cs_ads7846) = GPIO_bit(ssp_machinfo->cs_ads7846); ssp_write_word(&corgi_ssp_dev,data); ret = ssp_read_word(&corgi_ssp_dev); - GPSR0 = GPIO_bit(CORGI_GPIO_ADS7846_CS); + GPSR(ssp_machinfo->cs_ads7846) = GPIO_bit(ssp_machinfo->cs_ads7846); spin_unlock_irqrestore(&corgi_ssp_lock, flag); return ret; @@ -66,12 +68,12 @@ unsigned long corgi_ssp_ads7846_putget(ulong data) void corgi_ssp_ads7846_lock(void) { spin_lock(&corgi_ssp_lock); - GPCR0 = GPIO_bit(CORGI_GPIO_ADS7846_CS); + GPCR(ssp_machinfo->cs_ads7846) = GPIO_bit(ssp_machinfo->cs_ads7846); } void corgi_ssp_ads7846_unlock(void) { - GPSR0 = GPIO_bit(CORGI_GPIO_ADS7846_CS); + GPSR(ssp_machinfo->cs_ads7846) = GPIO_bit(ssp_machinfo->cs_ads7846); spin_unlock(&corgi_ssp_lock); } @@ -97,23 +99,27 @@ EXPORT_SYMBOL(corgi_ssp_ads7846_get); */ unsigned long corgi_ssp_dac_put(ulong data) { - unsigned long flag; + unsigned long flag, sscr1 = SSCR1_SPH; spin_lock_irqsave(&corgi_ssp_lock, flag); - GPCR0 = GPIO_bit(CORGI_GPIO_LCDCON_CS); + + if (machine_is_spitz() || machine_is_akita() || machine_is_borzoi()) + sscr1 = 0; ssp_disable(&corgi_ssp_dev); - ssp_config(&corgi_ssp_dev, (SSCR0_Motorola | (SSCR0_DSS & 0x07 )), SSCR1_SPH, 0, SSCR0_SerClkDiv(76)); + ssp_config(&corgi_ssp_dev, (SSCR0_Motorola | (SSCR0_DSS & 0x07 )), sscr1, 0, SSCR0_SerClkDiv(ssp_machinfo->clk_lcdcon)); ssp_enable(&corgi_ssp_dev); + GPCR(ssp_machinfo->cs_lcdcon) = GPIO_bit(ssp_machinfo->cs_lcdcon); ssp_write_word(&corgi_ssp_dev,data); /* Read null data back from device to prevent SSP overflow */ ssp_read_word(&corgi_ssp_dev); + GPSR(ssp_machinfo->cs_lcdcon) = GPIO_bit(ssp_machinfo->cs_lcdcon); ssp_disable(&corgi_ssp_dev); - ssp_config(&corgi_ssp_dev, (SSCR0_National | (SSCR0_DSS & 0x0b )), 0, 0, SSCR0_SerClkDiv(2)); + ssp_config(&corgi_ssp_dev, (SSCR0_National | (SSCR0_DSS & 0x0b )), 0, 0, SSCR0_SerClkDiv(ssp_machinfo->clk_ads7846)); ssp_enable(&corgi_ssp_dev); - GPSR0 = GPIO_bit(CORGI_GPIO_LCDCON_CS); + spin_unlock_irqrestore(&corgi_ssp_lock, flag); return 0; @@ -141,9 +147,9 @@ int corgi_ssp_max1111_get(ulong data) int voltage,voltage1,voltage2; spin_lock_irqsave(&corgi_ssp_lock, flag); - GPCR0 = GPIO_bit(CORGI_GPIO_MAX1111_CS); + GPCR(ssp_machinfo->cs_max1111) = GPIO_bit(ssp_machinfo->cs_max1111); ssp_disable(&corgi_ssp_dev); - ssp_config(&corgi_ssp_dev, (SSCR0_Motorola | (SSCR0_DSS & 0x07 )), 0, 0, SSCR0_SerClkDiv(8)); + ssp_config(&corgi_ssp_dev, (SSCR0_Motorola | (SSCR0_DSS & 0x07 )), 0, 0, SSCR0_SerClkDiv(ssp_machinfo->clk_max1111)); ssp_enable(&corgi_ssp_dev); udelay(1); @@ -161,9 +167,9 @@ int corgi_ssp_max1111_get(ulong data) voltage2=ssp_read_word(&corgi_ssp_dev); ssp_disable(&corgi_ssp_dev); - ssp_config(&corgi_ssp_dev, (SSCR0_National | (SSCR0_DSS & 0x0b )), 0, 0, SSCR0_SerClkDiv(2)); + ssp_config(&corgi_ssp_dev, (SSCR0_National | (SSCR0_DSS & 0x0b )), 0, 0, SSCR0_SerClkDiv(ssp_machinfo->clk_ads7846)); ssp_enable(&corgi_ssp_dev); - GPSR0 = GPIO_bit(CORGI_GPIO_MAX1111_CS); + GPSR(ssp_machinfo->cs_max1111) = GPIO_bit(ssp_machinfo->cs_max1111); spin_unlock_irqrestore(&corgi_ssp_lock, flag); if (voltage1 & 0xc0 || voltage2 & 0x3f) @@ -179,25 +185,31 @@ EXPORT_SYMBOL(corgi_ssp_max1111_get); /* * Support Routines */ -int __init corgi_ssp_probe(struct device *dev) + +void __init corgi_ssp_set_machinfo(struct corgissp_machinfo *machinfo) +{ + ssp_machinfo = machinfo; +} + +static int __init corgi_ssp_probe(struct device *dev) { int ret; /* Chip Select - Disable All */ - GPDR0 |= GPIO_bit(CORGI_GPIO_LCDCON_CS); /* output */ - GPSR0 = GPIO_bit(CORGI_GPIO_LCDCON_CS); /* High - Disable LCD Control/Timing Gen */ - GPDR0 |= GPIO_bit(CORGI_GPIO_MAX1111_CS); /* output */ - GPSR0 = GPIO_bit(CORGI_GPIO_MAX1111_CS); /* High - Disable MAX1111*/ - GPDR0 |= GPIO_bit(CORGI_GPIO_ADS7846_CS); /* output */ - GPSR0 = GPIO_bit(CORGI_GPIO_ADS7846_CS); /* High - Disable ADS7846*/ + GPDR(ssp_machinfo->cs_lcdcon) |= GPIO_bit(ssp_machinfo->cs_lcdcon); /* output */ + GPSR(ssp_machinfo->cs_lcdcon) = GPIO_bit(ssp_machinfo->cs_lcdcon); /* High - Disable LCD Control/Timing Gen */ + GPDR(ssp_machinfo->cs_max1111) |= GPIO_bit(ssp_machinfo->cs_max1111); /* output */ + GPSR(ssp_machinfo->cs_max1111) = GPIO_bit(ssp_machinfo->cs_max1111); /* High - Disable MAX1111*/ + GPDR(ssp_machinfo->cs_ads7846) |= GPIO_bit(ssp_machinfo->cs_ads7846); /* output */ + GPSR(ssp_machinfo->cs_ads7846) = GPIO_bit(ssp_machinfo->cs_ads7846); /* High - Disable ADS7846*/ - ret=ssp_init(&corgi_ssp_dev,1); + ret = ssp_init(&corgi_ssp_dev,ssp_machinfo->port); if (ret) printk(KERN_ERR "Unable to register SSP handler!\n"); else { ssp_disable(&corgi_ssp_dev); - ssp_config(&corgi_ssp_dev, (SSCR0_National | (SSCR0_DSS & 0x0b )), 0, 0, SSCR0_SerClkDiv(2)); + ssp_config(&corgi_ssp_dev, (SSCR0_National | (SSCR0_DSS & 0x0b )), 0, 0, SSCR0_SerClkDiv(ssp_machinfo->clk_ads7846)); ssp_enable(&corgi_ssp_dev); } @@ -222,9 +234,9 @@ static int corgi_ssp_suspend(struct device *dev, pm_message_t state, u32 level) static int corgi_ssp_resume(struct device *dev, u32 level) { if (level == RESUME_POWER_ON) { - GPSR0 = GPIO_bit(CORGI_GPIO_LCDCON_CS); /* High - Disable LCD Control/Timing Gen */ - GPSR0 = GPIO_bit(CORGI_GPIO_MAX1111_CS); /* High - Disable MAX1111*/ - GPSR0 = GPIO_bit(CORGI_GPIO_ADS7846_CS); /* High - Disable ADS7846*/ + GPSR(ssp_machinfo->cs_lcdcon) = GPIO_bit(ssp_machinfo->cs_lcdcon); /* High - Disable LCD Control/Timing Gen */ + GPSR(ssp_machinfo->cs_max1111) = GPIO_bit(ssp_machinfo->cs_max1111); /* High - Disable MAX1111*/ + GPSR(ssp_machinfo->cs_ads7846) = GPIO_bit(ssp_machinfo->cs_ads7846); /* High - Disable ADS7846*/ ssp_restore_state(&corgi_ssp_dev,&corgi_ssp_state); ssp_enable(&corgi_ssp_dev); } diff --git a/arch/arm/mach-pxa/lubbock.c b/arch/arm/mach-pxa/lubbock.c index 923f6eb..1f38033 100644 --- a/arch/arm/mach-pxa/lubbock.c +++ b/arch/arm/mach-pxa/lubbock.c @@ -146,6 +146,11 @@ static struct pxa2xx_udc_mach_info udc_info __initdata = { // no D+ pullup; lubbock can't connect/disconnect in software }; +static struct platform_device lub_audio_device = { + .name = "pxa2xx-ac97", + .id = -1, +}; + static struct resource sa1111_resources[] = { [0] = { .start = 0x10000000, @@ -195,6 +200,7 @@ static struct platform_device smc91x_device = { static struct platform_device *devices[] __initdata = { &sa1111_device, + &lub_audio_device, &smc91x_device, }; diff --git a/arch/arm/mach-pxa/poodle.c b/arch/arm/mach-pxa/poodle.c index 47cfb8b..f256388 100644 --- a/arch/arm/mach-pxa/poodle.c +++ b/arch/arm/mach-pxa/poodle.c @@ -30,6 +30,8 @@ #include <asm/arch/pxa-regs.h> #include <asm/arch/irq.h> +#include <asm/arch/mmc.h> +#include <asm/arch/udc.h> #include <asm/arch/poodle.h> #include <asm/arch/pxafb.h> @@ -93,6 +95,83 @@ static struct platform_device locomo_device = { .resource = locomo_resources, }; + +/* + * MMC/SD Device + * + * The card detect interrupt isn't debounced so we delay it by 250ms + * to give the card a chance to fully insert/eject. + */ +static struct pxamci_platform_data poodle_mci_platform_data; + +static int poodle_mci_init(struct device *dev, irqreturn_t (*poodle_detect_int)(int, void *, struct pt_regs *), void *data) +{ + int err; + + /* setup GPIO for PXA25x MMC controller */ + pxa_gpio_mode(GPIO6_MMCCLK_MD); + pxa_gpio_mode(GPIO8_MMCCS0_MD); + pxa_gpio_mode(POODLE_GPIO_nSD_DETECT | GPIO_IN); + pxa_gpio_mode(POODLE_GPIO_SD_PWR | GPIO_OUT); + + poodle_mci_platform_data.detect_delay = msecs_to_jiffies(250); + + err = request_irq(POODLE_IRQ_GPIO_nSD_DETECT, poodle_detect_int, SA_INTERRUPT, + "MMC card detect", data); + if (err) { + printk(KERN_ERR "poodle_mci_init: MMC/SD: can't request MMC card detect IRQ\n"); + return -1; + } + + set_irq_type(POODLE_IRQ_GPIO_nSD_DETECT, IRQT_BOTHEDGE); + + return 0; +} + +static void poodle_mci_setpower(struct device *dev, unsigned int vdd) +{ + struct pxamci_platform_data* p_d = dev->platform_data; + + if (( 1 << vdd) & p_d->ocr_mask) + GPSR1 = GPIO_bit(POODLE_GPIO_SD_PWR); + else + GPCR1 = GPIO_bit(POODLE_GPIO_SD_PWR); +} + +static void poodle_mci_exit(struct device *dev, void *data) +{ + free_irq(POODLE_IRQ_GPIO_nSD_DETECT, data); +} + +static struct pxamci_platform_data poodle_mci_platform_data = { + .ocr_mask = MMC_VDD_32_33|MMC_VDD_33_34, + .init = poodle_mci_init, + .setpower = poodle_mci_setpower, + .exit = poodle_mci_exit, +}; + + +/* + * USB Device Controller + */ +static void poodle_udc_command(int cmd) +{ + switch(cmd) { + case PXA2XX_UDC_CMD_CONNECT: + GPSR(POODLE_GPIO_USB_PULLUP) = GPIO_bit(POODLE_GPIO_USB_PULLUP); + break; + case PXA2XX_UDC_CMD_DISCONNECT: + GPCR(POODLE_GPIO_USB_PULLUP) = GPIO_bit(POODLE_GPIO_USB_PULLUP); + break; + } +} + +static struct pxa2xx_udc_mach_info udc_info __initdata = { + /* no connect GPIO; poodle can't tell connection status */ + .udc_command = poodle_udc_command, +}; + + /* PXAFB device */ static struct pxafb_mach_info poodle_fb_info __initdata = { .pixclock = 144700, @@ -126,6 +205,15 @@ static void __init poodle_init(void) { int ret = 0; + /* setup sleep mode values */ + PWER = 0x00000002; + PFER = 0x00000000; + PRER = 0x00000002; + PGSR0 = 0x00008000; + PGSR1 = 0x003F0202; + PGSR2 = 0x0001C000; + PCFR |= PCFR_OPDE; + /* cpu initialize */ /* Pgsr Register */ PGSR0 = 0x0146dd80; @@ -155,6 +243,9 @@ static void __init poodle_init(void) GPSR2 = 0x00000000; set_pxa_fb_info(&poodle_fb_info); + pxa_gpio_mode(POODLE_GPIO_USB_PULLUP | GPIO_OUT); + pxa_set_udc_info(&udc_info); + pxa_set_mci_info(&poodle_mci_platform_data); scoop_num = 1; scoop_devs = &poodle_pcmcia_scoop[0]; @@ -171,32 +262,12 @@ static void __init fixup_poodle(struct machine_desc *desc, sharpsl_save_param(); } -static struct map_desc poodle_io_desc[] __initdata = { - /* virtual physical length */ - { 0xef800000, 0x00000000, 0x00800000, MT_DEVICE }, /* Boot Flash */ -}; - -static void __init poodle_map_io(void) -{ - pxa_map_io(); - iotable_init(poodle_io_desc, ARRAY_SIZE(poodle_io_desc)); - - /* setup sleep mode values */ - PWER = 0x00000002; - PFER = 0x00000000; - PRER = 0x00000002; - PGSR0 = 0x00008000; - PGSR1 = 0x003F0202; - PGSR2 = 0x0001C000; - PCFR |= PCFR_OPDE; -} - MACHINE_START(POODLE, "SHARP Poodle") .phys_ram = 0xa0000000, .phys_io = 0x40000000, .io_pg_offst = (io_p2v(0x40000000) >> 18) & 0xfffc, .fixup = fixup_poodle, - .map_io = poodle_map_io, + .map_io = pxa_map_io, .init_irq = pxa_init_irq, .timer = &pxa_timer, .init_machine = poodle_init, diff --git a/arch/arm/mach-pxa/sharpsl.h b/arch/arm/mach-pxa/sharpsl.h new file mode 100644 index 0000000..3977a77 --- /dev/null +++ b/arch/arm/mach-pxa/sharpsl.h @@ -0,0 +1,34 @@ +/* + * SharpSL SSP Driver + */ + +struct corgissp_machinfo { + int port; + int cs_lcdcon; + int cs_ads7846; + int cs_max1111; + int clk_lcdcon; + int clk_ads7846; + int clk_max1111; +}; + +void corgi_ssp_set_machinfo(struct corgissp_machinfo *machinfo); + +/* + * SharpSL Backlight + */ + +void corgi_bl_set_intensity(int intensity); +void spitz_bl_set_intensity(int intensity); +void akita_bl_set_intensity(int intensity); + +/* + * SharpSL Touchscreen Driver + */ + +unsigned long corgi_get_hsync_len(void); +unsigned long spitz_get_hsync_len(void); +void corgi_put_hsync(void); +void spitz_put_hsync(void); +void corgi_wait_hsync(void); +void spitz_wait_hsync(void); diff --git a/arch/arm/mach-pxa/spitz.c b/arch/arm/mach-pxa/spitz.c new file mode 100644 index 0000000..568afe3d --- /dev/null +++ b/arch/arm/mach-pxa/spitz.c @@ -0,0 +1,380 @@ +/* + * Support for Sharp SL-Cxx00 Series of PDAs + * Models: SL-C3000 (Spitz), SL-C1000 (Akita) and SL-C3100 (Borzoi) + * + * Copyright (c) 2005 Richard Purdie + * + * Based on Sharp's 2.4 kernel patches/lubbock.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. + * + */ + +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/device.h> +#include <linux/delay.h> +#include <linux/major.h> +#include <linux/fs.h> +#include <linux/interrupt.h> +#include <linux/mmc/host.h> + +#include <asm/setup.h> +#include <asm/memory.h> +#include <asm/mach-types.h> +#include <asm/hardware.h> +#include <asm/irq.h> +#include <asm/io.h> + +#include <asm/mach/arch.h> +#include <asm/mach/map.h> +#include <asm/mach/irq.h> + +#include <asm/arch/pxa-regs.h> +#include <asm/arch/irq.h> +#include <asm/arch/mmc.h> +#include <asm/arch/udc.h> +#include <asm/arch/ohci.h> +#include <asm/arch/pxafb.h> +#include <asm/arch/akita.h> +#include <asm/arch/spitz.h> +#include <asm/arch/sharpsl.h> + +#include <asm/mach/sharpsl_param.h> +#include <asm/hardware/scoop.h> + +#include "generic.h" +#include "sharpsl.h" + +/* + * Spitz SCOOP Device #1 + */ +static struct resource spitz_scoop_resources[] = { + [0] = { + .start = 0x10800000, + .end = 0x10800fff, + .flags = IORESOURCE_MEM, + }, +}; + +static struct scoop_config spitz_scoop_setup = { + .io_dir = SPITZ_SCP_IO_DIR, + .io_out = SPITZ_SCP_IO_OUT, + .suspend_clr = SPITZ_SCP_SUS_CLR, + .suspend_set = SPITZ_SCP_SUS_SET, +}; + +struct platform_device spitzscoop_device = { + .name = "sharp-scoop", + .id = 0, + .dev = { + .platform_data = &spitz_scoop_setup, + }, + .num_resources = ARRAY_SIZE(spitz_scoop_resources), + .resource = spitz_scoop_resources, +}; + +/* + * Spitz SCOOP Device #2 + */ +static struct resource spitz_scoop2_resources[] = { + [0] = { + .start = 0x08800040, + .end = 0x08800fff, + .flags = IORESOURCE_MEM, + }, +}; + +static struct scoop_config spitz_scoop2_setup = { + .io_dir = SPITZ_SCP2_IO_DIR, + .io_out = SPITZ_SCP2_IO_OUT, + .suspend_clr = SPITZ_SCP2_SUS_CLR, + .suspend_set = SPITZ_SCP2_SUS_SET, +}; + +struct platform_device spitzscoop2_device = { + .name = "sharp-scoop", + .id = 1, + .dev = { + .platform_data = &spitz_scoop2_setup, + }, + .num_resources = ARRAY_SIZE(spitz_scoop2_resources), + .resource = spitz_scoop2_resources, +}; + +static struct scoop_pcmcia_dev spitz_pcmcia_scoop[] = { +{ + .dev = &spitzscoop_device.dev, + .irq = SPITZ_IRQ_GPIO_CF_IRQ, + .cd_irq = SPITZ_IRQ_GPIO_CF_CD, + .cd_irq_str = "PCMCIA0 CD", +},{ + .dev = &spitzscoop2_device.dev, + .irq = SPITZ_IRQ_GPIO_CF2_IRQ, + .cd_irq = -1, +}, +}; + + +/* + * Spitz SSP Device + * + * Set the parent as the scoop device because a lot of SSP devices + * also use scoop functions and this makes the power up/down order + * work correctly. + */ +struct platform_device spitzssp_device = { + .name = "corgi-ssp", + .dev = { + .parent = &spitzscoop_device.dev, + }, + .id = -1, +}; + +struct corgissp_machinfo spitz_ssp_machinfo = { + .port = 2, + .cs_lcdcon = SPITZ_GPIO_LCDCON_CS, + .cs_ads7846 = SPITZ_GPIO_ADS7846_CS, + .cs_max1111 = SPITZ_GPIO_MAX1111_CS, + .clk_lcdcon = 520, + .clk_ads7846 = 14, + .clk_max1111 = 56, +}; + + +/* + * Spitz Backlight Device + */ +static struct corgibl_machinfo spitz_bl_machinfo = { + .max_intensity = 0x2f, +}; + +static struct platform_device spitzbl_device = { + .name = "corgi-bl", + .dev = { + .platform_data = &spitz_bl_machinfo, + }, + .id = -1, +}; + + +/* + * Spitz Keyboard Device + */ +static struct platform_device spitzkbd_device = { + .name = "spitz-keyboard", + .id = -1, +}; + + +/* + * Spitz Touch Screen Device + */ +static struct resource spitzts_resources[] = { + [0] = { + .start = SPITZ_IRQ_GPIO_TP_INT, + .end = SPITZ_IRQ_GPIO_TP_INT, + .flags = IORESOURCE_IRQ, + }, +}; + +static struct corgits_machinfo spitz_ts_machinfo = { + .get_hsync_len = spitz_get_hsync_len, + .put_hsync = spitz_put_hsync, + .wait_hsync = spitz_wait_hsync, +}; + +static struct platform_device spitzts_device = { + .name = "corgi-ts", + .dev = { + .parent = &spitzssp_device.dev, + .platform_data = &spitz_ts_machinfo, + }, + .id = -1, + .num_resources = ARRAY_SIZE(spitzts_resources), + .resource = spitzts_resources, +}; + + +/* + * MMC/SD Device + * + * The card detect interrupt isn't debounced so we delay it by 250ms + * to give the card a chance to fully insert/eject. + */ + +static struct pxamci_platform_data spitz_mci_platform_data; + +static int spitz_mci_init(struct device *dev, irqreturn_t (*spitz_detect_int)(int, void *, struct pt_regs *), void *data) +{ + int err; + + /* setup GPIO for PXA27x MMC controller */ + pxa_gpio_mode(GPIO32_MMCCLK_MD); + pxa_gpio_mode(GPIO112_MMCCMD_MD); + pxa_gpio_mode(GPIO92_MMCDAT0_MD); + pxa_gpio_mode(GPIO109_MMCDAT1_MD); + pxa_gpio_mode(GPIO110_MMCDAT2_MD); + pxa_gpio_mode(GPIO111_MMCDAT3_MD); + pxa_gpio_mode(SPITZ_GPIO_nSD_DETECT | GPIO_IN); + pxa_gpio_mode(SPITZ_GPIO_nSD_WP | GPIO_IN); + + spitz_mci_platform_data.detect_delay = msecs_to_jiffies(250); + + err = request_irq(SPITZ_IRQ_GPIO_nSD_DETECT, spitz_detect_int, SA_INTERRUPT, + "MMC card detect", data); + if (err) { + printk(KERN_ERR "spitz_mci_init: MMC/SD: can't request MMC card detect IRQ\n"); + return -1; + } + + set_irq_type(SPITZ_IRQ_GPIO_nSD_DETECT, IRQT_BOTHEDGE); + + return 0; +} + +/* Power control is shared with one of the CF slots so we have a mess */ +static void spitz_mci_setpower(struct device *dev, unsigned int vdd) +{ + struct pxamci_platform_data* p_d = dev->platform_data; + + unsigned short cpr = read_scoop_reg(&spitzscoop_device.dev, SCOOP_CPR); + + if (( 1 << vdd) & p_d->ocr_mask) { + /* printk(KERN_DEBUG "%s: on\n", __FUNCTION__); */ + set_scoop_gpio(&spitzscoop_device.dev, SPITZ_SCP_CF_POWER); + mdelay(2); + write_scoop_reg(&spitzscoop_device.dev, SCOOP_CPR, cpr | 0x04); + } else { + /* printk(KERN_DEBUG "%s: off\n", __FUNCTION__); */ + write_scoop_reg(&spitzscoop_device.dev, SCOOP_CPR, cpr & ~0x04); + + if (!(cpr | 0x02)) { + mdelay(1); + reset_scoop_gpio(&spitzscoop_device.dev, SPITZ_SCP_CF_POWER); + } + } +} + +static int spitz_mci_get_ro(struct device *dev) +{ + return GPLR(SPITZ_GPIO_nSD_WP) & GPIO_bit(SPITZ_GPIO_nSD_WP); +} + +static void spitz_mci_exit(struct device *dev, void *data) +{ + free_irq(SPITZ_IRQ_GPIO_nSD_DETECT, data); +} + +static struct pxamci_platform_data spitz_mci_platform_data = { + .ocr_mask = MMC_VDD_32_33|MMC_VDD_33_34, + .init = spitz_mci_init, + .get_ro = spitz_mci_get_ro, + .setpower = spitz_mci_setpower, + .exit = spitz_mci_exit, +}; + + +/* + * Spitz PXA Framebuffer + */ +static struct pxafb_mach_info spitz_pxafb_info __initdata = { + .pixclock = 19231, + .xres = 480, + .yres = 640, + .bpp = 16, + .hsync_len = 40, + .left_margin = 46, + .right_margin = 125, + .vsync_len = 3, + .upper_margin = 1, + .lower_margin = 0, + .sync = 0, + .lccr0 = LCCR0_Color | LCCR0_Sngl | LCCR0_Act | LCCR0_LDDALT | LCCR0_OUC | LCCR0_CMDIM | LCCR0_RDSTM, + .lccr3 = LCCR3_PixRsEdg | LCCR3_OutEnH, + .pxafb_lcd_power = spitz_lcd_power, +}; + + +static struct platform_device *devices[] __initdata = { + &spitzscoop_device, + &spitzssp_device, + &spitzkbd_device, + &spitzts_device, + &spitzbl_device, + &spitzbattery_device, +}; + +static void __init common_init(void) +{ + PMCR = 0x00; + + /* setup sleep mode values */ + PWER = 0x00000002; + PFER = 0x00000000; + PRER = 0x00000002; + PGSR0 = 0x0158C000; + PGSR1 = 0x00FF0080; + PGSR2 = 0x0001C004; + + /* Stop 3.6MHz and drive HIGH to PCMCIA and CS */ + PCFR |= PCFR_OPDE; + + corgi_ssp_set_machinfo(&spitz_ssp_machinfo); + + pxa_gpio_mode(SPITZ_GPIO_HSYNC | GPIO_IN); + + platform_add_devices(devices, ARRAY_SIZE(devices)); + pxa_set_mci_info(&spitz_mci_platform_data); + pxafb_device.dev.parent = &spitzssp_device.dev; + set_pxa_fb_info(&spitz_pxafb_info); +} + +static void __init spitz_init(void) +{ + scoop_num = 2; + scoop_devs = &spitz_pcmcia_scoop[0]; + spitz_bl_machinfo.set_bl_intensity = spitz_bl_set_intensity; + + common_init(); + + platform_device_register(&spitzscoop2_device); +} + +static void __init fixup_spitz(struct machine_desc *desc, + struct tag *tags, char **cmdline, struct meminfo *mi) +{ + sharpsl_save_param(); + mi->nr_banks = 1; + mi->bank[0].start = 0xa0000000; + mi->bank[0].node = 0; + mi->bank[0].size = (64*1024*1024); +} + +#ifdef CONFIG_MACH_SPITZ +MACHINE_START(SPITZ, "SHARP Spitz") + .phys_ram = 0xa0000000, + .phys_io = 0x40000000, + .io_pg_offst = (io_p2v(0x40000000) >> 18) & 0xfffc, + .fixup = fixup_spitz, + .map_io = pxa_map_io, + .init_irq = pxa_init_irq, + .init_machine = spitz_init, + .timer = &pxa_timer, +MACHINE_END +#endif + +#ifdef CONFIG_MACH_BORZOI +MACHINE_START(BORZOI, "SHARP Borzoi") + .phys_ram = 0xa0000000, + .phys_io = 0x40000000, + .io_pg_offst = (io_p2v(0x40000000) >> 18) & 0xfffc, + .fixup = fixup_spitz, + .map_io = pxa_map_io, + .init_irq = pxa_init_irq, + .init_machine = spitz_init, + .timer = &pxa_timer, +MACHINE_END +#endif diff --git a/arch/arm/mach-s3c2410/mach-anubis.c b/arch/arm/mach-s3c2410/mach-anubis.c index f87aa0b..7c05f27 100644 --- a/arch/arm/mach-s3c2410/mach-anubis.c +++ b/arch/arm/mach-s3c2410/mach-anubis.c @@ -12,6 +12,7 @@ * * Modifications: * 02-May-2005 BJD Copied from mach-bast.c + * 20-Sep-2005 BJD Added static to non-exported items */ #include <linux/kernel.h> @@ -232,7 +233,7 @@ static struct s3c24xx_board anubis_board __initdata = { .clocks_count = ARRAY_SIZE(anubis_clocks) }; -void __init anubis_map_io(void) +static void __init anubis_map_io(void) { /* initialise the clocks */ diff --git a/arch/arm/mach-s3c2410/mach-bast.c b/arch/arm/mach-s3c2410/mach-bast.c index 1a3367d..ed1f07d 100644 --- a/arch/arm/mach-s3c2410/mach-bast.c +++ b/arch/arm/mach-s3c2410/mach-bast.c @@ -31,6 +31,7 @@ * 17-Jul-2005 BJD Changed to platform device for SuperIO 16550s * 25-Jul-2005 BJD Removed ASIX static mappings * 27-Jul-2005 BJD Ensure maximum frequency of i2c bus + * 20-Sep-2005 BJD Added static to non-exported items */ #include <linux/kernel.h> @@ -428,7 +429,7 @@ static struct s3c24xx_board bast_board __initdata = { .clocks_count = ARRAY_SIZE(bast_clocks) }; -void __init bast_map_io(void) +static void __init bast_map_io(void) { /* initialise the clocks */ diff --git a/arch/arm/mach-s3c2410/mach-h1940.c b/arch/arm/mach-s3c2410/mach-h1940.c index 6ff1889..fb3cb012 100644 --- a/arch/arm/mach-s3c2410/mach-h1940.c +++ b/arch/arm/mach-s3c2410/mach-h1940.c @@ -24,6 +24,7 @@ * 10-Jan-2005 BJD Removed include of s3c2410.h * 14-Jan-2005 BJD Added clock init * 10-Mar-2005 LCVR Changed S3C2410_VA to S3C24XX_VA + * 20-Sep-2005 BJD Added static to non-exported items */ #include <linux/kernel.h> @@ -147,7 +148,7 @@ static struct s3c24xx_board h1940_board __initdata = { .devices_count = ARRAY_SIZE(h1940_devices) }; -void __init h1940_map_io(void) +static void __init h1940_map_io(void) { s3c24xx_init_io(h1940_iodesc, ARRAY_SIZE(h1940_iodesc)); s3c24xx_init_clocks(0); @@ -155,13 +156,13 @@ void __init h1940_map_io(void) s3c24xx_set_board(&h1940_board); } -void __init h1940_init_irq(void) +static void __init h1940_init_irq(void) { s3c24xx_init_irq(); } -void __init h1940_init(void) +static void __init h1940_init(void) { set_s3c2410fb_info(&h1940_lcdcfg); } diff --git a/arch/arm/mach-s3c2410/mach-n30.c b/arch/arm/mach-s3c2410/mach-n30.c index 66bf5bb..5c0f2b0 100644 --- a/arch/arm/mach-s3c2410/mach-n30.c +++ b/arch/arm/mach-s3c2410/mach-n30.c @@ -97,7 +97,7 @@ static struct s3c24xx_board n30_board __initdata = { .devices_count = ARRAY_SIZE(n30_devices) }; -void __init n30_map_io(void) +static void __init n30_map_io(void) { s3c24xx_init_io(n30_iodesc, ARRAY_SIZE(n30_iodesc)); s3c24xx_init_clocks(0); @@ -105,14 +105,14 @@ void __init n30_map_io(void) s3c24xx_set_board(&n30_board); } -void __init n30_init_irq(void) +static void __init n30_init_irq(void) { s3c24xx_init_irq(); } /* GPB3 is the line that controls the pull-up for the USB D+ line */ -void __init n30_init(void) +static void __init n30_init(void) { s3c_device_i2c.dev.platform_data = &n30_i2ccfg; diff --git a/arch/arm/mach-s3c2410/mach-nexcoder.c b/arch/arm/mach-s3c2410/mach-nexcoder.c index d24c242..c22f821 100644 --- a/arch/arm/mach-s3c2410/mach-nexcoder.c +++ b/arch/arm/mach-s3c2410/mach-nexcoder.c @@ -136,7 +136,7 @@ static void __init nexcoder_sensorboard_init(void) s3c2410_gpio_cfgpin(S3C2410_GPF2, S3C2410_GPF2_OUTP); // CAM_GPIO6 => CAM_PWRDN } -void __init nexcoder_map_io(void) +static void __init nexcoder_map_io(void) { s3c24xx_init_io(nexcoder_iodesc, ARRAY_SIZE(nexcoder_iodesc)); s3c24xx_init_clocks(0); diff --git a/arch/arm/mach-s3c2410/mach-otom.c b/arch/arm/mach-s3c2410/mach-otom.c index d901ed4..ad1459e 100644 --- a/arch/arm/mach-s3c2410/mach-otom.c +++ b/arch/arm/mach-s3c2410/mach-otom.c @@ -105,7 +105,7 @@ static struct s3c24xx_board otom11_board __initdata = { }; -void __init otom11_map_io(void) +static void __init otom11_map_io(void) { s3c24xx_init_io(otom11_iodesc, ARRAY_SIZE(otom11_iodesc)); s3c24xx_init_clocks(0); diff --git a/arch/arm/mach-s3c2410/mach-rx3715.c b/arch/arm/mach-s3c2410/mach-rx3715.c index a73d61c..22d9e07 100644 --- a/arch/arm/mach-s3c2410/mach-rx3715.c +++ b/arch/arm/mach-s3c2410/mach-rx3715.c @@ -16,6 +16,7 @@ * 14-Jan-2005 BJD Added new clock init * 10-Mar-2005 LCVR Changed S3C2410_VA to S3C24XX_VA * 14-Mar-2005 BJD Fixed __iomem warnings + * 20-Sep-2005 BJD Added static to non-exported items */ #include <linux/kernel.h> @@ -108,7 +109,7 @@ static struct s3c24xx_board rx3715_board __initdata = { .devices_count = ARRAY_SIZE(rx3715_devices) }; -void __init rx3715_map_io(void) +static void __init rx3715_map_io(void) { s3c24xx_init_io(rx3715_iodesc, ARRAY_SIZE(rx3715_iodesc)); s3c24xx_init_clocks(16934000); @@ -116,7 +117,7 @@ void __init rx3715_map_io(void) s3c24xx_set_board(&rx3715_board); } -void __init rx3715_init_irq(void) +static void __init rx3715_init_irq(void) { s3c24xx_init_irq(); } diff --git a/arch/arm/mach-s3c2410/mach-smdk2410.c b/arch/arm/mach-s3c2410/mach-smdk2410.c index 67e903a..2eda55a 100644 --- a/arch/arm/mach-s3c2410/mach-smdk2410.c +++ b/arch/arm/mach-s3c2410/mach-smdk2410.c @@ -28,6 +28,7 @@ * Ben Dooks <ben@simtec.co.uk> * * 10-Mar-2005 LCVR Changed S3C2410_VA to S3C24XX_VA + * 20-Sep-2005 BJD Added static to non-exported items * ***********************************************************************/ @@ -97,7 +98,7 @@ static struct s3c24xx_board smdk2410_board __initdata = { .devices_count = ARRAY_SIZE(smdk2410_devices) }; -void __init smdk2410_map_io(void) +static void __init smdk2410_map_io(void) { s3c24xx_init_io(smdk2410_iodesc, ARRAY_SIZE(smdk2410_iodesc)); s3c24xx_init_clocks(0); @@ -105,7 +106,7 @@ void __init smdk2410_map_io(void) s3c24xx_set_board(&smdk2410_board); } -void __init smdk2410_init_irq(void) +static void __init smdk2410_init_irq(void) { s3c24xx_init_irq(); } diff --git a/arch/arm/mach-s3c2410/mach-smdk2440.c b/arch/arm/mach-s3c2410/mach-smdk2440.c index 3575221..722ef46 100644 --- a/arch/arm/mach-s3c2410/mach-smdk2440.c +++ b/arch/arm/mach-s3c2410/mach-smdk2440.c @@ -18,6 +18,7 @@ * 22-Feb-2005 BJD Updated for 2.6.11-rc5 relesa * 10-Mar-2005 LCVR Replaced S3C2410_VA by S3C24XX_VA * 14-Mar-2005 BJD void __iomem fixes + * 20-Sep-2005 BJD Added static to non-exported items */ #include <linux/kernel.h> @@ -98,7 +99,7 @@ static struct s3c24xx_board smdk2440_board __initdata = { .devices_count = ARRAY_SIZE(smdk2440_devices) }; -void __init smdk2440_map_io(void) +static void __init smdk2440_map_io(void) { s3c24xx_init_io(smdk2440_iodesc, ARRAY_SIZE(smdk2440_iodesc)); s3c24xx_init_clocks(16934400); @@ -106,7 +107,7 @@ void __init smdk2440_map_io(void) s3c24xx_set_board(&smdk2440_board); } -void __init smdk2440_machine_init(void) +static void __init smdk2440_machine_init(void) { /* Configure the LEDs (even if we have no LED support)*/ diff --git a/arch/arm/mach-s3c2410/mach-vr1000.c b/arch/arm/mach-s3c2410/mach-vr1000.c index 8f9ab28..663a7f9 100644 --- a/arch/arm/mach-s3c2410/mach-vr1000.c +++ b/arch/arm/mach-s3c2410/mach-vr1000.c @@ -28,6 +28,7 @@ * 10-Mar-2005 LCVR Changed S3C2410_VA to S3C24XX_VA * 14-Mar-2006 BJD void __iomem fixes * 22-Jun-2006 BJD Added DM9000 platform information + * 20-Sep-2005 BJD Added static to non-exported items */ #include <linux/kernel.h> @@ -347,7 +348,7 @@ static void vr1000_power_off(void) s3c2410_gpio_setpin(S3C2410_GPB9, 1); } -void __init vr1000_map_io(void) +static void __init vr1000_map_io(void) { /* initialise clock sources */ diff --git a/arch/arm/mach-sa1100/collie.c b/arch/arm/mach-sa1100/collie.c index 8cb6911..25d6a4e 100644 --- a/arch/arm/mach-sa1100/collie.c +++ b/arch/arm/mach-sa1100/collie.c @@ -111,12 +111,11 @@ static struct mtd_partition collie_partitions[] = { static void collie_set_vpp(int vpp) { - write_scoop_reg(SCOOP_GPCR, read_scoop_reg(SCOOP_GPCR) | COLLIE_SCP_VPEN); - if (vpp) { - write_scoop_reg(SCOOP_GPWR, read_scoop_reg(SCOOP_GPWR) | COLLIE_SCP_VPEN); - } else { - write_scoop_reg(SCOOP_GPWR, read_scoop_reg(SCOOP_GPWR) & ~COLLIE_SCP_VPEN); - } + write_scoop_reg(&colliescoop_device.dev, SCOOP_GPCR, read_scoop_reg(SCOOP_GPCR) | COLLIE_SCP_VPEN); + if (vpp) + write_scoop_reg(&colliescoop_device.dev, SCOOP_GPWR, read_scoop_reg(SCOOP_GPWR) | COLLIE_SCP_VPEN); + else + write_scoop_reg(&colliescoop_device.dev, SCOOP_GPWR, read_scoop_reg(SCOOP_GPWR) & ~COLLIE_SCP_VPEN); } static struct flash_platform_data collie_flash_data = { diff --git a/arch/arm/mach-sa1100/generic.h b/arch/arm/mach-sa1100/generic.h index 279e3af..f085d68 100644 --- a/arch/arm/mach-sa1100/generic.h +++ b/arch/arm/mach-sa1100/generic.h @@ -39,3 +39,6 @@ extern void sa11x0_set_ssp_data(struct sa11x0_ssp_plat_ops *ops); struct irda_platform_data; void sa11x0_set_irda_data(struct irda_platform_data *irda); + +struct mcp_plat_data; +void sa11x0_set_mcp_data(struct mcp_plat_data *data); diff --git a/arch/arm/mm/fault.c b/arch/arm/mm/fault.c index 0b6c4db..4a884ba 100644 --- a/arch/arm/mm/fault.c +++ b/arch/arm/mm/fault.c @@ -233,7 +233,17 @@ do_page_fault(unsigned long addr, unsigned int fsr, struct pt_regs *regs) if (in_interrupt() || !mm) goto no_context; - down_read(&mm->mmap_sem); + /* + * As per x86, we may deadlock here. However, since the kernel only + * validly references user space from well defined areas of the code, + * we can bug out early if this is from code which shouldn't. + */ + if (!down_read_trylock(&mm->mmap_sem)) { + if (!user_mode(regs) && !search_exception_tables(regs->ARM_pc)) + goto no_context; + down_read(&mm->mmap_sem); + } + fault = __do_page_fault(mm, addr, fsr, tsk); up_read(&mm->mmap_sem); diff --git a/arch/arm/mm/proc-arm1020.S b/arch/arm/mm/proc-arm1020.S index 1d739d2..82ec954 100644 --- a/arch/arm/mm/proc-arm1020.S +++ b/arch/arm/mm/proc-arm1020.S @@ -509,7 +509,7 @@ cpu_arm1020_name: .align - .section ".proc.info", #alloc, #execinstr + .section ".proc.info.init", #alloc, #execinstr .type __arm1020_proc_info,#object __arm1020_proc_info: diff --git a/arch/arm/mm/proc-arm1020e.S b/arch/arm/mm/proc-arm1020e.S index 9b72566..7375fe9 100644 --- a/arch/arm/mm/proc-arm1020e.S +++ b/arch/arm/mm/proc-arm1020e.S @@ -491,7 +491,7 @@ cpu_arm1020e_name: .align - .section ".proc.info", #alloc, #execinstr + .section ".proc.info.init", #alloc, #execinstr .type __arm1020e_proc_info,#object __arm1020e_proc_info: diff --git a/arch/arm/mm/proc-arm1022.S b/arch/arm/mm/proc-arm1022.S index 37b70fa..6ca6390 100644 --- a/arch/arm/mm/proc-arm1022.S +++ b/arch/arm/mm/proc-arm1022.S @@ -473,7 +473,7 @@ cpu_arm1022_name: .align - .section ".proc.info", #alloc, #execinstr + .section ".proc.info.init", #alloc, #execinstr .type __arm1022_proc_info,#object __arm1022_proc_info: diff --git a/arch/arm/mm/proc-arm1026.S b/arch/arm/mm/proc-arm1026.S index 931b690..10317e4 100644 --- a/arch/arm/mm/proc-arm1026.S +++ b/arch/arm/mm/proc-arm1026.S @@ -469,7 +469,7 @@ cpu_arm1026_name: .align - .section ".proc.info", #alloc, #execinstr + .section ".proc.info.init", #alloc, #execinstr .type __arm1026_proc_info,#object __arm1026_proc_info: diff --git a/arch/arm/mm/proc-arm6_7.S b/arch/arm/mm/proc-arm6_7.S index d0f1bbb..8e7e1e7 100644 --- a/arch/arm/mm/proc-arm6_7.S +++ b/arch/arm/mm/proc-arm6_7.S @@ -332,7 +332,7 @@ cpu_arm710_name: .align - .section ".proc.info", #alloc, #execinstr + .section ".proc.info.init", #alloc, #execinstr .type __arm6_proc_info, #object __arm6_proc_info: diff --git a/arch/arm/mm/proc-arm720.S b/arch/arm/mm/proc-arm720.S index c69c9de..a13e018 100644 --- a/arch/arm/mm/proc-arm720.S +++ b/arch/arm/mm/proc-arm720.S @@ -222,7 +222,7 @@ cpu_arm720_name: * See linux/include/asm-arm/procinfo.h for a definition of this structure. */ - .section ".proc.info", #alloc, #execinstr + .section ".proc.info.init", #alloc, #execinstr .type __arm710_proc_info, #object __arm710_proc_info: diff --git a/arch/arm/mm/proc-arm920.S b/arch/arm/mm/proc-arm920.S index 0f490a0..d165138 100644 --- a/arch/arm/mm/proc-arm920.S +++ b/arch/arm/mm/proc-arm920.S @@ -452,7 +452,7 @@ cpu_arm920_name: .align - .section ".proc.info", #alloc, #execinstr + .section ".proc.info.init", #alloc, #execinstr .type __arm920_proc_info,#object __arm920_proc_info: diff --git a/arch/arm/mm/proc-arm922.S b/arch/arm/mm/proc-arm922.S index 62bc34a..23b8ed9 100644 --- a/arch/arm/mm/proc-arm922.S +++ b/arch/arm/mm/proc-arm922.S @@ -456,7 +456,7 @@ cpu_arm922_name: .align - .section ".proc.info", #alloc, #execinstr + .section ".proc.info.init", #alloc, #execinstr .type __arm922_proc_info,#object __arm922_proc_info: diff --git a/arch/arm/mm/proc-arm925.S b/arch/arm/mm/proc-arm925.S index ee49aa2..ee95c52 100644 --- a/arch/arm/mm/proc-arm925.S +++ b/arch/arm/mm/proc-arm925.S @@ -521,7 +521,7 @@ cpu_arm925_name: .align - .section ".proc.info", #alloc, #execinstr + .section ".proc.info.init", #alloc, #execinstr .type __arm925_proc_info,#object __arm925_proc_info: diff --git a/arch/arm/mm/proc-arm926.S b/arch/arm/mm/proc-arm926.S index bb95cc9..7d042dc 100644 --- a/arch/arm/mm/proc-arm926.S +++ b/arch/arm/mm/proc-arm926.S @@ -471,7 +471,7 @@ cpu_arm926_name: .align - .section ".proc.info", #alloc, #execinstr + .section ".proc.info.init", #alloc, #execinstr .type __arm926_proc_info,#object __arm926_proc_info: diff --git a/arch/arm/mm/proc-sa110.S b/arch/arm/mm/proc-sa110.S index 34f7e7d..bd330c4 100644 --- a/arch/arm/mm/proc-sa110.S +++ b/arch/arm/mm/proc-sa110.S @@ -249,7 +249,7 @@ cpu_sa110_name: .align - .section ".proc.info", #alloc, #execinstr + .section ".proc.info.init", #alloc, #execinstr .type __sa110_proc_info,#object __sa110_proc_info: diff --git a/arch/arm/mm/proc-sa1100.S b/arch/arm/mm/proc-sa1100.S index ca14f80..91b8912 100644 --- a/arch/arm/mm/proc-sa1100.S +++ b/arch/arm/mm/proc-sa1100.S @@ -280,7 +280,7 @@ cpu_sa1110_name: .align - .section ".proc.info", #alloc, #execinstr + .section ".proc.info.init", #alloc, #execinstr .type __sa1100_proc_info,#object __sa1100_proc_info: diff --git a/arch/arm/mm/proc-v6.S b/arch/arm/mm/proc-v6.S index eb34823..caf3b19 100644 --- a/arch/arm/mm/proc-v6.S +++ b/arch/arm/mm/proc-v6.S @@ -240,7 +240,7 @@ cpu_elf_name: .size cpu_elf_name, . - cpu_elf_name .align - .section ".proc.info", #alloc, #execinstr + .section ".proc.info.init", #alloc, #execinstr /* * Match any ARMv6 processor core. diff --git a/arch/arm/mm/proc-xscale.S b/arch/arm/mm/proc-xscale.S index b88de270..861b3594 100644 --- a/arch/arm/mm/proc-xscale.S +++ b/arch/arm/mm/proc-xscale.S @@ -578,7 +578,7 @@ cpu_pxa270_name: .align - .section ".proc.info", #alloc, #execinstr + .section ".proc.info.init", #alloc, #execinstr .type __80200_proc_info,#object __80200_proc_info: diff --git a/arch/arm26/boot/compressed/hw-bse.c b/arch/arm26/boot/compressed/hw-bse.c deleted file mode 100644 index 3e8f07f..0000000 --- a/arch/arm26/boot/compressed/hw-bse.c +++ /dev/null @@ -1,74 +0,0 @@ -/* - * Bright Star Engineering Inc. - * - * code for readng parameters from the - * parameter blocks of the boot block - * flash memory - * - */ - -static int strcmp(const char *s1, const char *s2) -{ - while (*s1 != '\0' && *s1 == *s2) - { - s1++; - s2++; - } - - return (*(unsigned char *) s1) - (*(unsigned char *) s2); -} - -struct pblk_t { - char type; - unsigned short size; -}; - -static char *bse_getflashparam(char *name) { - unsigned int esize; - char *q,*r; - unsigned char *p,*e; - struct pblk_t *thepb = (struct pblk_t *) 0x00004000; - struct pblk_t *altpb = (struct pblk_t *) 0x00006000; - if (thepb->type&1) { - if (altpb->type&1) { - /* no valid param block */ - return (char*)0; - } else { - /* altpb is valid */ - struct pblk_t *tmp; - tmp = thepb; - thepb = altpb; - altpb = tmp; - } - } - p = (char*)thepb + sizeof(struct pblk_t); - e = p + thepb->size; - while (p < e) { - q = p; - esize = *p; - if (esize == 0xFF) break; - if (esize == 0) break; - if (esize > 127) { - esize = (esize&0x7F)<<8 | p[1]; - q++; - } - q++; - r=q; - if (*r && ((name == 0) || (!strcmp(name,r)))) { - while (*q++) ; - return q; - } - p+=esize; - } - return (char*)0; -} - -void bse_setup(void) { - /* extract the linux cmdline from flash */ - char *name=bse_getflashparam("linuxboot"); - char *x = (char *)0xc0000100; - if (name) { - while (*name) *x++=*name++; - } - *x=0; -} diff --git a/arch/i386/Kconfig b/arch/i386/Kconfig index b22f003..d2703cd 100644 --- a/arch/i386/Kconfig +++ b/arch/i386/Kconfig @@ -908,11 +908,6 @@ config IRQBALANCE The default yes will allow the kernel to do irq load balancing. Saying no will keep the kernel from doing irq load balancing. -config HAVE_DEC_LOCK - bool - depends on (SMP || PREEMPT) && X86_CMPXCHG - default y - # turning this on wastes a bunch of space. # Summit needs it only when NUMA is on config BOOT_IOREMAP diff --git a/arch/i386/kernel/acpi/earlyquirk.c b/arch/i386/kernel/acpi/earlyquirk.c index 1ae2aee..f1b9d2a 100644 --- a/arch/i386/kernel/acpi/earlyquirk.c +++ b/arch/i386/kernel/acpi/earlyquirk.c @@ -7,7 +7,6 @@ #include <linux/pci.h> #include <asm/pci-direct.h> #include <asm/acpi.h> -#include <asm/apic.h> static int __init check_bridge(int vendor, int device) { @@ -16,15 +15,6 @@ static int __init check_bridge(int vendor, int device) if (vendor == PCI_VENDOR_ID_NVIDIA) { acpi_skip_timer_override = 1; } -#ifdef CONFIG_X86_LOCAL_APIC - /* - * ATI IXP chipsets get double timer interrupts. - * For now just do this for all ATI chipsets. - * FIXME: this needs to be checked for the non ACPI case too. - */ - if (vendor == PCI_VENDOR_ID_ATI) - disable_timer_pin_1 = 1; -#endif return 0; } diff --git a/arch/i386/kernel/reboot.c b/arch/i386/kernel/reboot.c index 1cbb9c0..350ea66 100644 --- a/arch/i386/kernel/reboot.c +++ b/arch/i386/kernel/reboot.c @@ -11,6 +11,7 @@ #include <linux/mc146818rtc.h> #include <linux/efi.h> #include <linux/dmi.h> +#include <linux/ctype.h> #include <asm/uaccess.h> #include <asm/apic.h> #include <asm/desc.h> @@ -28,8 +29,6 @@ static int reboot_thru_bios; #ifdef CONFIG_SMP static int reboot_cpu = -1; -/* shamelessly grabbed from lib/vsprintf.c for readability */ -#define is_digit(c) ((c) >= '0' && (c) <= '9') #endif static int __init reboot_setup(char *str) { @@ -49,9 +48,9 @@ static int __init reboot_setup(char *str) break; #ifdef CONFIG_SMP case 's': /* "smp" reboot by executing reset on BSP or other CPU*/ - if (is_digit(*(str+1))) { + if (isdigit(*(str+1))) { reboot_cpu = (int) (*(str+1) - '0'); - if (is_digit(*(str+2))) + if (isdigit(*(str+2))) reboot_cpu = reboot_cpu*10 + (int)(*(str+2) - '0'); } /* we will leave sorting out the final value diff --git a/arch/i386/kernel/setup.c b/arch/i386/kernel/setup.c index dc39ca6..9b8c8a1 100644 --- a/arch/i386/kernel/setup.c +++ b/arch/i386/kernel/setup.c @@ -848,9 +848,7 @@ static void __init parse_cmdline_early (char ** cmdline_p) #ifdef CONFIG_X86_IO_APIC else if (!memcmp(from, "acpi_skip_timer_override", 24)) acpi_skip_timer_override = 1; -#endif -#ifdef CONFIG_X86_LOCAL_APIC if (!memcmp(from, "disable_timer_pin_1", 19)) disable_timer_pin_1 = 1; if (!memcmp(from, "enable_timer_pin_1", 18)) @@ -859,7 +857,7 @@ static void __init parse_cmdline_early (char ** cmdline_p) /* disable IO-APIC */ else if (!memcmp(from, "noapic", 6)) disable_ioapic_setup(); -#endif /* CONFIG_X86_LOCAL_APIC */ +#endif /* CONFIG_X86_IO_APIC */ #endif /* CONFIG_ACPI */ #ifdef CONFIG_X86_LOCAL_APIC diff --git a/arch/i386/kernel/smpboot.c b/arch/i386/kernel/smpboot.c index c70cd2a..5f0a95d 100644 --- a/arch/i386/kernel/smpboot.c +++ b/arch/i386/kernel/smpboot.c @@ -202,7 +202,7 @@ static void __devinit smp_store_cpu_info(int id) goto valid_k7; /* If we get here, it's not a certified SMP capable AMD system. */ - tainted |= TAINT_UNSAFE_SMP; + add_taint(TAINT_UNSAFE_SMP); } valid_k7: diff --git a/arch/i386/kernel/traps.c b/arch/i386/kernel/traps.c index 09a58cb..431a551 100644 --- a/arch/i386/kernel/traps.c +++ b/arch/i386/kernel/traps.c @@ -807,8 +807,9 @@ void math_error(void __user *eip) cwd = get_fpu_cwd(task); swd = get_fpu_swd(task); switch (swd & ~cwd & 0x3f) { - case 0x000: - default: + case 0x000: /* No unmasked exception */ + return; + default: /* Multiple exceptions */ break; case 0x001: /* Invalid Op */ /* diff --git a/arch/i386/lib/Makefile b/arch/i386/lib/Makefile index 7b1932d..914933e 100644 --- a/arch/i386/lib/Makefile +++ b/arch/i386/lib/Makefile @@ -7,4 +7,3 @@ lib-y = checksum.o delay.o usercopy.o getuser.o putuser.o memcpy.o strstr.o \ bitops.o lib-$(CONFIG_X86_USE_3DNOW) += mmx.o -lib-$(CONFIG_HAVE_DEC_LOCK) += dec_and_lock.o diff --git a/arch/i386/lib/dec_and_lock.c b/arch/i386/lib/dec_and_lock.c deleted file mode 100644 index 8b81b25..0000000 --- a/arch/i386/lib/dec_and_lock.c +++ /dev/null @@ -1,42 +0,0 @@ -/* - * x86 version of "atomic_dec_and_lock()" using - * the atomic "cmpxchg" instruction. - * - * (For CPU's lacking cmpxchg, we use the slow - * generic version, and this one never even gets - * compiled). - */ - -#include <linux/spinlock.h> -#include <linux/module.h> -#include <asm/atomic.h> - -int _atomic_dec_and_lock(atomic_t *atomic, spinlock_t *lock) -{ - int counter; - int newcount; - -repeat: - counter = atomic_read(atomic); - newcount = counter-1; - - if (!newcount) - goto slow_path; - - asm volatile("lock; cmpxchgl %1,%2" - :"=a" (newcount) - :"r" (newcount), "m" (atomic->counter), "0" (counter)); - - /* If the above failed, "eax" will have changed */ - if (newcount != counter) - goto repeat; - return 0; - -slow_path: - spin_lock(lock); - if (atomic_dec_and_test(atomic)) - return 1; - spin_unlock(lock); - return 0; -} -EXPORT_SYMBOL(_atomic_dec_and_lock); diff --git a/arch/ia64/Kconfig b/arch/ia64/Kconfig index ed25d66..945c15a 100644 --- a/arch/ia64/Kconfig +++ b/arch/ia64/Kconfig @@ -298,11 +298,6 @@ config PREEMPT source "mm/Kconfig" -config HAVE_DEC_LOCK - bool - depends on (SMP || PREEMPT) - default y - config IA32_SUPPORT bool "Support for Linux/x86 binaries" help diff --git a/arch/ia64/Makefile b/arch/ia64/Makefile index 70f8ed2..67932ad 100644 --- a/arch/ia64/Makefile +++ b/arch/ia64/Makefile @@ -82,17 +82,7 @@ unwcheck: vmlinux archclean: $(Q)$(MAKE) $(clean)=$(boot) -archprepare: include/asm-ia64/.offsets.h.stamp - -include/asm-ia64/.offsets.h.stamp: - mkdir -p include/asm-ia64 - [ -s include/asm-ia64/asm-offsets.h ] \ - || echo "#define IA64_TASK_SIZE 0" > include/asm-ia64/asm-offsets.h - touch $@ - - - -CLEAN_FILES += vmlinux.gz bootloader include/asm-ia64/.offsets.h.stamp +CLEAN_FILES += vmlinux.gz bootloader boot: lib/lib.a vmlinux $(Q)$(MAKE) $(build)=$(boot) $@ diff --git a/arch/ia64/hp/sim/simscsi.c b/arch/ia64/hp/sim/simscsi.c index 56405db..a18983a 100644 --- a/arch/ia64/hp/sim/simscsi.c +++ b/arch/ia64/hp/sim/simscsi.c @@ -233,6 +233,23 @@ simscsi_readwrite10 (struct scsi_cmnd *sc, int mode) simscsi_readwrite(sc, mode, offset, ((sc->cmnd[7] << 8) | sc->cmnd[8])*512); } +static void simscsi_fillresult(struct scsi_cmnd *sc, char *buf, unsigned len) +{ + + int scatterlen = sc->use_sg; + struct scatterlist *slp; + + if (scatterlen == 0) + memcpy(sc->request_buffer, buf, len); + else for (slp = (struct scatterlist *)sc->buffer; scatterlen-- > 0 && len > 0; slp++) { + unsigned thislen = min(len, slp->length); + + memcpy(page_address(slp->page) + slp->offset, buf, thislen); + slp++; + len -= thislen; + } +} + static int simscsi_queuecommand (struct scsi_cmnd *sc, void (*done)(struct scsi_cmnd *)) { @@ -240,6 +257,7 @@ simscsi_queuecommand (struct scsi_cmnd *sc, void (*done)(struct scsi_cmnd *)) char fname[MAX_ROOT_LEN+16]; size_t disk_size; char *buf; + char localbuf[36]; #if DEBUG_SIMSCSI register long sp asm ("sp"); @@ -263,7 +281,7 @@ simscsi_queuecommand (struct scsi_cmnd *sc, void (*done)(struct scsi_cmnd *)) /* disk doesn't exist... */ break; } - buf = sc->request_buffer; + buf = localbuf; buf[0] = 0; /* magnetic disk */ buf[1] = 0; /* not a removable medium */ buf[2] = 2; /* SCSI-2 compliant device */ @@ -273,6 +291,7 @@ simscsi_queuecommand (struct scsi_cmnd *sc, void (*done)(struct scsi_cmnd *)) buf[6] = 0; /* reserved */ buf[7] = 0; /* various flags */ memcpy(buf + 8, "HP SIMULATED DISK 0.00", 28); + simscsi_fillresult(sc, buf, 36); sc->result = GOOD; break; @@ -304,16 +323,13 @@ simscsi_queuecommand (struct scsi_cmnd *sc, void (*done)(struct scsi_cmnd *)) simscsi_readwrite10(sc, SSC_WRITE); break; - case READ_CAPACITY: if (desc[target_id] < 0 || sc->request_bufflen < 8) { break; } - buf = sc->request_buffer; - + buf = localbuf; disk_size = simscsi_get_disk_size(desc[target_id]); - /* pretend to be a 1GB disk (partition table contains real stuff): */ buf[0] = (disk_size >> 24) & 0xff; buf[1] = (disk_size >> 16) & 0xff; buf[2] = (disk_size >> 8) & 0xff; @@ -323,13 +339,14 @@ simscsi_queuecommand (struct scsi_cmnd *sc, void (*done)(struct scsi_cmnd *)) buf[5] = 0; buf[6] = 2; buf[7] = 0; + simscsi_fillresult(sc, buf, 8); sc->result = GOOD; break; case MODE_SENSE: case MODE_SENSE_10: /* sd.c uses this to determine whether disk does write-caching. */ - memset(sc->request_buffer, 0, 128); + simscsi_fillresult(sc, (char *)empty_zero_page, sc->request_bufflen); sc->result = GOOD; break; diff --git a/arch/ia64/ia32/binfmt_elf32.c b/arch/ia64/ia32/binfmt_elf32.c index 31de70b..a7280d9 100644 --- a/arch/ia64/ia32/binfmt_elf32.c +++ b/arch/ia64/ia32/binfmt_elf32.c @@ -216,12 +216,6 @@ ia32_setup_arg_pages (struct linux_binprm *bprm, int executable_stack) if (!mpnt) return -ENOMEM; - if (security_vm_enough_memory((IA32_STACK_TOP - (PAGE_MASK & (unsigned long) bprm->p)) - >> PAGE_SHIFT)) { - kmem_cache_free(vm_area_cachep, mpnt); - return -ENOMEM; - } - memset(mpnt, 0, sizeof(*mpnt)); down_write(¤t->mm->mmap_sem); diff --git a/arch/ia64/kernel/acpi.c b/arch/ia64/kernel/acpi.c index 28a4529..7e92647 100644 --- a/arch/ia64/kernel/acpi.c +++ b/arch/ia64/kernel/acpi.c @@ -899,7 +899,7 @@ int acpi_register_ioapic(acpi_handle handle, u64 phys_addr, u32 gsi_base) if ((err = iosapic_init(phys_addr, gsi_base))) return err; -#if CONFIG_ACPI_NUMA +#ifdef CONFIG_ACPI_NUMA acpi_map_iosapic(handle, 0, NULL, NULL); #endif /* CONFIG_ACPI_NUMA */ diff --git a/arch/ia64/kernel/asm-offsets.c b/arch/ia64/kernel/asm-offsets.c index f6a2342..7722565 100644 --- a/arch/ia64/kernel/asm-offsets.c +++ b/arch/ia64/kernel/asm-offsets.c @@ -4,6 +4,7 @@ * to extract and format the required data. */ +#define ASM_OFFSETS_C 1 #include <linux/config.h> #include <linux/sched.h> diff --git a/arch/ia64/kernel/entry.S b/arch/ia64/kernel/entry.S index ba0b6a1..0741b066 100644 --- a/arch/ia64/kernel/entry.S +++ b/arch/ia64/kernel/entry.S @@ -491,7 +491,7 @@ GLOBAL_ENTRY(prefetch_stack) ;; lfetch.fault [r16], 128 br.ret.sptk.many rp -END(prefetch_switch_stack) +END(prefetch_stack) GLOBAL_ENTRY(execve) mov r15=__NR_execve // put syscall number in place diff --git a/arch/ia64/kernel/mca_asm.S b/arch/ia64/kernel/mca_asm.S index 499a065..db32fc1 100644 --- a/arch/ia64/kernel/mca_asm.S +++ b/arch/ia64/kernel/mca_asm.S @@ -489,24 +489,27 @@ ia64_state_save: ;; st8 [temp1]=r17,16 // pal_min_state st8 [temp2]=r6,16 // prev_IA64_KR_CURRENT + mov r6=IA64_KR(CURRENT_STACK) + ;; + st8 [temp1]=r6,16 // prev_IA64_KR_CURRENT_STACK + st8 [temp2]=r0,16 // prev_task, starts off as NULL mov r6=cr.ifa ;; - st8 [temp1]=r0,16 // prev_task, starts off as NULL - st8 [temp2]=r12,16 // cr.isr + st8 [temp1]=r12,16 // cr.isr + st8 [temp2]=r6,16 // cr.ifa mov r12=cr.itir ;; - st8 [temp1]=r6,16 // cr.ifa - st8 [temp2]=r12,16 // cr.itir + st8 [temp1]=r12,16 // cr.itir + st8 [temp2]=r11,16 // cr.iipa mov r12=cr.iim ;; - st8 [temp1]=r11,16 // cr.iipa - st8 [temp2]=r12,16 // cr.iim - mov r6=cr.iha + st8 [temp1]=r12,16 // cr.iim (p1) mov r12=IA64_MCA_COLD_BOOT (p2) mov r12=IA64_INIT_WARM_BOOT + mov r6=cr.iha ;; - st8 [temp1]=r6,16 // cr.iha - st8 [temp2]=r12 // os_status, default is cold boot + st8 [temp2]=r6,16 // cr.iha + st8 [temp1]=r12 // os_status, default is cold boot mov r6=IA64_MCA_SAME_CONTEXT ;; st8 [temp1]=r6 // context, default is same context @@ -823,9 +826,12 @@ ia64_state_restore: ld8 r12=[temp1],16 // sal_ra ld8 r9=[temp2],16 // sal_gp ;; - ld8 r22=[temp1],24 // pal_min_state, virtual. skip prev_task + ld8 r22=[temp1],16 // pal_min_state, virtual ld8 r21=[temp2],16 // prev_IA64_KR_CURRENT ;; + ld8 r16=[temp1],16 // prev_IA64_KR_CURRENT_STACK + ld8 r20=[temp2],16 // prev_task + ;; ld8 temp3=[temp1],16 // cr.isr ld8 temp4=[temp2],16 // cr.ifa ;; @@ -846,6 +852,45 @@ ia64_state_restore: ld8 r8=[temp1] // os_status ld8 r10=[temp2] // context + /* Wire IA64_TR_CURRENT_STACK to the stack that we are resuming to. To + * avoid any dependencies on the algorithm in ia64_switch_to(), just + * purge any existing CURRENT_STACK mapping and insert the new one. + * + * r16 contains prev_IA64_KR_CURRENT_STACK, r21 contains + * prev_IA64_KR_CURRENT, these values may have been changed by the C + * code. Do not use r8, r9, r10, r22, they contain values ready for + * the return to SAL. + */ + + mov r15=IA64_KR(CURRENT_STACK) // physical granule mapped by IA64_TR_CURRENT_STACK + ;; + shl r15=r15,IA64_GRANULE_SHIFT + ;; + dep r15=-1,r15,61,3 // virtual granule + mov r18=IA64_GRANULE_SHIFT<<2 // for cr.itir.ps + ;; + ptr.d r15,r18 + ;; + srlz.d + + extr.u r19=r21,61,3 // r21 = prev_IA64_KR_CURRENT + shl r20=r16,IA64_GRANULE_SHIFT // r16 = prev_IA64_KR_CURRENT_STACK + movl r21=PAGE_KERNEL // page properties + ;; + mov IA64_KR(CURRENT_STACK)=r16 + cmp.ne p6,p0=RGN_KERNEL,r19 // new stack is in the kernel region? + or r21=r20,r21 // construct PA | page properties +(p6) br.spnt 1f // the dreaded cpu 0 idle task in region 5:( + ;; + mov cr.itir=r18 + mov cr.ifa=r21 + mov r20=IA64_TR_CURRENT_STACK + ;; + itr.d dtr[r20]=r21 + ;; + srlz.d +1: + br.sptk b0 //EndStub////////////////////////////////////////////////////////////////////// @@ -982,6 +1027,7 @@ ia64_set_kernel_registers: add temp4=temp4, temp1 // &struct ia64_sal_os_state.os_gp add r12=temp1, temp3 // kernel stack pointer on MCA/INIT stack add r13=temp1, r3 // set current to start of MCA/INIT stack + add r20=temp1, r3 // physical start of MCA/INIT stack ;; ld8 r1=[temp4] // OS GP from SAL OS state ;; @@ -991,7 +1037,35 @@ ia64_set_kernel_registers: ;; mov IA64_KR(CURRENT)=r13 - // FIXME: do I need to wire IA64_KR_CURRENT_STACK and IA64_TR_CURRENT_STACK? + /* Wire IA64_TR_CURRENT_STACK to the MCA/INIT handler stack. To avoid + * any dependencies on the algorithm in ia64_switch_to(), just purge + * any existing CURRENT_STACK mapping and insert the new one. + */ + + mov r16=IA64_KR(CURRENT_STACK) // physical granule mapped by IA64_TR_CURRENT_STACK + ;; + shl r16=r16,IA64_GRANULE_SHIFT + ;; + dep r16=-1,r16,61,3 // virtual granule + mov r18=IA64_GRANULE_SHIFT<<2 // for cr.itir.ps + ;; + ptr.d r16,r18 + ;; + srlz.d + + shr.u r16=r20,IA64_GRANULE_SHIFT // r20 = physical start of MCA/INIT stack + movl r21=PAGE_KERNEL // page properties + ;; + mov IA64_KR(CURRENT_STACK)=r16 + or r21=r20,r21 // construct PA | page properties + ;; + mov cr.itir=r18 + mov cr.ifa=r13 + mov r20=IA64_TR_CURRENT_STACK + ;; + itr.d dtr[r20]=r21 + ;; + srlz.d br.sptk b0 diff --git a/arch/ia64/kernel/mca_drv.c b/arch/ia64/kernel/mca_drv.c index 6e68374..f081c60 100644 --- a/arch/ia64/kernel/mca_drv.c +++ b/arch/ia64/kernel/mca_drv.c @@ -56,8 +56,9 @@ static struct page *page_isolate[MAX_PAGE_ISOLATE]; static int num_page_isolate = 0; typedef enum { - ISOLATE_NG = 0, - ISOLATE_OK = 1 + ISOLATE_NG, + ISOLATE_OK, + ISOLATE_NONE } isolate_status_t; /* @@ -74,7 +75,7 @@ static struct { * @paddr: poisoned memory location * * Return value: - * ISOLATE_OK / ISOLATE_NG + * one of isolate_status_t, ISOLATE_OK/NG/NONE. */ static isolate_status_t @@ -84,23 +85,26 @@ mca_page_isolate(unsigned long paddr) struct page *p; /* whether physical address is valid or not */ - if ( !ia64_phys_addr_valid(paddr) ) - return ISOLATE_NG; + if (!ia64_phys_addr_valid(paddr)) + return ISOLATE_NONE; + + if (!pfn_valid(paddr)) + return ISOLATE_NONE; /* convert physical address to physical page number */ p = pfn_to_page(paddr>>PAGE_SHIFT); /* check whether a page number have been already registered or not */ - for( i = 0; i < num_page_isolate; i++ ) - if( page_isolate[i] == p ) + for (i = 0; i < num_page_isolate; i++) + if (page_isolate[i] == p) return ISOLATE_OK; /* already listed */ /* limitation check */ - if( num_page_isolate == MAX_PAGE_ISOLATE ) + if (num_page_isolate == MAX_PAGE_ISOLATE) return ISOLATE_NG; /* kick pages having attribute 'SLAB' or 'Reserved' */ - if( PageSlab(p) || PageReserved(p) ) + if (PageSlab(p) || PageReserved(p)) return ISOLATE_NG; /* add attribute 'Reserved' and register the page */ @@ -122,10 +126,15 @@ mca_handler_bh(unsigned long paddr) current->pid, current->comm); spin_lock(&mca_bh_lock); - if (mca_page_isolate(paddr) == ISOLATE_OK) { + switch (mca_page_isolate(paddr)) { + case ISOLATE_OK: printk(KERN_DEBUG "Page isolation: ( %lx ) success.\n", paddr); - } else { + break; + case ISOLATE_NG: printk(KERN_DEBUG "Page isolation: ( %lx ) failure.\n", paddr); + break; + default: + break; } spin_unlock(&mca_bh_lock); @@ -139,10 +148,10 @@ mca_handler_bh(unsigned long paddr) * @peidx: pointer to index of processor error section */ -static void +static void mca_make_peidx(sal_log_processor_info_t *slpi, peidx_table_t *peidx) { - /* + /* * calculate the start address of * "struct cpuid_info" and "sal_processor_static_info_t". */ @@ -164,7 +173,7 @@ mca_make_peidx(sal_log_processor_info_t *slpi, peidx_table_t *peidx) } /** - * mca_make_slidx - Make index of SAL error record + * mca_make_slidx - Make index of SAL error record * @buffer: pointer to SAL error record * @slidx: pointer to index of SAL error record * @@ -172,12 +181,12 @@ mca_make_peidx(sal_log_processor_info_t *slpi, peidx_table_t *peidx) * 1 if record has platform error / 0 if not */ #define LOG_INDEX_ADD_SECT_PTR(sect, ptr) \ - { slidx_list_t *hl = &slidx_pool.buffer[slidx_pool.cur_idx]; \ - hl->hdr = ptr; \ - list_add(&hl->list, &(sect)); \ - slidx_pool.cur_idx = (slidx_pool.cur_idx + 1)%slidx_pool.max_idx; } + {slidx_list_t *hl = &slidx_pool.buffer[slidx_pool.cur_idx]; \ + hl->hdr = ptr; \ + list_add(&hl->list, &(sect)); \ + slidx_pool.cur_idx = (slidx_pool.cur_idx + 1)%slidx_pool.max_idx; } -static int +static int mca_make_slidx(void *buffer, slidx_table_t *slidx) { int platform_err = 0; @@ -214,28 +223,36 @@ mca_make_slidx(void *buffer, slidx_table_t *slidx) sp = (sal_log_section_hdr_t *)((char*)buffer + ercd_pos); if (!efi_guidcmp(sp->guid, SAL_PROC_DEV_ERR_SECT_GUID)) { LOG_INDEX_ADD_SECT_PTR(slidx->proc_err, sp); - } else if (!efi_guidcmp(sp->guid, SAL_PLAT_MEM_DEV_ERR_SECT_GUID)) { + } else if (!efi_guidcmp(sp->guid, + SAL_PLAT_MEM_DEV_ERR_SECT_GUID)) { platform_err = 1; LOG_INDEX_ADD_SECT_PTR(slidx->mem_dev_err, sp); - } else if (!efi_guidcmp(sp->guid, SAL_PLAT_SEL_DEV_ERR_SECT_GUID)) { + } else if (!efi_guidcmp(sp->guid, + SAL_PLAT_SEL_DEV_ERR_SECT_GUID)) { platform_err = 1; LOG_INDEX_ADD_SECT_PTR(slidx->sel_dev_err, sp); - } else if (!efi_guidcmp(sp->guid, SAL_PLAT_PCI_BUS_ERR_SECT_GUID)) { + } else if (!efi_guidcmp(sp->guid, + SAL_PLAT_PCI_BUS_ERR_SECT_GUID)) { platform_err = 1; LOG_INDEX_ADD_SECT_PTR(slidx->pci_bus_err, sp); - } else if (!efi_guidcmp(sp->guid, SAL_PLAT_SMBIOS_DEV_ERR_SECT_GUID)) { + } else if (!efi_guidcmp(sp->guid, + SAL_PLAT_SMBIOS_DEV_ERR_SECT_GUID)) { platform_err = 1; LOG_INDEX_ADD_SECT_PTR(slidx->smbios_dev_err, sp); - } else if (!efi_guidcmp(sp->guid, SAL_PLAT_PCI_COMP_ERR_SECT_GUID)) { + } else if (!efi_guidcmp(sp->guid, + SAL_PLAT_PCI_COMP_ERR_SECT_GUID)) { platform_err = 1; LOG_INDEX_ADD_SECT_PTR(slidx->pci_comp_err, sp); - } else if (!efi_guidcmp(sp->guid, SAL_PLAT_SPECIFIC_ERR_SECT_GUID)) { + } else if (!efi_guidcmp(sp->guid, + SAL_PLAT_SPECIFIC_ERR_SECT_GUID)) { platform_err = 1; LOG_INDEX_ADD_SECT_PTR(slidx->plat_specific_err, sp); - } else if (!efi_guidcmp(sp->guid, SAL_PLAT_HOST_CTLR_ERR_SECT_GUID)) { + } else if (!efi_guidcmp(sp->guid, + SAL_PLAT_HOST_CTLR_ERR_SECT_GUID)) { platform_err = 1; LOG_INDEX_ADD_SECT_PTR(slidx->host_ctlr_err, sp); - } else if (!efi_guidcmp(sp->guid, SAL_PLAT_BUS_ERR_SECT_GUID)) { + } else if (!efi_guidcmp(sp->guid, + SAL_PLAT_BUS_ERR_SECT_GUID)) { platform_err = 1; LOG_INDEX_ADD_SECT_PTR(slidx->plat_bus_err, sp); } else { @@ -253,15 +270,16 @@ mca_make_slidx(void *buffer, slidx_table_t *slidx) * Return value: * 0 on Success / -ENOMEM on Failure */ -static int +static int init_record_index_pools(void) { int i; int rec_max_size; /* Maximum size of SAL error records */ int sect_min_size; /* Minimum size of SAL error sections */ /* minimum size table of each section */ - static int sal_log_sect_min_sizes[] = { - sizeof(sal_log_processor_info_t) + sizeof(sal_processor_static_info_t), + static int sal_log_sect_min_sizes[] = { + sizeof(sal_log_processor_info_t) + + sizeof(sal_processor_static_info_t), sizeof(sal_log_mem_dev_err_info_t), sizeof(sal_log_sel_dev_err_info_t), sizeof(sal_log_pci_bus_err_info_t), @@ -294,7 +312,8 @@ init_record_index_pools(void) /* - 3 - */ slidx_pool.max_idx = (rec_max_size/sect_min_size) * 2 + 1; - slidx_pool.buffer = (slidx_list_t *) kmalloc(slidx_pool.max_idx * sizeof(slidx_list_t), GFP_KERNEL); + slidx_pool.buffer = (slidx_list_t *) + kmalloc(slidx_pool.max_idx * sizeof(slidx_list_t), GFP_KERNEL); return slidx_pool.buffer ? 0 : -ENOMEM; } @@ -308,6 +327,7 @@ init_record_index_pools(void) * is_mca_global - Check whether this MCA is global or not * @peidx: pointer of index of processor error section * @pbci: pointer to pal_bus_check_info_t + * @sos: pointer to hand off struct between SAL and OS * * Return value: * MCA_IS_LOCAL / MCA_IS_GLOBAL @@ -317,11 +337,12 @@ static mca_type_t is_mca_global(peidx_table_t *peidx, pal_bus_check_info_t *pbci, struct ia64_sal_os_state *sos) { - pal_processor_state_info_t *psp = (pal_processor_state_info_t*)peidx_psp(peidx); + pal_processor_state_info_t *psp = + (pal_processor_state_info_t*)peidx_psp(peidx); - /* + /* * PAL can request a rendezvous, if the MCA has a global scope. - * If "rz_always" flag is set, SAL requests MCA rendezvous + * If "rz_always" flag is set, SAL requests MCA rendezvous * in spite of global MCA. * Therefore it is local MCA when rendezvous has not been requested. * Failed to rendezvous, the system must be down. @@ -381,13 +402,15 @@ is_mca_global(peidx_table_t *peidx, pal_bus_check_info_t *pbci, * @slidx: pointer of index of SAL error record * @peidx: pointer of index of processor error section * @pbci: pointer of pal_bus_check_info + * @sos: pointer to hand off struct between SAL and OS * * Return value: * 1 on Success / 0 on Failure */ static int -recover_from_read_error(slidx_table_t *slidx, peidx_table_t *peidx, pal_bus_check_info_t *pbci, +recover_from_read_error(slidx_table_t *slidx, + peidx_table_t *peidx, pal_bus_check_info_t *pbci, struct ia64_sal_os_state *sos) { sal_log_mod_error_info_t *smei; @@ -453,24 +476,28 @@ recover_from_read_error(slidx_table_t *slidx, peidx_table_t *peidx, pal_bus_chec * @slidx: pointer of index of SAL error record * @peidx: pointer of index of processor error section * @pbci: pointer of pal_bus_check_info + * @sos: pointer to hand off struct between SAL and OS * * Return value: * 1 on Success / 0 on Failure */ static int -recover_from_platform_error(slidx_table_t *slidx, peidx_table_t *peidx, pal_bus_check_info_t *pbci, +recover_from_platform_error(slidx_table_t *slidx, peidx_table_t *peidx, + pal_bus_check_info_t *pbci, struct ia64_sal_os_state *sos) { int status = 0; - pal_processor_state_info_t *psp = (pal_processor_state_info_t*)peidx_psp(peidx); + pal_processor_state_info_t *psp = + (pal_processor_state_info_t*)peidx_psp(peidx); if (psp->bc && pbci->eb && pbci->bsi == 0) { switch(pbci->type) { case 1: /* partial read */ case 3: /* full line(cpu) read */ case 9: /* I/O space read */ - status = recover_from_read_error(slidx, peidx, pbci, sos); + status = recover_from_read_error(slidx, peidx, pbci, + sos); break; case 0: /* unknown */ case 2: /* partial write */ @@ -481,7 +508,8 @@ recover_from_platform_error(slidx_table_t *slidx, peidx_table_t *peidx, pal_bus_ case 8: /* write coalescing transactions */ case 10: /* I/O space write */ case 11: /* inter-processor interrupt message(IPI) */ - case 12: /* interrupt acknowledge or external task priority cycle */ + case 12: /* interrupt acknowledge or + external task priority cycle */ default: break; } @@ -496,6 +524,7 @@ recover_from_platform_error(slidx_table_t *slidx, peidx_table_t *peidx, pal_bus_ * @slidx: pointer of index of SAL error record * @peidx: pointer of index of processor error section * @pbci: pointer of pal_bus_check_info + * @sos: pointer to hand off struct between SAL and OS * * Return value: * 1 on Success / 0 on Failure @@ -509,15 +538,17 @@ recover_from_platform_error(slidx_table_t *slidx, peidx_table_t *peidx, pal_bus_ */ static int -recover_from_processor_error(int platform, slidx_table_t *slidx, peidx_table_t *peidx, pal_bus_check_info_t *pbci, +recover_from_processor_error(int platform, slidx_table_t *slidx, + peidx_table_t *peidx, pal_bus_check_info_t *pbci, struct ia64_sal_os_state *sos) { - pal_processor_state_info_t *psp = (pal_processor_state_info_t*)peidx_psp(peidx); + pal_processor_state_info_t *psp = + (pal_processor_state_info_t*)peidx_psp(peidx); - /* + /* * We cannot recover errors with other than bus_check. */ - if (psp->cc || psp->rc || psp->uc) + if (psp->cc || psp->rc || psp->uc) return 0; /* @@ -546,10 +577,10 @@ recover_from_processor_error(int platform, slidx_table_t *slidx, peidx_table_t * * (e.g. a load from poisoned memory) * This means "there are some platform errors". */ - if (platform) + if (platform) return recover_from_platform_error(slidx, peidx, pbci, sos); - /* - * On account of strange SAL error record, we cannot recover. + /* + * On account of strange SAL error record, we cannot recover. */ return 0; } @@ -557,14 +588,14 @@ recover_from_processor_error(int platform, slidx_table_t *slidx, peidx_table_t * /** * mca_try_to_recover - Try to recover from MCA * @rec: pointer to a SAL error record + * @sos: pointer to hand off struct between SAL and OS * * Return value: * 1 on Success / 0 on Failure */ static int -mca_try_to_recover(void *rec, - struct ia64_sal_os_state *sos) +mca_try_to_recover(void *rec, struct ia64_sal_os_state *sos) { int platform_err; int n_proc_err; @@ -588,7 +619,8 @@ mca_try_to_recover(void *rec, } /* Make index of processor error section */ - mca_make_peidx((sal_log_processor_info_t*)slidx_first_entry(&slidx.proc_err)->hdr, &peidx); + mca_make_peidx((sal_log_processor_info_t*) + slidx_first_entry(&slidx.proc_err)->hdr, &peidx); /* Extract Processor BUS_CHECK[0] */ *((u64*)&pbci) = peidx_check_info(&peidx, bus_check, 0); @@ -598,7 +630,8 @@ mca_try_to_recover(void *rec, return 0; /* Try to recover a processor error */ - return recover_from_processor_error(platform_err, &slidx, &peidx, &pbci, sos); + return recover_from_processor_error(platform_err, &slidx, &peidx, + &pbci, sos); } /* @@ -611,7 +644,7 @@ int __init mca_external_handler_init(void) return -ENOMEM; /* register external mca handlers */ - if (ia64_reg_MCA_extension(mca_try_to_recover)){ + if (ia64_reg_MCA_extension(mca_try_to_recover)) { printk(KERN_ERR "ia64_reg_MCA_extension failed.\n"); kfree(slidx_pool.buffer); return -EFAULT; diff --git a/arch/ia64/kernel/mca_drv.h b/arch/ia64/kernel/mca_drv.h index 0227b76..e2f6fa1 100644 --- a/arch/ia64/kernel/mca_drv.h +++ b/arch/ia64/kernel/mca_drv.h @@ -6,7 +6,7 @@ * Copyright (C) Hidetoshi Seto (seto.hidetoshi@jp.fujitsu.com) */ /* - * Processor error section: + * Processor error section: * * +-sal_log_processor_info_t *info-------------+ * | sal_log_section_hdr_t header; | diff --git a/arch/ia64/kernel/mca_drv_asm.S b/arch/ia64/kernel/mca_drv_asm.S index 2d7e021..3f298ee 100644 --- a/arch/ia64/kernel/mca_drv_asm.S +++ b/arch/ia64/kernel/mca_drv_asm.S @@ -13,45 +13,45 @@ #include <asm/ptrace.h> GLOBAL_ENTRY(mca_handler_bhhook) - invala // clear RSE ? - ;; // - cover // - ;; // - clrrrb // + invala // clear RSE ? + ;; + cover + ;; + clrrrb ;; - alloc r16=ar.pfs,0,2,1,0 // make a new frame + alloc r16=ar.pfs,0,2,1,0 // make a new frame ;; - mov ar.rsc=0 + mov ar.rsc=0 ;; - mov r13=IA64_KR(CURRENT) // current task pointer + mov r13=IA64_KR(CURRENT) // current task pointer ;; - mov r2=r13 + mov r2=r13 ;; - addl r22=IA64_RBS_OFFSET,r2 + addl r22=IA64_RBS_OFFSET,r2 ;; - mov ar.bspstore=r22 + mov ar.bspstore=r22 ;; - addl sp=IA64_STK_OFFSET-IA64_PT_REGS_SIZE,r2 + addl sp=IA64_STK_OFFSET-IA64_PT_REGS_SIZE,r2 ;; - adds r2=IA64_TASK_THREAD_ON_USTACK_OFFSET,r13 + adds r2=IA64_TASK_THREAD_ON_USTACK_OFFSET,r13 ;; - st1 [r2]=r0 // clear current->thread.on_ustack flag - mov loc0=r16 - movl loc1=mca_handler_bh // recovery C function + st1 [r2]=r0 // clear current->thread.on_ustack flag + mov loc0=r16 + movl loc1=mca_handler_bh // recovery C function ;; - mov out0=r8 // poisoned address - mov b6=loc1 + mov out0=r8 // poisoned address + mov b6=loc1 ;; - mov loc1=rp + mov loc1=rp ;; - ssm psr.i + ssm psr.i ;; - br.call.sptk.many rp=b6 // does not return ... + br.call.sptk.many rp=b6 // does not return ... ;; - mov ar.pfs=loc0 - mov rp=loc1 + mov ar.pfs=loc0 + mov rp=loc1 ;; - mov r8=r0 + mov r8=r0 br.ret.sptk.many rp ;; END(mca_handler_bhhook) diff --git a/arch/ia64/kernel/perfmon.c b/arch/ia64/kernel/perfmon.c index 1650353..d71731e 100644 --- a/arch/ia64/kernel/perfmon.c +++ b/arch/ia64/kernel/perfmon.c @@ -574,7 +574,7 @@ pfm_protect_ctx_ctxsw(pfm_context_t *x) return 0UL; } -static inline unsigned long +static inline void pfm_unprotect_ctx_ctxsw(pfm_context_t *x, unsigned long f) { spin_unlock(&(x)->ctx_lock); @@ -2218,12 +2218,13 @@ static void pfm_free_fd(int fd, struct file *file) { struct files_struct *files = current->files; - struct fdtable *fdt = files_fdtable(files); + struct fdtable *fdt; /* * there ie no fd_uninstall(), so we do it here */ spin_lock(&files->file_lock); + fdt = files_fdtable(files); rcu_assign_pointer(fdt->fd[fd], NULL); spin_unlock(&files->file_lock); diff --git a/arch/ia64/lib/Makefile b/arch/ia64/lib/Makefile index 799407e..cb1af59 100644 --- a/arch/ia64/lib/Makefile +++ b/arch/ia64/lib/Makefile @@ -15,7 +15,6 @@ lib-$(CONFIG_ITANIUM) += copy_page.o copy_user.o memcpy.o lib-$(CONFIG_MCKINLEY) += copy_page_mck.o memcpy_mck.o lib-$(CONFIG_PERFMON) += carta_random.o lib-$(CONFIG_MD_RAID5) += xor.o -lib-$(CONFIG_HAVE_DEC_LOCK) += dec_and_lock.o AFLAGS___divdi3.o = AFLAGS___udivdi3.o = -DUNSIGNED diff --git a/arch/ia64/lib/dec_and_lock.c b/arch/ia64/lib/dec_and_lock.c deleted file mode 100644 index c7ce92f..0000000 --- a/arch/ia64/lib/dec_and_lock.c +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright (C) 2003 Jerome Marchand, Bull S.A. - * Cleaned up by David Mosberger-Tang <davidm@hpl.hp.com> - * - * This file is released under the GPLv2, or at your option any later version. - * - * ia64 version of "atomic_dec_and_lock()" using the atomic "cmpxchg" instruction. This - * code is an adaptation of the x86 version of "atomic_dec_and_lock()". - */ - -#include <linux/compiler.h> -#include <linux/module.h> -#include <linux/spinlock.h> -#include <asm/atomic.h> - -/* - * Decrement REFCOUNT and if the count reaches zero, acquire the spinlock. Both of these - * operations have to be done atomically, so that the count doesn't drop to zero without - * acquiring the spinlock first. - */ -int -_atomic_dec_and_lock (atomic_t *refcount, spinlock_t *lock) -{ - int old, new; - - do { - old = atomic_read(refcount); - new = old - 1; - - if (unlikely (old == 1)) { - /* oops, we may be decrementing to zero, do it the slow way... */ - spin_lock(lock); - if (atomic_dec_and_test(refcount)) - return 1; - spin_unlock(lock); - return 0; - } - } while (cmpxchg(&refcount->counter, old, new) != old); - return 0; -} - -EXPORT_SYMBOL(_atomic_dec_and_lock); diff --git a/arch/m32r/Kconfig b/arch/m32r/Kconfig index 1ef3987e..4d100f3 100644 --- a/arch/m32r/Kconfig +++ b/arch/m32r/Kconfig @@ -220,11 +220,6 @@ config PREEMPT Say Y here if you are building a kernel for a desktop, embedded or real-time system. Say N if you are unsure. -config HAVE_DEC_LOCK - bool - depends on (SMP || PREEMPT) - default n - config SMP bool "Symmetric multi-processing support" ---help--- diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig index 0eb71ac..4cd724c 100644 --- a/arch/mips/Kconfig +++ b/arch/mips/Kconfig @@ -1009,10 +1009,6 @@ config GENERIC_CALIBRATE_DELAY bool default y -config HAVE_DEC_LOCK - bool - default y - # # Select some configuration options automatically based on user selections. # diff --git a/arch/mips/kernel/sysirix.c b/arch/mips/kernel/sysirix.c index 4de1556..7ae4af4 100644 --- a/arch/mips/kernel/sysirix.c +++ b/arch/mips/kernel/sysirix.c @@ -581,18 +581,13 @@ asmlinkage int irix_brk(unsigned long brk) } /* - * Check if we have enough memory.. + * Ok, looks good - let it rip. */ - if (security_vm_enough_memory((newbrk-oldbrk) >> PAGE_SHIFT)) { + if (do_brk(oldbrk, newbrk-oldbrk) != oldbrk) { ret = -ENOMEM; goto out; } - - /* - * Ok, looks good - let it rip. - */ mm->brk = brk; - do_brk(oldbrk, newbrk-oldbrk); ret = 0; out: diff --git a/arch/mips/lib/Makefile b/arch/mips/lib/Makefile index 21b92b9..0373034 100644 --- a/arch/mips/lib/Makefile +++ b/arch/mips/lib/Makefile @@ -2,7 +2,7 @@ # Makefile for MIPS-specific library files.. # -lib-y += csum_partial_copy.o dec_and_lock.o memcpy.o promlib.o \ +lib-y += csum_partial_copy.o memcpy.o promlib.o \ strlen_user.o strncpy_user.o strnlen_user.o obj-y += iomap.o diff --git a/arch/mips/lib/dec_and_lock.c b/arch/mips/lib/dec_and_lock.c deleted file mode 100644 index fd82c84..0000000 --- a/arch/mips/lib/dec_and_lock.c +++ /dev/null @@ -1,47 +0,0 @@ -/* - * MIPS version of atomic_dec_and_lock() using cmpxchg - * - * This 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 <linux/module.h> -#include <linux/spinlock.h> -#include <asm/atomic.h> -#include <asm/system.h> - -/* - * This is an implementation of the notion of "decrement a - * reference count, and return locked if it decremented to zero". - * - * This implementation can be used on any architecture that - * has a cmpxchg, and where atomic->value is an int holding - * the value of the atomic (i.e. the high bits aren't used - * for a lock or anything like that). - */ -int _atomic_dec_and_lock(atomic_t *atomic, spinlock_t *lock) -{ - int counter; - int newcount; - - for (;;) { - counter = atomic_read(atomic); - newcount = counter - 1; - if (!newcount) - break; /* do it the slow way */ - - newcount = cmpxchg(&atomic->counter, counter, newcount); - if (newcount == counter) - return 0; - } - - spin_lock(lock); - if (atomic_dec_and_test(atomic)) - return 1; - spin_unlock(lock); - return 0; -} - -EXPORT_SYMBOL(_atomic_dec_and_lock); diff --git a/arch/ppc/Kconfig b/arch/ppc/Kconfig index 347ea28..776941c 100644 --- a/arch/ppc/Kconfig +++ b/arch/ppc/Kconfig @@ -26,10 +26,6 @@ config GENERIC_CALIBRATE_DELAY bool default y -config HAVE_DEC_LOCK - bool - default y - config PPC bool default y diff --git a/arch/ppc/kernel/Makefile b/arch/ppc/kernel/Makefile index 1fb92f1..b1457a8 100644 --- a/arch/ppc/kernel/Makefile +++ b/arch/ppc/kernel/Makefile @@ -15,9 +15,8 @@ extra-y += vmlinux.lds obj-y := entry.o traps.o irq.o idle.o time.o misc.o \ process.o signal.o ptrace.o align.o \ semaphore.o syscalls.o setup.o \ - cputable.o ppc_htab.o + cputable.o ppc_htab.o perfmon.o obj-$(CONFIG_6xx) += l2cr.o cpu_setup_6xx.o -obj-$(CONFIG_E500) += perfmon.o obj-$(CONFIG_SOFTWARE_SUSPEND) += swsusp.o obj-$(CONFIG_POWER4) += cpu_setup_power4.o obj-$(CONFIG_MODULES) += module.o ppc_ksyms.o diff --git a/arch/ppc/kernel/perfmon.c b/arch/ppc/kernel/perfmon.c index fa1dad9..04c1878 100644 --- a/arch/ppc/kernel/perfmon.c +++ b/arch/ppc/kernel/perfmon.c @@ -45,7 +45,7 @@ static void dummy_perf(struct pt_regs *regs) mtpmr(PMRN_PMGC0, pmgc0); } -#else +#elif CONFIG_6xx /* Ensure exceptions are disabled */ static void dummy_perf(struct pt_regs *regs) @@ -55,6 +55,10 @@ static void dummy_perf(struct pt_regs *regs) mmcr0 &= ~MMCR0_PMXE; mtspr(SPRN_MMCR0, mmcr0); } +#else +static void dummy_perf(struct pt_regs *regs) +{ +} #endif void (*perf_irq)(struct pt_regs *) = dummy_perf; diff --git a/arch/ppc/kernel/temp.c b/arch/ppc/kernel/temp.c index fe8bb63..26bd8ea 100644 --- a/arch/ppc/kernel/temp.c +++ b/arch/ppc/kernel/temp.c @@ -21,7 +21,6 @@ #include <linux/interrupt.h> #include <linux/init.h> -#include <asm/segment.h> #include <asm/io.h> #include <asm/reg.h> #include <asm/nvram.h> diff --git a/arch/ppc/kernel/time.c b/arch/ppc/kernel/time.c index a3c5281..22d7fd1 100644 --- a/arch/ppc/kernel/time.c +++ b/arch/ppc/kernel/time.c @@ -58,7 +58,6 @@ #include <linux/init.h> #include <linux/profile.h> -#include <asm/segment.h> #include <asm/io.h> #include <asm/nvram.h> #include <asm/cache.h> diff --git a/arch/ppc/kernel/vmlinux.lds.S b/arch/ppc/kernel/vmlinux.lds.S index 9353584..17d2db7 100644 --- a/arch/ppc/kernel/vmlinux.lds.S +++ b/arch/ppc/kernel/vmlinux.lds.S @@ -96,6 +96,9 @@ 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); __vtop_table_begin = .; @@ -190,5 +193,6 @@ SECTIONS /* Sections to be discarded. */ /DISCARD/ : { *(.exitcall.exit) + *(.exit.data) } } diff --git a/arch/ppc/lib/Makefile b/arch/ppc/lib/Makefile index f1e1fb4..50358e4 100644 --- a/arch/ppc/lib/Makefile +++ b/arch/ppc/lib/Makefile @@ -2,7 +2,7 @@ # Makefile for ppc-specific library files.. # -obj-y := checksum.o string.o strcase.o dec_and_lock.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/arch/ppc/lib/dec_and_lock.c b/arch/ppc/lib/dec_and_lock.c deleted file mode 100644 index b18f0d9..0000000 --- a/arch/ppc/lib/dec_and_lock.c +++ /dev/null @@ -1,38 +0,0 @@ -#include <linux/module.h> -#include <linux/spinlock.h> -#include <asm/atomic.h> -#include <asm/system.h> - -/* - * This is an implementation of the notion of "decrement a - * reference count, and return locked if it decremented to zero". - * - * This implementation can be used on any architecture that - * has a cmpxchg, and where atomic->value is an int holding - * the value of the atomic (i.e. the high bits aren't used - * for a lock or anything like that). - */ -int _atomic_dec_and_lock(atomic_t *atomic, spinlock_t *lock) -{ - int counter; - int newcount; - - for (;;) { - counter = atomic_read(atomic); - newcount = counter - 1; - if (!newcount) - break; /* do it the slow way */ - - newcount = cmpxchg(&atomic->counter, counter, newcount); - if (newcount == counter) - return 0; - } - - spin_lock(lock); - if (atomic_dec_and_test(atomic)) - return 1; - spin_unlock(lock); - return 0; -} - -EXPORT_SYMBOL(_atomic_dec_and_lock); diff --git a/arch/ppc/platforms/chrp_time.c b/arch/ppc/platforms/chrp_time.c index 4864a7d..6037ce7 100644 --- a/arch/ppc/platforms/chrp_time.c +++ b/arch/ppc/platforms/chrp_time.c @@ -22,7 +22,6 @@ #include <linux/init.h> #include <linux/bcd.h> -#include <asm/segment.h> #include <asm/io.h> #include <asm/nvram.h> #include <asm/prom.h> diff --git a/arch/ppc/platforms/pmac_setup.c b/arch/ppc/platforms/pmac_setup.c index b392b9a..4c56a47 100644 --- a/arch/ppc/platforms/pmac_setup.c +++ b/arch/ppc/platforms/pmac_setup.c @@ -719,7 +719,8 @@ pmac_declare_of_platform_devices(void) if (np) { for (np = np->child; np != NULL; np = np->sibling) if (strncmp(np->name, "i2c", 3) == 0) { - of_platform_device_create(np, "uni-n-i2c"); + of_platform_device_create(np, "uni-n-i2c", + NULL); break; } } @@ -727,17 +728,18 @@ pmac_declare_of_platform_devices(void) if (np) { for (np = np->child; np != NULL; np = np->sibling) if (strncmp(np->name, "i2c", 3) == 0) { - of_platform_device_create(np, "u3-i2c"); + of_platform_device_create(np, "u3-i2c", + NULL); break; } } np = find_devices("valkyrie"); if (np) - of_platform_device_create(np, "valkyrie"); + of_platform_device_create(np, "valkyrie", NULL); np = find_devices("platinum"); if (np) - of_platform_device_create(np, "platinum"); + of_platform_device_create(np, "platinum", NULL); return 0; } diff --git a/arch/ppc/syslib/Makefile b/arch/ppc/syslib/Makefile index 8b9b226..b8d08f3 100644 --- a/arch/ppc/syslib/Makefile +++ b/arch/ppc/syslib/Makefile @@ -34,7 +34,8 @@ ifeq ($(CONFIG_40x),y) obj-$(CONFIG_PCI) += indirect_pci.o pci_auto.o ppc405_pci.o endif endif -obj-$(CONFIG_8xx) += m8xx_setup.o ppc8xx_pic.o $(wdt-mpc8xx-y) +obj-$(CONFIG_8xx) += m8xx_setup.o ppc8xx_pic.o $(wdt-mpc8xx-y) \ + ppc_sys.o mpc8xx_devices.o mpc8xx_sys.o ifeq ($(CONFIG_8xx),y) obj-$(CONFIG_PCI) += qspan_pci.o i8259.o endif diff --git a/arch/ppc/syslib/mpc8xx_devices.c b/arch/ppc/syslib/mpc8xx_devices.c new file mode 100644 index 0000000..2b5f0e7 --- /dev/null +++ b/arch/ppc/syslib/mpc8xx_devices.c @@ -0,0 +1,224 @@ +/* + * arch/ppc/syslib/mpc8xx_devices.c + * + * MPC8xx Device descriptions + * + * Maintainer: Kumar Gala <kumar.gala@freescale.com> + * + * Copyright 2005 MontaVista Software, Inc. by Vitaly Bordug<vbordug@ru.mvista.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. + */ + +#include <linux/init.h> +#include <linux/module.h> +#include <linux/device.h> +#include <linux/serial_8250.h> +#include <linux/mii.h> +#include <asm/commproc.h> +#include <asm/mpc8xx.h> +#include <asm/irq.h> +#include <asm/ppc_sys.h> + +/* We use offsets for IORESOURCE_MEM to do not set dependences at compile time. + * They will get fixed up by mach_mpc8xx_fixup + */ + +struct platform_device ppc_sys_platform_devices[] = { + [MPC8xx_CPM_FEC1] = { + .name = "fsl-cpm-fec", + .id = 1, + .num_resources = 2, + .resource = (struct resource[]) { + { + .name = "regs", + .start = 0xe00, + .end = 0xe88, + .flags = IORESOURCE_MEM, + }, + { + .name = "interrupt", + .start = MPC8xx_INT_FEC1, + .end = MPC8xx_INT_FEC1, + .flags = IORESOURCE_IRQ, + }, + }, + }, + [MPC8xx_CPM_FEC2] = { + .name = "fsl-cpm-fec", + .id = 2, + .num_resources = 2, + .resource = (struct resource[]) { + { + .name = "regs", + .start = 0x1e00, + .end = 0x1e88, + .flags = IORESOURCE_MEM, + }, + { + .name = "interrupt", + .start = MPC8xx_INT_FEC2, + .end = MPC8xx_INT_FEC2, + .flags = IORESOURCE_IRQ, + }, + }, + }, + [MPC8xx_CPM_SCC1] = { + .name = "fsl-cpm-scc", + .id = 1, + .num_resources = 3, + .resource = (struct resource[]) { + { + .name = "regs", + .start = 0xa00, + .end = 0xa18, + .flags = IORESOURCE_MEM, + }, + { + .name = "pram", + .start = 0x3c00, + .end = 0x3c80, + .flags = IORESOURCE_MEM, + }, + { + .name = "interrupt", + .start = MPC8xx_INT_SCC1, + .end = MPC8xx_INT_SCC1, + .flags = IORESOURCE_IRQ, + }, + }, + }, + [MPC8xx_CPM_SCC2] = { + .name = "fsl-cpm-scc", + .id = 2, + .num_resources = 3, + .resource = (struct resource[]) { + { + .name = "regs", + .start = 0xa20, + .end = 0xa38, + .flags = IORESOURCE_MEM, + }, + { + .name = "pram", + .start = 0x3d00, + .end = 0x3d80, + .flags = IORESOURCE_MEM, + }, + + { + .name = "interrupt", + .start = MPC8xx_INT_SCC2, + .end = MPC8xx_INT_SCC2, + .flags = IORESOURCE_IRQ, + }, + }, + }, + [MPC8xx_CPM_SCC3] = { + .name = "fsl-cpm-scc", + .id = 3, + .num_resources = 3, + .resource = (struct resource[]) { + { + .name = "regs", + .start = 0xa40, + .end = 0xa58, + .flags = IORESOURCE_MEM, + }, + { + .name = "pram", + .start = 0x3e00, + .end = 0x3e80, + .flags = IORESOURCE_MEM, + }, + + { + .name = "interrupt", + .start = MPC8xx_INT_SCC3, + .end = MPC8xx_INT_SCC3, + .flags = IORESOURCE_IRQ, + }, + }, + }, + [MPC8xx_CPM_SCC4] = { + .name = "fsl-cpm-scc", + .id = 4, + .num_resources = 3, + .resource = (struct resource[]) { + { + .name = "regs", + .start = 0xa60, + .end = 0xa78, + .flags = IORESOURCE_MEM, + }, + { + .name = "pram", + .start = 0x3f00, + .end = 0x3f80, + .flags = IORESOURCE_MEM, + }, + + { + .name = "interrupt", + .start = MPC8xx_INT_SCC4, + .end = MPC8xx_INT_SCC4, + .flags = IORESOURCE_IRQ, + }, + }, + }, + [MPC8xx_CPM_SMC1] = { + .name = "fsl-cpm-smc", + .id = 1, + .num_resources = 2, + .resource = (struct resource[]) { + { + .name = "regs", + .start = 0xa82, + .end = 0xa91, + .flags = IORESOURCE_MEM, + }, + { + .name = "interrupt", + .start = MPC8xx_INT_SMC1, + .end = MPC8xx_INT_SMC1, + .flags = IORESOURCE_IRQ, + }, + }, + }, + [MPC8xx_CPM_SMC2] = { + .name = "fsl-cpm-smc", + .id = 2, + .num_resources = 2, + .resource = (struct resource[]) { + { + .name = "regs", + .start = 0xa92, + .end = 0xaa1, + .flags = IORESOURCE_MEM, + }, + { + .name = "interrupt", + .start = MPC8xx_INT_SMC2, + .end = MPC8xx_INT_SMC2, + .flags = IORESOURCE_IRQ, + }, + }, + }, +}; + +static int __init mach_mpc8xx_fixup(struct platform_device *pdev) +{ + ppc_sys_fixup_mem_resource (pdev, IMAP_ADDR); + return 0; +} + +static int __init mach_mpc8xx_init(void) +{ + ppc_sys_device_fixup = mach_mpc8xx_fixup; + return 0; +} + +postcore_initcall(mach_mpc8xx_init); diff --git a/arch/ppc/syslib/mpc8xx_sys.c b/arch/ppc/syslib/mpc8xx_sys.c new file mode 100644 index 0000000..a532ccc --- /dev/null +++ b/arch/ppc/syslib/mpc8xx_sys.c @@ -0,0 +1,61 @@ +/* + * arch/ppc/platforms/mpc8xx_sys.c + * + * MPC8xx System descriptions + * + * Maintainer: Kumar Gala <kumar.gala@freescale.com> + * + * Copyright 2005 MontaVista Software, Inc. by Vitaly Bordug <vbordug@ru.mvista.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. + */ + +#include <linux/init.h> +#include <linux/module.h> +#include <linux/device.h> +#include <asm/ppc_sys.h> + +struct ppc_sys_spec *cur_ppc_sys_spec; +struct ppc_sys_spec ppc_sys_specs[] = { + { + .ppc_sys_name = "MPC86X", + .mask = 0xFFFFFFFF, + .value = 0x00000000, + .num_devices = 2, + .device_list = (enum ppc_sys_devices[]) + { + MPC8xx_CPM_FEC1, + MPC8xx_CPM_SCC1, + MPC8xx_CPM_SCC2, + MPC8xx_CPM_SCC3, + MPC8xx_CPM_SCC4, + MPC8xx_CPM_SMC1, + MPC8xx_CPM_SMC2, + }, + }, + { + .ppc_sys_name = "MPC885", + .mask = 0xFFFFFFFF, + .value = 0x00000000, + .num_devices = 3, + .device_list = (enum ppc_sys_devices[]) + { + MPC8xx_CPM_FEC1, + MPC8xx_CPM_FEC2, + MPC8xx_CPM_SCC1, + MPC8xx_CPM_SCC2, + MPC8xx_CPM_SCC3, + MPC8xx_CPM_SCC4, + MPC8xx_CPM_SMC1, + MPC8xx_CPM_SMC2, + }, + }, + { /* default match */ + .ppc_sys_name = "", + .mask = 0x00000000, + .value = 0x00000000, + }, +}; diff --git a/arch/ppc/syslib/of_device.c b/arch/ppc/syslib/of_device.c index da8a0f2..93c7231 100644 --- a/arch/ppc/syslib/of_device.c +++ b/arch/ppc/syslib/of_device.c @@ -234,7 +234,9 @@ void of_device_unregister(struct of_device *ofdev) device_unregister(&ofdev->dev); } -struct of_device* of_platform_device_create(struct device_node *np, const char *bus_id) +struct of_device* of_platform_device_create(struct device_node *np, + const char *bus_id, + struct device *parent) { struct of_device *dev; u32 *reg; @@ -247,7 +249,7 @@ struct of_device* of_platform_device_create(struct device_node *np, const char * dev->node = of_node_get(np); dev->dma_mask = 0xffffffffUL; dev->dev.dma_mask = &dev->dma_mask; - dev->dev.parent = NULL; + dev->dev.parent = parent; dev->dev.bus = &of_platform_bus_type; dev->dev.release = of_release_dev; diff --git a/arch/ppc/syslib/open_pic2.c b/arch/ppc/syslib/open_pic2.c index 2e0ea92..9a7e874 100644 --- a/arch/ppc/syslib/open_pic2.c +++ b/arch/ppc/syslib/open_pic2.c @@ -575,7 +575,7 @@ static void openpic2_cached_disable_irq(u_int irq) * we need something better to deal with that... Maybe switch to S1 for * cpufreq changes */ -int openpic2_suspend(struct sys_device *sysdev, u32 state) +int openpic2_suspend(struct sys_device *sysdev, pm_message_t state) { int i; unsigned long flags; diff --git a/arch/ppc/syslib/ppc85xx_setup.c b/arch/ppc/syslib/ppc85xx_setup.c index b7242f1..832b8bf 100644 --- a/arch/ppc/syslib/ppc85xx_setup.c +++ b/arch/ppc/syslib/ppc85xx_setup.c @@ -184,8 +184,8 @@ mpc85xx_setup_pci1(struct pci_controller *hose) pci->powar1 = 0x80044000 | (__ilog2(MPC85XX_PCI1_UPPER_MEM - MPC85XX_PCI1_LOWER_MEM + 1) - 1); - /* Setup outboud IO windows @ MPC85XX_PCI1_IO_BASE */ - pci->potar2 = 0x00000000; + /* Setup outbound IO windows @ MPC85XX_PCI1_IO_BASE */ + pci->potar2 = (MPC85XX_PCI1_LOWER_IO >> 12) & 0x000fffff; pci->potear2 = 0x00000000; pci->powbar2 = (MPC85XX_PCI1_IO_BASE >> 12) & 0x000fffff; /* Enable, IO R/W */ @@ -235,8 +235,8 @@ mpc85xx_setup_pci2(struct pci_controller *hose) pci->powar1 = 0x80044000 | (__ilog2(MPC85XX_PCI2_UPPER_MEM - MPC85XX_PCI2_LOWER_MEM + 1) - 1); - /* Setup outboud IO windows @ MPC85XX_PCI2_IO_BASE */ - pci->potar2 = 0x00000000; + /* Setup outbound IO windows @ MPC85XX_PCI2_IO_BASE */ + pci->potar2 = (MPC85XX_PCI2_LOWER_IO >> 12) & 0x000fffff;; pci->potear2 = 0x00000000; pci->powbar2 = (MPC85XX_PCI2_IO_BASE >> 12) & 0x000fffff; /* Enable, IO R/W */ diff --git a/arch/ppc/syslib/prep_nvram.c b/arch/ppc/syslib/prep_nvram.c index 2bcf8a1..8599850 100644 --- a/arch/ppc/syslib/prep_nvram.c +++ b/arch/ppc/syslib/prep_nvram.c @@ -15,7 +15,6 @@ #include <linux/ioport.h> #include <asm/sections.h> -#include <asm/segment.h> #include <asm/io.h> #include <asm/machdep.h> #include <asm/prep_nvram.h> diff --git a/arch/ppc64/Kconfig b/arch/ppc64/Kconfig index deca68a..c658650 100644 --- a/arch/ppc64/Kconfig +++ b/arch/ppc64/Kconfig @@ -28,10 +28,6 @@ config GENERIC_ISA_DMA bool default y -config HAVE_DEC_LOCK - bool - default y - config EARLY_PRINTK bool default y diff --git a/arch/ppc64/Makefile b/arch/ppc64/Makefile index 17d2c1e..521c2a5 100644 --- a/arch/ppc64/Makefile +++ b/arch/ppc64/Makefile @@ -107,7 +107,7 @@ install: vmlinux $(Q)$(MAKE) $(build)=$(boot) BOOTIMAGE=$(BOOTIMAGE) $@ defaultimage-$(CONFIG_PPC_PSERIES) := zImage -defaultimage-$(CONFIG_PPC_PMAC) := vmlinux +defaultimage-$(CONFIG_PPC_PMAC) := zImage.vmode defaultimage-$(CONFIG_PPC_MAPLE) := zImage defaultimage-$(CONFIG_PPC_ISERIES) := vmlinux KBUILD_IMAGE := $(defaultimage-y) diff --git a/arch/ppc64/kernel/asm-offsets.c b/arch/ppc64/kernel/asm-offsets.c index 17e35d0..1ff4fa0 100644 --- a/arch/ppc64/kernel/asm-offsets.c +++ b/arch/ppc64/kernel/asm-offsets.c @@ -68,6 +68,7 @@ int main(void) DEFINE(THREAD_USED_VR, offsetof(struct thread_struct, used_vr)); #endif /* CONFIG_ALTIVEC */ DEFINE(MM, offsetof(struct task_struct, mm)); + DEFINE(AUDITCONTEXT, offsetof(struct task_struct, audit_context)); DEFINE(DCACHEL1LINESIZE, offsetof(struct ppc64_caches, dline_size)); DEFINE(DCACHEL1LOGLINESIZE, offsetof(struct ppc64_caches, log_dline_size)); diff --git a/arch/ppc64/kernel/entry.S b/arch/ppc64/kernel/entry.S index d133a49..e8c0bbf 100644 --- a/arch/ppc64/kernel/entry.S +++ b/arch/ppc64/kernel/entry.S @@ -276,12 +276,22 @@ _GLOBAL(ppc64_rt_sigsuspend) _GLOBAL(ppc32_rt_sigsuspend) bl .save_nvgprs bl .sys32_rt_sigsuspend - /* If sigsuspend() returns zero, we are going into a signal handler */ 70: cmpdi 0,r3,0 - beq .ret_from_except - /* If it returned -EINTR, we need to return via syscall_exit to set + /* If it returned an error, we need to return via syscall_exit to set the SO bit in cr0 and potentially stop for ptrace. */ - b syscall_exit + bne syscall_exit + /* If sigsuspend() returns zero, we are going into a signal handler. We + may need to call audit_syscall_exit() to mark the exit from sigsuspend() */ +#ifdef CONFIG_AUDIT + ld r3,PACACURRENT(r13) + ld r4,AUDITCONTEXT(r3) + cmpdi 0,r4,0 + beq .ret_from_except /* No audit_context: Leave immediately. */ + li r4, 2 /* AUDITSC_FAILURE */ + li r5,-4 /* It's always -EINTR */ + bl .audit_syscall_exit +#endif + b .ret_from_except _GLOBAL(ppc_fork) bl .save_nvgprs diff --git a/arch/ppc64/kernel/head.S b/arch/ppc64/kernel/head.S index 58c3147..72c6104 100644 --- a/arch/ppc64/kernel/head.S +++ b/arch/ppc64/kernel/head.S @@ -1649,7 +1649,7 @@ _GLOBAL(__secondary_start) ld r3,0(r3) lwz r3,PLATFORM(r3) /* r3 = platform flags */ andi. r3,r3,PLATFORM_LPAR /* Test if bit 0 is set (LPAR bit) */ - bne 98f + beq 98f /* branch if result is 0 */ mfspr r3,PVR srwi r3,r3,16 cmpwi r3,0x37 /* SStar */ @@ -1813,7 +1813,7 @@ _STATIC(start_here_multiplatform) ld r3,0(r3) lwz r3,PLATFORM(r3) /* r3 = platform flags */ andi. r3,r3,PLATFORM_LPAR /* Test if bit 0 is set (LPAR bit) */ - bne 98f + beq 98f /* branch if result is 0 */ mfspr r3,PVR srwi r3,r3,16 cmpwi r3,0x37 /* SStar */ @@ -1834,7 +1834,7 @@ _STATIC(start_here_multiplatform) lwz r3,PLATFORM(r3) /* r3 = platform flags */ /* Test if bit 0 is set (LPAR bit) */ andi. r3,r3,PLATFORM_LPAR - bne 98f + bne 98f /* branch if result is !0 */ LOADADDR(r6,_SDR1) /* Only if NOT LPAR */ sub r6,r6,r26 ld r6,0(r6) /* get the value of _SDR1 */ diff --git a/arch/ppc64/kernel/of_device.c b/arch/ppc64/kernel/of_device.c index da58081..9f200f0 100644 --- a/arch/ppc64/kernel/of_device.c +++ b/arch/ppc64/kernel/of_device.c @@ -233,7 +233,9 @@ void of_device_unregister(struct of_device *ofdev) device_unregister(&ofdev->dev); } -struct of_device* of_platform_device_create(struct device_node *np, const char *bus_id) +struct of_device* of_platform_device_create(struct device_node *np, + const char *bus_id, + struct device *parent) { struct of_device *dev; @@ -245,7 +247,7 @@ struct of_device* of_platform_device_create(struct device_node *np, const char * dev->node = np; dev->dma_mask = 0xffffffffUL; dev->dev.dma_mask = &dev->dma_mask; - dev->dev.parent = NULL; + dev->dev.parent = parent; dev->dev.bus = &of_platform_bus_type; dev->dev.release = of_release_dev; @@ -259,6 +261,7 @@ struct of_device* of_platform_device_create(struct device_node *np, const char * return dev; } + EXPORT_SYMBOL(of_match_device); EXPORT_SYMBOL(of_platform_bus_type); EXPORT_SYMBOL(of_register_driver); diff --git a/arch/ppc64/kernel/pSeries_iommu.c b/arch/ppc64/kernel/pSeries_iommu.c index f0fd7fb..d17f010 100644 --- a/arch/ppc64/kernel/pSeries_iommu.c +++ b/arch/ppc64/kernel/pSeries_iommu.c @@ -265,8 +265,10 @@ static void iommu_table_setparms(struct pci_controller *phb, tbl->it_offset = phb->dma_window_base_cur >> PAGE_SHIFT; /* Test if we are going over 2GB of DMA space */ - if (phb->dma_window_base_cur + phb->dma_window_size > (1L << 31)) + if (phb->dma_window_base_cur + phb->dma_window_size > 0x80000000ul) { + udbg_printf("PCI_DMA: Unexpected number of IOAs under this PHB.\n"); panic("PCI_DMA: Unexpected number of IOAs under this PHB.\n"); + } phb->dma_window_base_cur += phb->dma_window_size; @@ -310,92 +312,85 @@ static void iommu_table_setparms_lpar(struct pci_controller *phb, static void iommu_bus_setup_pSeries(struct pci_bus *bus) { - struct device_node *dn, *pdn; - struct pci_dn *pci; + struct device_node *dn; struct iommu_table *tbl; + struct device_node *isa_dn, *isa_dn_orig; + struct device_node *tmp; + struct pci_dn *pci; + int children; DBG("iommu_bus_setup_pSeries, bus %p, bus->self %p\n", bus, bus->self); - /* For each (root) bus, we carve up the available DMA space in 256MB - * pieces. Since each piece is used by one (sub) bus/device, that would - * give a maximum of 7 devices per PHB. In most cases, this is plenty. - * - * The exception is on Python PHBs (pre-POWER4). Here we don't have EADS - * bridges below the PHB to allocate the sectioned tables to, so instead - * we allocate a 1GB table at the PHB level. + dn = pci_bus_to_OF_node(bus); + pci = PCI_DN(dn); + + if (bus->self) { + /* This is not a root bus, any setup will be done for the + * device-side of the bridge in iommu_dev_setup_pSeries(). + */ + return; + } + + /* Check if the ISA bus on the system is under + * this PHB. */ + isa_dn = isa_dn_orig = of_find_node_by_type(NULL, "isa"); - dn = pci_bus_to_OF_node(bus); - pci = dn->data; - - if (!bus->self) { - /* Root bus */ - if (is_python(dn)) { - unsigned int *iohole; - - DBG("Python root bus %s\n", bus->name); - - iohole = (unsigned int *)get_property(dn, "io-hole", 0); - - if (iohole) { - /* On first bus we need to leave room for the - * ISA address space. Just skip the first 256MB - * alltogether. This leaves 768MB for the window. - */ - DBG("PHB has io-hole, reserving 256MB\n"); - pci->phb->dma_window_size = 3 << 28; - pci->phb->dma_window_base_cur = 1 << 28; - } else { - /* 1GB window by default */ - pci->phb->dma_window_size = 1 << 30; - pci->phb->dma_window_base_cur = 0; - } - - tbl = kmalloc(sizeof(struct iommu_table), GFP_KERNEL); - - iommu_table_setparms(pci->phb, dn, tbl); - pci->iommu_table = iommu_init_table(tbl); - } else { - /* Do a 128MB table at root. This is used for the IDE - * controller on some SMP-mode POWER4 machines. It - * doesn't hurt to allocate it on other machines - * -- it'll just be unused since new tables are - * allocated on the EADS level. - * - * Allocate at offset 128MB to avoid having to deal - * with ISA holes; 128MB table for IDE is plenty. - */ - pci->phb->dma_window_size = 1 << 27; - pci->phb->dma_window_base_cur = 1 << 27; - - tbl = kmalloc(sizeof(struct iommu_table), GFP_KERNEL); - - iommu_table_setparms(pci->phb, dn, tbl); - pci->iommu_table = iommu_init_table(tbl); - - /* All child buses have 256MB tables */ - pci->phb->dma_window_size = 1 << 28; - } - } else { - pdn = pci_bus_to_OF_node(bus->parent); + while (isa_dn && isa_dn != dn) + isa_dn = isa_dn->parent; + + if (isa_dn_orig) + of_node_put(isa_dn_orig); - if (!bus->parent->self && !is_python(pdn)) { - struct iommu_table *tbl; - /* First child and not python means this is the EADS - * level. Allocate new table for this slot with 256MB - * window. - */ + /* Count number of direct PCI children of the PHB. + * All PCI device nodes have class-code property, so it's + * an easy way to find them. + */ + for (children = 0, tmp = dn->child; tmp; tmp = tmp->sibling) + if (get_property(tmp, "class-code", NULL)) + children++; - tbl = kmalloc(sizeof(struct iommu_table), GFP_KERNEL); + DBG("Children: %d\n", children); - iommu_table_setparms(pci->phb, dn, tbl); + /* Calculate amount of DMA window per slot. Each window must be + * a power of two (due to pci_alloc_consistent requirements). + * + * Keep 256MB aside for PHBs with ISA. + */ - pci->iommu_table = iommu_init_table(tbl); - } else { - /* Lower than first child or under python, use parent table */ - pci->iommu_table = PCI_DN(pdn)->iommu_table; - } + if (!isa_dn) { + /* No ISA/IDE - just set window size and return */ + pci->phb->dma_window_size = 0x80000000ul; /* To be divided */ + + while (pci->phb->dma_window_size * children > 0x80000000ul) + pci->phb->dma_window_size >>= 1; + DBG("No ISA/IDE, window size is 0x%lx\n", + pci->phb->dma_window_size); + pci->phb->dma_window_base_cur = 0; + + return; } + + /* If we have ISA, then we probably have an IDE + * controller too. Allocate a 128MB table but + * skip the first 128MB to avoid stepping on ISA + * space. + */ + pci->phb->dma_window_size = 0x8000000ul; + pci->phb->dma_window_base_cur = 0x8000000ul; + + tbl = kmalloc(sizeof(struct iommu_table), GFP_KERNEL); + + iommu_table_setparms(pci->phb, dn, tbl); + pci->iommu_table = iommu_init_table(tbl); + + /* Divide the rest (1.75GB) among the children */ + pci->phb->dma_window_size = 0x80000000ul; + while (pci->phb->dma_window_size * children > 0x70000000ul) + pci->phb->dma_window_size >>= 1; + + DBG("ISA/IDE, window size is 0x%lx\n", pci->phb->dma_window_size); + } @@ -446,21 +441,36 @@ static void iommu_bus_setup_pSeriesLP(struct pci_bus *bus) static void iommu_dev_setup_pSeries(struct pci_dev *dev) { struct device_node *dn, *mydn; + struct iommu_table *tbl; + + DBG("iommu_dev_setup_pSeries, dev %p (%s)\n", dev, pci_name(dev)); - DBG("iommu_dev_setup_pSeries, dev %p (%s)\n", dev, dev->pretty_name); - /* Now copy the iommu_table ptr from the bus device down to the - * pci device_node. This means get_iommu_table() won't need to search - * up the device tree to find it. - */ mydn = dn = pci_device_to_OF_node(dev); + /* If we're the direct child of a root bus, then we need to allocate + * an iommu table ourselves. The bus setup code should have setup + * the window sizes already. + */ + if (!dev->bus->self) { + DBG(" --> first child, no bridge. Allocating iommu table.\n"); + tbl = kmalloc(sizeof(struct iommu_table), GFP_KERNEL); + iommu_table_setparms(PCI_DN(dn)->phb, dn, tbl); + PCI_DN(mydn)->iommu_table = iommu_init_table(tbl); + + return; + } + + /* If this device is further down the bus tree, search upwards until + * an already allocated iommu table is found and use that. + */ + while (dn && dn->data && PCI_DN(dn)->iommu_table == NULL) dn = dn->parent; if (dn && dn->data) { PCI_DN(mydn)->iommu_table = PCI_DN(dn)->iommu_table; } else { - DBG("iommu_dev_setup_pSeries, dev %p (%s) has no iommu table\n", dev, dev->pretty_name); + DBG("iommu_dev_setup_pSeries, dev %p (%s) has no iommu table\n", dev, pci_name(dev)); } } @@ -494,7 +504,7 @@ static void iommu_dev_setup_pSeriesLP(struct pci_dev *dev) int *dma_window = NULL; struct pci_dn *pci; - DBG("iommu_dev_setup_pSeriesLP, dev %p (%s)\n", dev, dev->pretty_name); + DBG("iommu_dev_setup_pSeriesLP, dev %p (%s)\n", dev, pci_name(dev)); /* dev setup for LPAR is a little tricky, since the device tree might * contain the dma-window properties per-device and not neccesarily @@ -516,9 +526,8 @@ static void iommu_dev_setup_pSeriesLP(struct pci_dev *dev) * slots on POWER4 machines. */ if (dma_window == NULL || pdn->parent == NULL) { - /* Fall back to regular (non-LPAR) dev setup */ - DBG("No dma window for device, falling back to regular setup\n"); - iommu_dev_setup_pSeries(dev); + DBG("No dma window for device, linking to parent\n"); + PCI_DN(dn)->iommu_table = PCI_DN(pdn)->iommu_table; return; } else { DBG("Found DMA window, allocating table\n"); diff --git a/arch/ppc64/kernel/pSeries_setup.c b/arch/ppc64/kernel/pSeries_setup.c index bfadccc..3009701 100644 --- a/arch/ppc64/kernel/pSeries_setup.c +++ b/arch/ppc64/kernel/pSeries_setup.c @@ -238,8 +238,8 @@ static void __init pSeries_setup_arch(void) /* Find and initialize PCI host bridges */ init_pci_config_tokens(); - eeh_init(); find_and_init_phbs(); + eeh_init(); #ifdef CONFIG_DUMMY_CONSOLE conswitchp = &dummy_con; diff --git a/arch/ppc64/kernel/pci.c b/arch/ppc64/kernel/pci.c index 861138a..ff4be1d 100644 --- a/arch/ppc64/kernel/pci.c +++ b/arch/ppc64/kernel/pci.c @@ -246,11 +246,14 @@ static unsigned int pci_parse_of_flags(u32 addr0) unsigned int flags = 0; if (addr0 & 0x02000000) { - flags |= IORESOURCE_MEM; + 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; + flags |= IORESOURCE_PREFETCH + | PCI_BASE_ADDRESS_MEM_PREFETCH; } else if (addr0 & 0x01000000) - flags |= IORESOURCE_IO; + flags = IORESOURCE_IO | PCI_BASE_ADDRESS_SPACE_IO; return flags; } diff --git a/arch/ppc64/kernel/pmac_setup.c b/arch/ppc64/kernel/pmac_setup.c index 325426c..2575525 100644 --- a/arch/ppc64/kernel/pmac_setup.c +++ b/arch/ppc64/kernel/pmac_setup.c @@ -434,15 +434,23 @@ static int pmac_check_legacy_ioport(unsigned int baseport) static int __init pmac_declare_of_platform_devices(void) { - struct device_node *np; + struct device_node *np, *npp; - np = find_devices("u3"); - if (np) { - for (np = np->child; np != NULL; np = np->sibling) + npp = of_find_node_by_name(NULL, "u3"); + if (npp) { + for (np = NULL; (np = of_get_next_child(npp, np)) != NULL;) { if (strncmp(np->name, "i2c", 3) == 0) { - of_platform_device_create(np, "u3-i2c"); + of_platform_device_create(np, "u3-i2c", NULL); + of_node_put(np); break; } + } + of_node_put(npp); + } + npp = of_find_node_by_type(NULL, "smu"); + if (npp) { + of_platform_device_create(npp, "smu", NULL); + of_node_put(npp); } return 0; diff --git a/arch/ppc64/kernel/pmac_time.c b/arch/ppc64/kernel/pmac_time.c index 3059edb..41bbb8c 100644 --- a/arch/ppc64/kernel/pmac_time.c +++ b/arch/ppc64/kernel/pmac_time.c @@ -84,7 +84,7 @@ void __pmac pmac_get_rtc_time(struct rtc_time *tm) #ifdef CONFIG_PMAC_SMU case SYS_CTRLER_SMU: - smu_get_rtc_time(tm); + smu_get_rtc_time(tm, 1); break; #endif /* CONFIG_PMAC_SMU */ default: @@ -128,7 +128,7 @@ int __pmac pmac_set_rtc_time(struct rtc_time *tm) #ifdef CONFIG_PMAC_SMU case SYS_CTRLER_SMU: - return smu_set_rtc_time(tm); + return smu_set_rtc_time(tm, 1); #endif /* CONFIG_PMAC_SMU */ default: return -ENODEV; diff --git a/arch/ppc64/kernel/prom_init.c b/arch/ppc64/kernel/prom_init.c index 9979919..f252670 100644 --- a/arch/ppc64/kernel/prom_init.c +++ b/arch/ppc64/kernel/prom_init.c @@ -1711,6 +1711,7 @@ static void __init flatten_device_tree(void) unsigned long offset = reloc_offset(); unsigned long mem_start, mem_end, room; struct boot_param_header *hdr; + struct prom_t *_prom = PTRRELOC(&prom); char *namep; u64 *rsvmap; @@ -1765,6 +1766,7 @@ static void __init flatten_device_tree(void) RELOC(dt_struct_end) = PAGE_ALIGN(mem_start); /* Finish header */ + hdr->boot_cpuid_phys = _prom->cpu; hdr->magic = OF_DT_HEADER; hdr->totalsize = RELOC(dt_struct_end) - RELOC(dt_header_start); hdr->off_dt_struct = RELOC(dt_struct_start) - RELOC(dt_header_start); @@ -1854,7 +1856,6 @@ static void __init prom_find_boot_cpu(void) cpu_pkg = call_prom("instance-to-package", 1, 1, prom_cpu); - prom_setprop(cpu_pkg, "linux,boot-cpu", NULL, 0); prom_getprop(cpu_pkg, "reg", &getprop_rval, sizeof(getprop_rval)); _prom->cpu = getprop_rval; diff --git a/arch/ppc64/kernel/ptrace.c b/arch/ppc64/kernel/ptrace.c index 85ed318..b1c044c 100644 --- a/arch/ppc64/kernel/ptrace.c +++ b/arch/ppc64/kernel/ptrace.c @@ -219,6 +219,7 @@ int sys_ptrace(long request, long pid, long addr, long data) case PTRACE_SET_DEBUGREG: ret = ptrace_set_debugreg(child, addr, data); + break; case PTRACE_DETACH: ret = ptrace_detach(child, data); diff --git a/arch/ppc64/kernel/vdso.c b/arch/ppc64/kernel/vdso.c index 4777676..efa985f 100644 --- a/arch/ppc64/kernel/vdso.c +++ b/arch/ppc64/kernel/vdso.c @@ -224,10 +224,7 @@ int arch_setup_additional_pages(struct linux_binprm *bprm, int executable_stack) vma = kmem_cache_alloc(vm_area_cachep, SLAB_KERNEL); if (vma == NULL) return -ENOMEM; - if (security_vm_enough_memory(vdso_pages)) { - kmem_cache_free(vm_area_cachep, vma); - return -ENOMEM; - } + memset(vma, 0, sizeof(*vma)); /* @@ -237,8 +234,10 @@ int arch_setup_additional_pages(struct linux_binprm *bprm, int executable_stack) */ vdso_base = get_unmapped_area(NULL, vdso_base, vdso_pages << PAGE_SHIFT, 0, 0); - if (vdso_base & ~PAGE_MASK) + if (vdso_base & ~PAGE_MASK) { + kmem_cache_free(vm_area_cachep, vma); return (int)vdso_base; + } current->thread.vdso_base = vdso_base; @@ -266,7 +265,11 @@ int arch_setup_additional_pages(struct linux_binprm *bprm, int executable_stack) vma->vm_ops = &vdso_vmops; down_write(&mm->mmap_sem); - insert_vm_struct(mm, vma); + if (insert_vm_struct(mm, vma)) { + up_write(&mm->mmap_sem); + kmem_cache_free(vm_area_cachep, vma); + return -ENOMEM; + } mm->total_vm += (vma->vm_end - vma->vm_start) >> PAGE_SHIFT; up_write(&mm->mmap_sem); diff --git a/arch/ppc64/lib/Makefile b/arch/ppc64/lib/Makefile index 76fbfa9..0b6e967 100644 --- a/arch/ppc64/lib/Makefile +++ b/arch/ppc64/lib/Makefile @@ -2,7 +2,7 @@ # Makefile for ppc64-specific library files.. # -lib-y := checksum.o dec_and_lock.o string.o strcase.o +lib-y := checksum.o string.o strcase.o lib-y += copypage.o memcpy.o copyuser.o usercopy.o # Lock primitives are defined as no-ops in include/linux/spinlock.h diff --git a/arch/ppc64/lib/dec_and_lock.c b/arch/ppc64/lib/dec_and_lock.c deleted file mode 100644 index 7b9d4da..0000000 --- a/arch/ppc64/lib/dec_and_lock.c +++ /dev/null @@ -1,47 +0,0 @@ -/* - * ppc64 version of atomic_dec_and_lock() using cmpxchg - * - * This 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 <linux/module.h> -#include <linux/spinlock.h> -#include <asm/atomic.h> -#include <asm/system.h> - -/* - * This is an implementation of the notion of "decrement a - * reference count, and return locked if it decremented to zero". - * - * This implementation can be used on any architecture that - * has a cmpxchg, and where atomic->value is an int holding - * the value of the atomic (i.e. the high bits aren't used - * for a lock or anything like that). - */ -int _atomic_dec_and_lock(atomic_t *atomic, spinlock_t *lock) -{ - int counter; - int newcount; - - for (;;) { - counter = atomic_read(atomic); - newcount = counter - 1; - if (!newcount) - break; /* do it the slow way */ - - newcount = cmpxchg(&atomic->counter, counter, newcount); - if (newcount == counter) - return 0; - } - - spin_lock(lock); - if (atomic_dec_and_test(atomic)) - return 1; - spin_unlock(lock); - return 0; -} - -EXPORT_SYMBOL(_atomic_dec_and_lock); diff --git a/arch/ppc64/mm/fault.c b/arch/ppc64/mm/fault.c index 7fbc68b..be3f25c 100644 --- a/arch/ppc64/mm/fault.c +++ b/arch/ppc64/mm/fault.c @@ -38,6 +38,7 @@ #include <asm/system.h> #include <asm/uaccess.h> #include <asm/kdebug.h> +#include <asm/siginfo.h> /* * Check whether the instruction at regs->nip is a store using diff --git a/arch/ppc64/mm/hash_native.c b/arch/ppc64/mm/hash_native.c index 7626bb5..eb1bbb5 100644 --- a/arch/ppc64/mm/hash_native.c +++ b/arch/ppc64/mm/hash_native.c @@ -343,9 +343,7 @@ static void native_flush_hash_range(unsigned long context, hpte_t *hptep; unsigned long hpte_v; struct ppc64_tlb_batch *batch = &__get_cpu_var(ppc64_tlb_batch); - - /* XXX fix for large ptes */ - unsigned long large = 0; + unsigned long large; local_irq_save(flags); @@ -358,6 +356,7 @@ static void native_flush_hash_range(unsigned long context, va = (vsid << 28) | (batch->addr[i] & 0x0fffffff); batch->vaddr[j] = va; + large = pte_huge(batch->pte[i]); if (large) vpn = va >> HPAGE_SHIFT; else diff --git a/arch/ppc64/mm/hugetlbpage.c b/arch/ppc64/mm/hugetlbpage.c index 338771e..0ea0994 100644 --- a/arch/ppc64/mm/hugetlbpage.c +++ b/arch/ppc64/mm/hugetlbpage.c @@ -710,10 +710,13 @@ repeat: hpte_group = ((~hash & htab_hash_mask) * HPTES_PER_GROUP) & ~0x7UL; slot = ppc_md.hpte_insert(hpte_group, va, prpn, - HPTE_V_LARGE, rflags); + HPTE_V_LARGE | + HPTE_V_SECONDARY, + rflags); if (slot == -1) { if (mftb() & 0x1) - hpte_group = ((hash & htab_hash_mask) * HPTES_PER_GROUP) & ~0x7UL; + hpte_group = ((hash & htab_hash_mask) * + HPTES_PER_GROUP)&~0x7UL; ppc_md.hpte_remove(hpte_group); goto repeat; diff --git a/arch/s390/defconfig b/arch/s390/defconfig index 0865251..45d44c6 100644 --- a/arch/s390/defconfig +++ b/arch/s390/defconfig @@ -1,7 +1,7 @@ # # Automatically generated make config: don't edit -# Linux kernel version: 2.6.13-rc4 -# Fri Jul 29 14:49:30 2005 +# Linux kernel version: 2.6.14-rc1 +# Wed Sep 14 16:46:19 2005 # CONFIG_MMU=y CONFIG_RWSEM_XCHGADD_ALGORITHM=y @@ -21,6 +21,7 @@ CONFIG_INIT_ENV_ARG_LIMIT=32 # General setup # CONFIG_LOCALVERSION="" +CONFIG_LOCALVERSION_AUTO=y CONFIG_SWAP=y CONFIG_SYSVIPC=y CONFIG_POSIX_MQUEUE=y @@ -33,6 +34,7 @@ CONFIG_KOBJECT_UEVENT=y CONFIG_IKCONFIG=y CONFIG_IKCONFIG_PROC=y # CONFIG_CPUSETS is not set +CONFIG_INITRAMFS_SOURCE="" # CONFIG_EMBEDDED is not set CONFIG_KALLSYMS=y # CONFIG_KALLSYMS_ALL is not set @@ -94,6 +96,7 @@ CONFIG_FLATMEM_MANUAL=y # CONFIG_SPARSEMEM_MANUAL is not set CONFIG_FLATMEM=y CONFIG_FLAT_NODE_MEM_MAP=y +# CONFIG_SPARSEMEM_STATIC is not set # # I/O subsystem configuration @@ -151,8 +154,8 @@ CONFIG_IP_FIB_HASH=y # CONFIG_INET_ESP is not set # CONFIG_INET_IPCOMP is not set # CONFIG_INET_TUNNEL is not set -CONFIG_IP_TCPDIAG=y -CONFIG_IP_TCPDIAG_IPV6=y +CONFIG_INET_DIAG=y +CONFIG_INET_TCP_DIAG=y # CONFIG_TCP_CONG_ADVANCED is not set CONFIG_TCP_CONG_BIC=y CONFIG_IPV6=y @@ -165,6 +168,11 @@ CONFIG_IPV6=y # CONFIG_NETFILTER is not set # +# DCCP Configuration (EXPERIMENTAL) +# +# CONFIG_IP_DCCP is not set + +# # SCTP Configuration (EXPERIMENTAL) # # CONFIG_IP_SCTP is not set @@ -217,9 +225,11 @@ CONFIG_NET_CLS_POLICE=y # Network testing # # CONFIG_NET_PKTGEN is not set +# CONFIG_NETFILTER_NETLINK is not set # CONFIG_HAMRADIO is not set # CONFIG_IRDA is not set # CONFIG_BT is not set +# CONFIG_IEEE80211 is not set # CONFIG_PCMCIA is not set # @@ -233,6 +243,7 @@ CONFIG_PREVENT_FIRMWARE_BUILD=y # # SCSI device support # +# CONFIG_RAID_ATTRS is not set CONFIG_SCSI=y CONFIG_SCSI_PROC_FS=y @@ -260,6 +271,7 @@ CONFIG_SCSI_LOGGING=y # CONFIG_SCSI_SPI_ATTRS is not set CONFIG_SCSI_FC_ATTRS=y # CONFIG_SCSI_ISCSI_ATTRS is not set +# CONFIG_SCSI_SAS_ATTRS is not set # # SCSI low-level drivers @@ -280,7 +292,6 @@ CONFIG_BLK_DEV_RAM=y CONFIG_BLK_DEV_RAM_COUNT=16 CONFIG_BLK_DEV_RAM_SIZE=4096 CONFIG_BLK_DEV_INITRD=y -CONFIG_INITRAMFS_SOURCE="" # CONFIG_LBD is not set # CONFIG_CDROM_PKTCDVD is not set @@ -384,6 +395,10 @@ CONFIG_EQUALIZER=m CONFIG_TUN=m # +# PHY device support +# + +# # Ethernet (10 or 100Mbit) # CONFIG_NET_ETHERNET=y @@ -453,10 +468,6 @@ CONFIG_FS_MBCACHE=y # CONFIG_REISERFS_FS is not set # CONFIG_JFS_FS is not set # CONFIG_FS_POSIX_ACL is not set - -# -# XFS support -# # CONFIG_XFS_FS is not set # CONFIG_MINIX_FS is not set # CONFIG_ROMFS_FS is not set @@ -465,6 +476,7 @@ CONFIG_INOTIFY=y 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 @@ -485,11 +497,10 @@ CONFIG_DNOTIFY=y CONFIG_PROC_FS=y CONFIG_PROC_KCORE=y CONFIG_SYSFS=y -# CONFIG_DEVPTS_FS_XATTR is not set CONFIG_TMPFS=y -# CONFIG_TMPFS_XATTR is not set # CONFIG_HUGETLB_PAGE is not set CONFIG_RAMFS=y +# CONFIG_RELAYFS_FS is not set # # Miscellaneous filesystems @@ -533,6 +544,7 @@ CONFIG_SUNRPC=y # 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 @@ -572,6 +584,7 @@ CONFIG_MSDOS_PARTITION=y CONFIG_DEBUG_KERNEL=y CONFIG_MAGIC_SYSRQ=y CONFIG_LOG_BUF_SHIFT=17 +CONFIG_DETECT_SOFTLOCKUP=y # CONFIG_SCHEDSTATS is not set # CONFIG_DEBUG_SLAB is not set CONFIG_DEBUG_PREEMPT=y @@ -626,5 +639,6 @@ CONFIG_CRYPTO=y # Library routines # # CONFIG_CRC_CCITT is not set +# CONFIG_CRC16 is not set CONFIG_CRC32=m # CONFIG_LIBCRC32C is not set diff --git a/arch/s390/kernel/Makefile b/arch/s390/kernel/Makefile index ab1e49d2..8584dd8 100644 --- a/arch/s390/kernel/Makefile +++ b/arch/s390/kernel/Makefile @@ -6,7 +6,7 @@ EXTRA_AFLAGS := -traditional obj-y := bitmap.o traps.o time.o process.o \ setup.o sys_s390.o ptrace.o signal.o cpcmd.o ebcdic.o \ - semaphore.o s390_ext.o debug.o profile.o irq.o + semaphore.o s390_ext.o debug.o profile.o irq.o reipl_diag.o extra-$(CONFIG_ARCH_S390_31) += head.o extra-$(CONFIG_ARCH_S390X) += head64.o diff --git a/arch/s390/kernel/entry.S b/arch/s390/kernel/entry.S index 58fc7fb..9b30f4c 100644 --- a/arch/s390/kernel/entry.S +++ b/arch/s390/kernel/entry.S @@ -108,7 +108,7 @@ STACK_SIZE = 1 << STACK_SHIFT bl BASED(0f) l %r14,BASED(.Lcleanup_critical) basr %r14,%r14 - tm 0(%r12),0x01 # retest problem state after cleanup + tm 1(%r12),0x01 # retest problem state after cleanup bnz BASED(1f) 0: l %r14,__LC_ASYNC_STACK # are we already on the async stack ? slr %r14,%r15 diff --git a/arch/s390/kernel/entry64.S b/arch/s390/kernel/entry64.S index d0c9ffa..7b9b4a2 100644 --- a/arch/s390/kernel/entry64.S +++ b/arch/s390/kernel/entry64.S @@ -101,7 +101,7 @@ _TIF_WORK_INT = (_TIF_SIGPENDING | _TIF_NEED_RESCHED | _TIF_MCCK_PENDING) clc \psworg+8(8),BASED(.Lcritical_start) jl 0f brasl %r14,cleanup_critical - tm 0(%r12),0x01 # retest problem state after cleanup + tm 1(%r12),0x01 # retest problem state after cleanup jnz 1f 0: lg %r14,__LC_ASYNC_STACK # are we already on the async. stack ? slgr %r14,%r15 diff --git a/arch/s390/kernel/reipl_diag.c b/arch/s390/kernel/reipl_diag.c new file mode 100644 index 0000000..83cb42b --- /dev/null +++ b/arch/s390/kernel/reipl_diag.c @@ -0,0 +1,39 @@ +/* + * This file contains the implementation of the + * Linux re-IPL support + * + * (C) Copyright IBM Corp. 2005 + * + * Author(s): Volker Sameske (sameske@de.ibm.com) + * + */ + +#include <linux/kernel.h> + +static unsigned int reipl_diag_rc1; +static unsigned int reipl_diag_rc2; + +/* + * re-IPL the system using the last used IPL parameters + */ +void reipl_diag(void) +{ + asm volatile ( + " la %%r4,0\n" + " la %%r5,0\n" + " diag %%r4,%2,0x308\n" + "0:\n" + " st %%r4,%0\n" + " st %%r5,%1\n" + ".section __ex_table,\"a\"\n" +#ifdef __s390x__ + " .align 8\n" + " .quad 0b, 0b\n" +#else + " .align 4\n" + " .long 0b, 0b\n" +#endif + ".previous\n" + : "=m" (reipl_diag_rc1), "=m" (reipl_diag_rc2) + : "d" (3) : "cc", "4", "5" ); +} diff --git a/arch/s390/kernel/setup.c b/arch/s390/kernel/setup.c index 5ba5a54..5204778 100644 --- a/arch/s390/kernel/setup.c +++ b/arch/s390/kernel/setup.c @@ -261,8 +261,11 @@ void (*_machine_power_off)(void) = machine_power_off_smp; * Reboot, halt and power_off routines for non SMP. */ extern void reipl(unsigned long devno); +extern void reipl_diag(void); static void do_machine_restart_nonsmp(char * __unused) { + reipl_diag(); + if (MACHINE_IS_VM) cpcmd ("IPL", NULL, 0); else @@ -634,6 +637,7 @@ static int show_cpuinfo(struct seq_file *m, void *v) struct cpuinfo_S390 *cpuinfo; unsigned long n = (unsigned long) v - 1; + preempt_disable(); if (!n) { seq_printf(m, "vendor_id : IBM/S390\n" "# processors : %i\n" @@ -658,6 +662,7 @@ static int show_cpuinfo(struct seq_file *m, void *v) cpuinfo->cpu_id.ident, cpuinfo->cpu_id.machine); } + preempt_enable(); return 0; } diff --git a/arch/s390/kernel/smp.c b/arch/s390/kernel/smp.c index 85222fe..e13c87b 100644 --- a/arch/s390/kernel/smp.c +++ b/arch/s390/kernel/smp.c @@ -65,6 +65,7 @@ extern char vmhalt_cmd[]; extern char vmpoff_cmd[]; extern void reipl(unsigned long devno); +extern void reipl_diag(void); static void smp_ext_bitcall(int, ec_bit_sig); static void smp_ext_bitcall_others(ec_bit_sig); @@ -283,6 +284,8 @@ static void do_machine_restart(void * __unused) * interrupted by an external interrupt and s390irq * locks are always held disabled). */ + reipl_diag(); + if (MACHINE_IS_VM) cpcmd ("IPL", NULL, 0, NULL); else diff --git a/arch/sparc64/Kconfig.debug b/arch/sparc64/Kconfig.debug index cd8d39fb..af0e941 100644 --- a/arch/sparc64/Kconfig.debug +++ b/arch/sparc64/Kconfig.debug @@ -33,14 +33,6 @@ config DEBUG_BOOTMEM depends on DEBUG_KERNEL bool "Debug BOOTMEM initialization" -# We have a custom atomic_dec_and_lock() implementation but it's not -# compatible with spinlock debugging so we need to fall back on -# the generic version in that case. -config HAVE_DEC_LOCK - bool - depends on SMP && !DEBUG_SPINLOCK - default y - config MCOUNT bool depends on STACK_DEBUG diff --git a/arch/sparc64/kernel/entry.S b/arch/sparc64/kernel/entry.S index 3e0badb..b483495 100644 --- a/arch/sparc64/kernel/entry.S +++ b/arch/sparc64/kernel/entry.S @@ -42,19 +42,15 @@ * executing (see inherit_locked_prom_mappings() rant). */ sparc64_vpte_nucleus: - /* Load 0xf0000000, which is LOW_OBP_ADDRESS. */ - mov 0xf, %g5 - sllx %g5, 28, %g5 - - /* Is addr >= LOW_OBP_ADDRESS? */ + /* Note that kvmap below has verified that the address is + * in the range MODULES_VADDR --> VMALLOC_END already. So + * here we need only check if it is an OBP address or not. + */ + sethi %hi(LOW_OBP_ADDRESS), %g5 cmp %g4, %g5 blu,pn %xcc, sparc64_vpte_patchme1 mov 0x1, %g5 - - /* Load 0x100000000, which is HI_OBP_ADDRESS. */ sllx %g5, 32, %g5 - - /* Is addr < HI_OBP_ADDRESS? */ cmp %g4, %g5 blu,pn %xcc, obp_iaddr_patch nop @@ -156,26 +152,29 @@ obp_daddr_patch: * rather, use information saved during inherit_prom_mappings() using 8k * pagesize. */ + .align 32 kvmap: - /* Load 0xf0000000, which is LOW_OBP_ADDRESS. */ - mov 0xf, %g5 - sllx %g5, 28, %g5 + sethi %hi(MODULES_VADDR), %g5 + cmp %g4, %g5 + blu,pn %xcc, longpath + mov (VMALLOC_END >> 24), %g5 + sllx %g5, 24, %g5 + cmp %g4, %g5 + bgeu,pn %xcc, longpath + nop - /* Is addr >= LOW_OBP_ADDRESS? */ +kvmap_check_obp: + sethi %hi(LOW_OBP_ADDRESS), %g5 cmp %g4, %g5 - blu,pn %xcc, vmalloc_addr + blu,pn %xcc, kvmap_vmalloc_addr mov 0x1, %g5 - - /* Load 0x100000000, which is HI_OBP_ADDRESS. */ sllx %g5, 32, %g5 - - /* Is addr < HI_OBP_ADDRESS? */ cmp %g4, %g5 blu,pn %xcc, obp_daddr_patch nop -vmalloc_addr: - /* If we get here, a vmalloc addr accessed, load kernel VPTE. */ +kvmap_vmalloc_addr: + /* If we get here, a vmalloc addr was accessed, load kernel VPTE. */ ldxa [%g3 + %g6] ASI_N, %g5 brgez,pn %g5, longpath nop diff --git a/arch/sparc64/kernel/ptrace.c b/arch/sparc64/kernel/ptrace.c index 23ad839..5efbff9 100644 --- a/arch/sparc64/kernel/ptrace.c +++ b/arch/sparc64/kernel/ptrace.c @@ -30,6 +30,7 @@ #include <asm/psrcompat.h> #include <asm/visasm.h> #include <asm/spitfire.h> +#include <asm/page.h> /* Returning from ptrace is a bit tricky because the syscall return * low level code assumes any value returned which is negative and @@ -128,20 +129,20 @@ void flush_ptrace_access(struct vm_area_struct *vma, struct page *page, * is mapped to in the user's address space, we can skip the * D-cache flush. */ - if ((uaddr ^ kaddr) & (1UL << 13)) { + if ((uaddr ^ (unsigned long) kaddr) & (1UL << 13)) { unsigned long start = __pa(kaddr); unsigned long end = start + len; if (tlb_type == spitfire) { for (; start < end; start += 32) - spitfire_put_dcache_tag(va & 0x3fe0, 0x0); + spitfire_put_dcache_tag(start & 0x3fe0, 0x0); } else { for (; start < end; start += 32) __asm__ __volatile__( "stxa %%g0, [%0] %1\n\t" "membar #Sync" : /* no outputs */ - : "r" (va), + : "r" (start), "i" (ASI_DCACHE_INVALIDATE)); } } diff --git a/arch/sparc64/kernel/sparc64_ksyms.c b/arch/sparc64/kernel/sparc64_ksyms.c index cbb5e59..fb7a537 100644 --- a/arch/sparc64/kernel/sparc64_ksyms.c +++ b/arch/sparc64/kernel/sparc64_ksyms.c @@ -163,9 +163,6 @@ EXPORT_SYMBOL(atomic64_add); EXPORT_SYMBOL(atomic64_add_ret); EXPORT_SYMBOL(atomic64_sub); EXPORT_SYMBOL(atomic64_sub_ret); -#ifdef CONFIG_SMP -EXPORT_SYMBOL(_atomic_dec_and_lock); -#endif /* Atomic bit operations. */ EXPORT_SYMBOL(test_and_set_bit); diff --git a/arch/sparc64/kernel/una_asm.S b/arch/sparc64/kernel/una_asm.S index cbb4058..da48400 100644 --- a/arch/sparc64/kernel/una_asm.S +++ b/arch/sparc64/kernel/una_asm.S @@ -17,7 +17,7 @@ kernel_unaligned_trap_fault: __do_int_store: rd %asi, %o4 wr %o3, 0, %asi - ldx [%o2], %g3 + mov %o2, %g3 cmp %o1, 2 be,pn %icc, 2f cmp %o1, 4 diff --git a/arch/sparc64/kernel/unaligned.c b/arch/sparc64/kernel/unaligned.c index da9739f..42718f6 100644 --- a/arch/sparc64/kernel/unaligned.c +++ b/arch/sparc64/kernel/unaligned.c @@ -184,13 +184,14 @@ extern void do_int_load(unsigned long *dest_reg, int size, unsigned long *saddr, int is_signed, int asi); extern void __do_int_store(unsigned long *dst_addr, int size, - unsigned long *src_val, int asi); + unsigned long src_val, int asi); static inline void do_int_store(int reg_num, int size, unsigned long *dst_addr, - struct pt_regs *regs, int asi) + struct pt_regs *regs, int asi, int orig_asi) { unsigned long zero = 0; - unsigned long *src_val = &zero; + unsigned long *src_val_p = &zero; + unsigned long src_val; if (size == 16) { size = 8; @@ -198,7 +199,25 @@ static inline void do_int_store(int reg_num, int size, unsigned long *dst_addr, (unsigned)fetch_reg(reg_num, regs) : 0)) << 32) | (unsigned)fetch_reg(reg_num + 1, regs); } else if (reg_num) { - src_val = fetch_reg_addr(reg_num, regs); + src_val_p = fetch_reg_addr(reg_num, regs); + } + src_val = *src_val_p; + if (unlikely(asi != orig_asi)) { + switch (size) { + case 2: + src_val = swab16(src_val); + break; + case 4: + src_val = swab32(src_val); + break; + case 8: + src_val = swab64(src_val); + break; + case 16: + default: + BUG(); + break; + }; } __do_int_store(dst_addr, size, src_val, asi); } @@ -276,6 +295,7 @@ asmlinkage void kernel_unaligned_trap(struct pt_regs *regs, unsigned int insn, u kernel_mna_trap_fault(); } else { unsigned long addr; + int orig_asi, asi; addr = compute_effective_address(regs, insn, ((insn >> 25) & 0x1f)); @@ -285,18 +305,48 @@ asmlinkage void kernel_unaligned_trap(struct pt_regs *regs, unsigned int insn, u regs->tpc, dirstrings[dir], addr, size, regs->u_regs[UREG_RETPC]); #endif + orig_asi = asi = decode_asi(insn, regs); + switch (asi) { + case ASI_NL: + case ASI_AIUPL: + case ASI_AIUSL: + case ASI_PL: + case ASI_SL: + case ASI_PNFL: + case ASI_SNFL: + asi &= ~0x08; + break; + }; switch (dir) { case load: do_int_load(fetch_reg_addr(((insn>>25)&0x1f), regs), size, (unsigned long *) addr, - decode_signedness(insn), - decode_asi(insn, regs)); + decode_signedness(insn), asi); + if (unlikely(asi != orig_asi)) { + unsigned long val_in = *(unsigned long *) addr; + switch (size) { + case 2: + val_in = swab16(val_in); + break; + case 4: + val_in = swab32(val_in); + break; + case 8: + val_in = swab64(val_in); + break; + case 16: + default: + BUG(); + break; + }; + *(unsigned long *) addr = val_in; + } break; case store: do_int_store(((insn>>25)&0x1f), size, (unsigned long *) addr, regs, - decode_asi(insn, regs)); + asi, orig_asi); break; default: diff --git a/arch/sparc64/lib/Makefile b/arch/sparc64/lib/Makefile index d968aeb..c295806 100644 --- a/arch/sparc64/lib/Makefile +++ b/arch/sparc64/lib/Makefile @@ -14,6 +14,4 @@ lib-y := PeeCeeI.o copy_page.o clear_page.o strlen.o strncmp.o \ copy_in_user.o user_fixup.o memmove.o \ mcount.o ipcsum.o rwsem.o xor.o find_bit.o delay.o -lib-$(CONFIG_HAVE_DEC_LOCK) += dec_and_lock.o - obj-y += iomap.o diff --git a/arch/sparc64/lib/dec_and_lock.S b/arch/sparc64/lib/dec_and_lock.S deleted file mode 100644 index 8ee288d..0000000 --- a/arch/sparc64/lib/dec_and_lock.S +++ /dev/null @@ -1,80 +0,0 @@ -/* $Id: dec_and_lock.S,v 1.5 2001/11/18 00:12:56 davem Exp $ - * dec_and_lock.S: Sparc64 version of "atomic_dec_and_lock()" - * using cas and ldstub instructions. - * - * Copyright (C) 2000 David S. Miller (davem@redhat.com) - */ -#include <linux/config.h> -#include <asm/thread_info.h> - - .text - .align 64 - - /* CAS basically works like this: - * - * void CAS(MEM, REG1, REG2) - * { - * START_ATOMIC(); - * if (*(MEM) == REG1) { - * TMP = *(MEM); - * *(MEM) = REG2; - * REG2 = TMP; - * } else - * REG2 = *(MEM); - * END_ATOMIC(); - * } - */ - - .globl _atomic_dec_and_lock -_atomic_dec_and_lock: /* %o0 = counter, %o1 = lock */ -loop1: lduw [%o0], %g2 - subcc %g2, 1, %g7 - be,pn %icc, start_to_zero - nop -nzero: cas [%o0], %g2, %g7 - cmp %g2, %g7 - bne,pn %icc, loop1 - mov 0, %g1 - -out: - membar #StoreLoad | #StoreStore - retl - mov %g1, %o0 -start_to_zero: -#ifdef CONFIG_PREEMPT - ldsw [%g6 + TI_PRE_COUNT], %g3 - add %g3, 1, %g3 - stw %g3, [%g6 + TI_PRE_COUNT] -#endif -to_zero: - ldstub [%o1], %g3 - membar #StoreLoad | #StoreStore - brnz,pn %g3, spin_on_lock - nop -loop2: cas [%o0], %g2, %g7 /* ASSERT(g7 == 0) */ - cmp %g2, %g7 - - be,pt %icc, out - mov 1, %g1 - lduw [%o0], %g2 - subcc %g2, 1, %g7 - be,pn %icc, loop2 - nop - membar #StoreStore | #LoadStore - stb %g0, [%o1] -#ifdef CONFIG_PREEMPT - ldsw [%g6 + TI_PRE_COUNT], %g3 - sub %g3, 1, %g3 - stw %g3, [%g6 + TI_PRE_COUNT] -#endif - - b,pt %xcc, nzero - nop -spin_on_lock: - ldub [%o1], %g3 - membar #LoadLoad - brnz,pt %g3, spin_on_lock - nop - ba,pt %xcc, to_zero - nop - nop diff --git a/arch/um/Kconfig.i386 b/arch/um/Kconfig.i386 index 8ad156a..5d92cac 100644 --- a/arch/um/Kconfig.i386 +++ b/arch/um/Kconfig.i386 @@ -42,3 +42,7 @@ config ARCH_HAS_SC_SIGNALS config ARCH_REUSE_HOST_VSYSCALL_AREA bool default y + +config X86_CMPXCHG + bool + default y diff --git a/arch/um/Makefile b/arch/um/Makefile index ce98726..5b5af95 100644 --- a/arch/um/Makefile +++ b/arch/um/Makefile @@ -53,9 +53,13 @@ SYS_DIR := $(ARCH_DIR)/include/sysdep-$(SUBARCH) # -Dvmap=kernel_vmap affects everything, and prevents anything from # referencing the libpcap.o symbol so named. +# +# Same things for in6addr_loopback - found in libc. CFLAGS += $(CFLAGS-y) -D__arch_um__ -DSUBARCH=\"$(SUBARCH)\" \ - $(ARCH_INCLUDE) $(MODE_INCLUDE) -Dvmap=kernel_vmap + $(ARCH_INCLUDE) $(MODE_INCLUDE) -Dvmap=kernel_vmap \ + -Din6addr_loopback=kernel_in6addr_loopback + AFLAGS += $(ARCH_INCLUDE) USER_CFLAGS := $(patsubst -I%,,$(CFLAGS)) diff --git a/arch/um/drivers/chan_kern.c b/arch/um/drivers/chan_kern.c index 14a12d6..16e7dc8 100644 --- a/arch/um/drivers/chan_kern.c +++ b/arch/um/drivers/chan_kern.c @@ -19,18 +19,44 @@ #include "line.h" #include "os.h" -#ifdef CONFIG_NOCONFIG_CHAN +/* XXX: could well be moved to somewhere else, if needed. */ +static int my_printf(const char * fmt, ...) + __attribute__ ((format (printf, 1, 2))); + +static int my_printf(const char * fmt, ...) +{ + /* Yes, can be called on atomic context.*/ + char *buf = kmalloc(4096, GFP_ATOMIC); + va_list args; + int r; + + if (!buf) { + /* We print directly fmt. + * Yes, yes, yes, feel free to complain. */ + r = strlen(fmt); + } else { + va_start(args, fmt); + r = vsprintf(buf, fmt, args); + va_end(args); + fmt = buf; + } -/* The printk's here are wrong because we are complaining that there is no - * output device, but printk is printing to that output device. The user will - * never see the error. printf would be better, except it can't run on a - * kernel stack because it will overflow it. - * Use printk for now since that will avoid crashing. - */ + if (r) + r = os_write_file(1, fmt, r); + return r; + +} + +#ifdef CONFIG_NOCONFIG_CHAN +/* Despite its name, there's no added trailing newline. */ +static int my_puts(const char * buf) +{ + return os_write_file(1, buf, strlen(buf)); +} static void *not_configged_init(char *str, int device, struct chan_opts *opts) { - printk(KERN_ERR "Using a channel type which is configured out of " + my_puts("Using a channel type which is configured out of " "UML\n"); return(NULL); } @@ -38,27 +64,27 @@ static void *not_configged_init(char *str, int device, struct chan_opts *opts) static int not_configged_open(int input, int output, int primary, void *data, char **dev_out) { - printk(KERN_ERR "Using a channel type which is configured out of " + my_puts("Using a channel type which is configured out of " "UML\n"); return(-ENODEV); } static void not_configged_close(int fd, void *data) { - printk(KERN_ERR "Using a channel type which is configured out of " + my_puts("Using a channel type which is configured out of " "UML\n"); } static int not_configged_read(int fd, char *c_out, void *data) { - printk(KERN_ERR "Using a channel type which is configured out of " + my_puts("Using a channel type which is configured out of " "UML\n"); return(-EIO); } static int not_configged_write(int fd, const char *buf, int len, void *data) { - printk(KERN_ERR "Using a channel type which is configured out of " + my_puts("Using a channel type which is configured out of " "UML\n"); return(-EIO); } @@ -66,7 +92,7 @@ static int not_configged_write(int fd, const char *buf, int len, void *data) static int not_configged_console_write(int fd, const char *buf, int len, void *data) { - printk(KERN_ERR "Using a channel type which is configured out of " + my_puts("Using a channel type which is configured out of " "UML\n"); return(-EIO); } @@ -74,14 +100,14 @@ static int not_configged_console_write(int fd, const char *buf, int len, static int not_configged_window_size(int fd, void *data, unsigned short *rows, unsigned short *cols) { - printk(KERN_ERR "Using a channel type which is configured out of " + my_puts("Using a channel type which is configured out of " "UML\n"); return(-ENODEV); } static void not_configged_free(void *data) { - printf(KERN_ERR "Using a channel type which is configured out of " + my_puts("Using a channel type which is configured out of " "UML\n"); } @@ -457,7 +483,7 @@ static struct chan *parse_chan(char *str, int pri, int device, } } if(ops == NULL){ - printk(KERN_ERR "parse_chan couldn't parse \"%s\"\n", + my_printf("parse_chan couldn't parse \"%s\"\n", str); return(NULL); } @@ -465,7 +491,7 @@ static struct chan *parse_chan(char *str, int pri, int device, data = (*ops->init)(str, device, opts); if(data == NULL) return(NULL); - chan = kmalloc(sizeof(*chan), GFP_KERNEL); + chan = kmalloc(sizeof(*chan), GFP_ATOMIC); if(chan == NULL) return(NULL); *chan = ((struct chan) { .list = LIST_HEAD_INIT(chan->list), .primary = 1, diff --git a/arch/um/drivers/mcast_user.c b/arch/um/drivers/mcast_user.c index 7a0d115..5db136e 100644 --- a/arch/um/drivers/mcast_user.c +++ b/arch/um/drivers/mcast_user.c @@ -13,7 +13,6 @@ #include <errno.h> #include <unistd.h> -#include <linux/inet.h> #include <sys/socket.h> #include <sys/un.h> #include <sys/time.h> @@ -55,7 +54,7 @@ static int mcast_open(void *data) struct mcast_data *pri = data; struct sockaddr_in *sin = pri->mcast_addr; struct ip_mreq mreq; - int fd = -EINVAL, yes = 1, err = -EINVAL;; + int fd, yes = 1, err = 0; if ((sin->sin_addr.s_addr == 0) || (sin->sin_port == 0)) @@ -66,13 +65,14 @@ static int mcast_open(void *data) if (fd < 0){ printk("mcast_open : data socket failed, errno = %d\n", errno); - fd = -errno; + err = -errno; goto out; } if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes)) < 0) { printk("mcast_open: SO_REUSEADDR failed, errno = %d\n", errno); + err = -errno; goto out_close; } @@ -81,6 +81,7 @@ static int mcast_open(void *data) sizeof(pri->ttl)) < 0) { printk("mcast_open: IP_MULTICAST_TTL failed, error = %d\n", errno); + err = -errno; goto out_close; } @@ -88,12 +89,14 @@ static int mcast_open(void *data) if (setsockopt(fd, SOL_IP, IP_MULTICAST_LOOP, &yes, sizeof(yes)) < 0) { printk("mcast_open: IP_MULTICAST_LOOP failed, error = %d\n", errno); + err = -errno; goto out_close; } /* bind socket to mcast address */ if (bind(fd, (struct sockaddr *) sin, sizeof(*sin)) < 0) { printk("mcast_open : data bind failed, errno = %d\n", errno); + err = -errno; goto out_close; } @@ -108,14 +111,15 @@ static int mcast_open(void *data) "interface on the host.\n"); printk("eth0 should be configured in order to use the " "multicast transport.\n"); + err = -errno; goto out_close; } - out: return fd; out_close: os_close_file(fd); + out: return err; } diff --git a/arch/um/drivers/mconsole_kern.c b/arch/um/drivers/mconsole_kern.c index c190c24..12c9536 100644 --- a/arch/um/drivers/mconsole_kern.c +++ b/arch/um/drivers/mconsole_kern.c @@ -32,6 +32,7 @@ #include "os.h" #include "umid.h" #include "irq_kern.h" +#include "choose-mode.h" static int do_unlink_socket(struct notifier_block *notifier, unsigned long what, void *data) @@ -276,6 +277,7 @@ void mconsole_proc(struct mc_request *req) go - continue the UML after a 'stop' \n\ log <string> - make UML enter <string> into the kernel log\n\ proc <file> - returns the contents of the UML's /proc/<file>\n\ + stack <pid> - returns the stack of the specified pid\n\ " void mconsole_help(struct mc_request *req) @@ -479,6 +481,56 @@ void mconsole_sysrq(struct mc_request *req) } #endif +/* Mconsole stack trace + * Added by Allan Graves, Jeff Dike + * Dumps a stacks registers to the linux console. + * Usage stack <pid>. + */ +void do_stack(struct mc_request *req) +{ + char *ptr = req->request.data; + int pid_requested= -1; + struct task_struct *from = NULL; + struct task_struct *to = NULL; + + /* Would be nice: + * 1) Send showregs output to mconsole. + * 2) Add a way to stack dump all pids. + */ + + ptr += strlen("stack"); + while(isspace(*ptr)) ptr++; + + /* Should really check for multiple pids or reject bad args here */ + /* What do the arguments in mconsole_reply mean? */ + if(sscanf(ptr, "%d", &pid_requested) == 0){ + mconsole_reply(req, "Please specify a pid", 1, 0); + return; + } + + from = current; + to = find_task_by_pid(pid_requested); + + if((to == NULL) || (pid_requested == 0)) { + mconsole_reply(req, "Couldn't find that pid", 1, 0); + return; + } + to->thread.saved_task = current; + + switch_to(from, to, from); + mconsole_reply(req, "Stack Dumped to console and message log", 0, 0); +} + +void mconsole_stack(struct mc_request *req) +{ + /* This command doesn't work in TT mode, so let's check and then + * get out of here + */ + CHOOSE_MODE(mconsole_reply(req, "Sorry, this doesn't work in TT mode", + 1, 0), + do_stack(req)); +} + /* Changed by mconsole_setup, which is __setup, and called before SMP is * active. */ diff --git a/arch/um/drivers/mconsole_user.c b/arch/um/drivers/mconsole_user.c index fe5afb132..04383f9 100644 --- a/arch/um/drivers/mconsole_user.c +++ b/arch/um/drivers/mconsole_user.c @@ -23,13 +23,14 @@ static struct mconsole_command commands[] = { { "reboot", mconsole_reboot, MCONSOLE_PROC }, { "config", mconsole_config, MCONSOLE_PROC }, { "remove", mconsole_remove, MCONSOLE_PROC }, - { "sysrq", mconsole_sysrq, MCONSOLE_INTR }, + { "sysrq", mconsole_sysrq, MCONSOLE_PROC }, { "help", mconsole_help, MCONSOLE_INTR }, { "cad", mconsole_cad, MCONSOLE_INTR }, { "stop", mconsole_stop, MCONSOLE_PROC }, { "go", mconsole_go, MCONSOLE_INTR }, { "log", mconsole_log, MCONSOLE_INTR }, { "proc", mconsole_proc, MCONSOLE_PROC }, + { "stack", mconsole_stack, MCONSOLE_INTR }, }; /* Initialized in mconsole_init, which is an initcall */ @@ -172,9 +173,9 @@ int mconsole_notify(char *sock_name, int type, const void *data, int len) if(notify_sock < 0){ notify_sock = socket(PF_UNIX, SOCK_DGRAM, 0); if(notify_sock < 0){ - printk("mconsole_notify - socket failed, errno = %d\n", - errno); err = -errno; + printk("mconsole_notify - socket failed, errno = %d\n", + err); } } unlock_notify(); @@ -197,8 +198,8 @@ int mconsole_notify(char *sock_name, int type, const void *data, int len) n = sendto(notify_sock, &packet, len, 0, (struct sockaddr *) &target, sizeof(target)); if(n < 0){ - printk("mconsole_notify - sendto failed, errno = %d\n", errno); err = -errno; + printk("mconsole_notify - sendto failed, errno = %d\n", errno); } return(err); } diff --git a/arch/um/drivers/pty.c b/arch/um/drivers/pty.c index ed84d01..0306a1b 100644 --- a/arch/um/drivers/pty.c +++ b/arch/um/drivers/pty.c @@ -43,8 +43,9 @@ static int pts_open(int input, int output, int primary, void *d, fd = get_pty(); if(fd < 0){ + err = -errno; printk("open_pts : Failed to open pts\n"); - return(-errno); + return err; } if(data->raw){ CATCH_EINTR(err = tcgetattr(fd, &data->tt)); diff --git a/arch/um/drivers/ubd_user.c b/arch/um/drivers/ubd_user.c deleted file mode 100644 index b94d2bc4f..0000000 --- a/arch/um/drivers/ubd_user.c +++ /dev/null @@ -1,75 +0,0 @@ -/* - * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com) - * Copyright (C) 2001 Ridgerun,Inc (glonnon@ridgerun.com) - * Licensed under the GPL - */ - -#include <stddef.h> -#include <unistd.h> -#include <errno.h> -#include <sched.h> -#include <signal.h> -#include <string.h> -#include <netinet/in.h> -#include <sys/time.h> -#include <sys/socket.h> -#include <sys/mman.h> -#include <sys/param.h> -#include "asm/types.h" -#include "user_util.h" -#include "kern_util.h" -#include "user.h" -#include "ubd_user.h" -#include "os.h" -#include "cow.h" - -#include <endian.h> -#include <byteswap.h> - -void ignore_sigwinch_sig(void) -{ - signal(SIGWINCH, SIG_IGN); -} - -int start_io_thread(unsigned long sp, int *fd_out) -{ - int pid, fds[2], err; - - err = os_pipe(fds, 1, 1); - if(err < 0){ - printk("start_io_thread - os_pipe failed, err = %d\n", -err); - goto out; - } - - kernel_fd = fds[0]; - *fd_out = fds[1]; - - pid = clone(io_thread, (void *) sp, CLONE_FILES | CLONE_VM | SIGCHLD, - NULL); - if(pid < 0){ - printk("start_io_thread - clone failed : errno = %d\n", errno); - err = -errno; - goto out_close; - } - - return(pid); - - out_close: - os_close_file(fds[0]); - os_close_file(fds[1]); - kernel_fd = -1; - *fd_out = -1; - out: - return(err); -} - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-file-style: "linux" - * End: - */ diff --git a/arch/um/drivers/xterm.c b/arch/um/drivers/xterm.c index 93dc191..90e0e5f 100644 --- a/arch/um/drivers/xterm.c +++ b/arch/um/drivers/xterm.c @@ -110,13 +110,15 @@ int xterm_open(int input, int output, int primary, void *d, fd = mkstemp(file); if(fd < 0){ + err = -errno; printk("xterm_open : mkstemp failed, errno = %d\n", errno); - return(-errno); + return err; } if(unlink(file)){ + err = -errno; printk("xterm_open : unlink failed, errno = %d\n", errno); - return(-errno); + return err; } os_close_file(fd); diff --git a/arch/um/include/common-offsets.h b/arch/um/include/common-offsets.h index 0aa6209..782ac3a 100644 --- a/arch/um/include/common-offsets.h +++ b/arch/um/include/common-offsets.h @@ -12,4 +12,6 @@ DEFINE_STR(UM_KERN_WARNING, KERN_WARNING); DEFINE_STR(UM_KERN_NOTICE, KERN_NOTICE); DEFINE_STR(UM_KERN_INFO, KERN_INFO); DEFINE_STR(UM_KERN_DEBUG, KERN_DEBUG); -DEFINE(HOST_ELF_CLASS, ELF_CLASS); +DEFINE(UM_ELF_CLASS, ELF_CLASS); +DEFINE(UM_ELFCLASS32, ELFCLASS32); +DEFINE(UM_ELFCLASS64, ELFCLASS64); diff --git a/arch/um/include/mconsole.h b/arch/um/include/mconsole.h index cfa368e..b1b512f 100644 --- a/arch/um/include/mconsole.h +++ b/arch/um/include/mconsole.h @@ -81,6 +81,7 @@ extern void mconsole_stop(struct mc_request *req); extern void mconsole_go(struct mc_request *req); extern void mconsole_log(struct mc_request *req); extern void mconsole_proc(struct mc_request *req); +extern void mconsole_stack(struct mc_request *req); extern int mconsole_get_request(int fd, struct mc_request *req); extern int mconsole_notify(char *sock_name, int type, const void *data, diff --git a/arch/um/include/mem_user.h b/arch/um/include/mem_user.h index d6404bb..9fef412 100644 --- a/arch/um/include/mem_user.h +++ b/arch/um/include/mem_user.h @@ -51,7 +51,6 @@ extern unsigned long task_size; extern void check_devanon(void); extern int init_mem_user(void); -extern int create_mem_file(unsigned long len); extern void setup_memory(void *entry); extern unsigned long find_iomem(char *driver, unsigned long *len_out); extern int init_maps(unsigned long physmem, unsigned long iomem, @@ -64,20 +63,6 @@ extern unsigned long phys_offset(unsigned long phys); extern void unmap_physmem(void); extern void map_memory(unsigned long virt, unsigned long phys, unsigned long len, int r, int w, int x); -extern int protect_memory(unsigned long addr, unsigned long len, - int r, int w, int x, int must_succeed); extern unsigned long get_kmem_end(void); -extern void check_tmpexec(void); #endif - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-file-style: "linux" - * End: - */ diff --git a/arch/um/include/os.h b/arch/um/include/os.h index 4c36245..583329d 100644 --- a/arch/um/include/os.h +++ b/arch/um/include/os.h @@ -157,6 +157,9 @@ extern int os_lock_file(int fd, int excl); extern void os_early_checks(void); extern int can_do_skas(void); +/* mem.c */ +extern int create_mem_file(unsigned long len); + /* process.c */ extern unsigned long os_process_pc(int pid); extern int os_process_parent(int pid); @@ -181,6 +184,8 @@ extern unsigned long long os_usecs(void); /* tt.c * for tt mode only (will be deleted in future...) */ +extern int protect_memory(unsigned long addr, unsigned long len, + int r, int w, int x, int must_succeed); extern void forward_pending_sigio(int target); extern int start_fork_tramp(void *arg, unsigned long temp_stack, int clone_flags, int (*tramp)(void *)); diff --git a/arch/um/include/user.h b/arch/um/include/user.h index 57ee9e2..0f865ef 100644 --- a/arch/um/include/user.h +++ b/arch/um/include/user.h @@ -14,7 +14,9 @@ extern void *um_kmalloc_atomic(int size); extern void kfree(void *ptr); extern int in_aton(char *str); extern int open_gdb_chan(void); -extern int strlcpy(char *, const char *, int); +/* These use size_t, however unsigned long is correct on both i386 and x86_64. */ +extern unsigned long strlcpy(char *, const char *, unsigned long); +extern unsigned long strlcat(char *, const char *, unsigned long); extern void *um_vmalloc(int size); extern void vfree(void *ptr); diff --git a/arch/um/kernel/Makefile b/arch/um/kernel/Makefile index 614b8eb..1a0001b 100644 --- a/arch/um/kernel/Makefile +++ b/arch/um/kernel/Makefile @@ -1,4 +1,4 @@ -# +# # Copyright (C) 2002 Jeff Dike (jdike@karaya.com) # Licensed under the GPL # @@ -7,11 +7,11 @@ extra-y := vmlinux.lds clean-files := obj-y = config.o exec_kern.o exitcode.o \ - helper.o init_task.o irq.o irq_user.o ksyms.o main.o mem.o mem_user.o \ - physmem.o process_kern.o ptrace.o reboot.o resource.o sigio_user.o \ - sigio_kern.o signal_kern.o signal_user.o smp.o syscall_kern.o sysrq.o \ - tempfile.o time.o time_kern.o tlb.o trap_kern.o trap_user.o \ - uaccess_user.o um_arch.o umid.o user_util.o + helper.o init_task.o irq.o irq_user.o ksyms.o main.o mem.o physmem.o \ + process_kern.o ptrace.o reboot.o resource.o sigio_user.o sigio_kern.o \ + signal_kern.o signal_user.o smp.o syscall_kern.o sysrq.o time.o \ + time_kern.o tlb.o trap_kern.o trap_user.o uaccess_user.o um_arch.o \ + umid.o user_util.o obj-$(CONFIG_BLK_DEV_INITRD) += initrd.o obj-$(CONFIG_GPROF) += gprof_syms.o @@ -24,8 +24,8 @@ obj-$(CONFIG_MODE_SKAS) += skas/ user-objs-$(CONFIG_TTY_LOG) += tty_log.o -USER_OBJS := $(user-objs-y) config.o helper.o main.o tempfile.o time.o \ - tty_log.o umid.o user_util.o +USER_OBJS := $(user-objs-y) config.o helper.o main.o time.o tty_log.o umid.o \ + user_util.o include arch/um/scripts/Makefile.rules diff --git a/arch/um/kernel/helper.c b/arch/um/kernel/helper.c index f83e1e8..33fb0bd 100644 --- a/arch/um/kernel/helper.c +++ b/arch/um/kernel/helper.c @@ -85,8 +85,8 @@ int run_helper(void (*pre_exec)(void *), void *pre_data, char **argv, data.fd = fds[1]; pid = clone(helper_child, (void *) sp, CLONE_VM | SIGCHLD, &data); if(pid < 0){ - printk("run_helper : clone failed, errno = %d\n", errno); ret = -errno; + printk("run_helper : clone failed, errno = %d\n", errno); goto out_close; } @@ -122,7 +122,7 @@ int run_helper_thread(int (*proc)(void *), void *arg, unsigned int flags, unsigned long *stack_out, int stack_order) { unsigned long stack, sp; - int pid, status; + int pid, status, err; stack = alloc_stack(stack_order, um_in_interrupt()); if(stack == 0) return(-ENOMEM); @@ -130,16 +130,18 @@ int run_helper_thread(int (*proc)(void *), void *arg, unsigned int flags, sp = stack + (page_size() << stack_order) - sizeof(void *); pid = clone(proc, (void *) sp, flags | SIGCHLD, arg); if(pid < 0){ + err = -errno; printk("run_helper_thread : clone failed, errno = %d\n", errno); - return(-errno); + return err; } if(stack_out == NULL){ CATCH_EINTR(pid = waitpid(pid, &status, 0)); if(pid < 0){ + err = -errno; printk("run_helper_thread - wait failed, errno = %d\n", errno); - pid = -errno; + pid = err; } if(!WIFEXITED(status) || (WEXITSTATUS(status) != 0)) printk("run_helper_thread - thread returned status " @@ -156,8 +158,8 @@ int helper_wait(int pid) CATCH_EINTR(ret = waitpid(pid, NULL, WNOHANG)); if(ret < 0){ + ret = -errno; printk("helper_wait : waitpid failed, errno = %d\n", errno); - return(-errno); } return(ret); } diff --git a/arch/um/kernel/init_task.c b/arch/um/kernel/init_task.c index cd7c85b..49ed5dd 100644 --- a/arch/um/kernel/init_task.c +++ b/arch/um/kernel/init_task.c @@ -13,6 +13,7 @@ #include "asm/pgtable.h" #include "user_util.h" #include "mem_user.h" +#include "os.h" static struct fs_struct init_fs = INIT_FS; struct mm_struct init_mm = INIT_MM(init_mm); @@ -45,8 +46,8 @@ __attribute__((__section__(".data.init_task"))) = void unprotect_stack(unsigned long stack) { - protect_memory(stack, (1 << CONFIG_KERNEL_STACK_ORDER) * PAGE_SIZE, - 1, 1, 0, 1); + os_protect_memory((void *) stack, (1 << CONFIG_KERNEL_STACK_ORDER) * PAGE_SIZE, + 1, 1, 0); } /* diff --git a/arch/um/kernel/mem.c b/arch/um/kernel/mem.c index 64fa062..ea008b0 100644 --- a/arch/um/kernel/mem.c +++ b/arch/um/kernel/mem.c @@ -1,4 +1,4 @@ -/* +/* * Copyright (C) 2000 - 2003 Jeff Dike (jdike@addtoit.com) * Licensed under the GPL */ @@ -19,6 +19,10 @@ #include "mem_user.h" #include "uml_uaccess.h" #include "os.h" +#include "linux/types.h" +#include "linux/string.h" +#include "init.h" +#include "kern_constants.h" extern char __binary_start; @@ -368,6 +372,16 @@ struct page *pte_alloc_one(struct mm_struct *mm, unsigned long address) return pte; } +struct iomem_region *iomem_regions = NULL; +int iomem_size = 0; + +extern int parse_iomem(char *str, int *add) __init; + +__uml_setup("iomem=", parse_iomem, +"iomem=<name>,<file>\n" +" Configure <file> as an IO memory region named <name>.\n\n" +); + /* * Overrides for Emacs so that we follow Linus's tabbing style. * Emacs will notice this stuff at the end of the file and automatically diff --git a/arch/um/kernel/mem_user.c b/arch/um/kernel/mem_user.c deleted file mode 100644 index 4a663fd..0000000 --- a/arch/um/kernel/mem_user.c +++ /dev/null @@ -1,273 +0,0 @@ -/* - * arch/um/kernel/mem_user.c - * - * BRIEF MODULE DESCRIPTION - * user side memory routines for supporting IO memory inside user mode linux - * - * Copyright (C) 2001 RidgeRun, Inc. - * Author: RidgeRun, Inc. - * Greg Lonnon glonnon@ridgerun.com or info@ridgerun.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 <stdio.h> -#include <stdlib.h> -#include <stddef.h> -#include <stdarg.h> -#include <unistd.h> -#include <errno.h> -#include <string.h> -#include <fcntl.h> -#include <sys/types.h> -#include <sys/mman.h> -#include "kern_util.h" -#include "user.h" -#include "user_util.h" -#include "mem_user.h" -#include "init.h" -#include "os.h" -#include "tempfile.h" -#include "kern_constants.h" - -#define TEMPNAME_TEMPLATE "vm_file-XXXXXX" - -static int create_tmp_file(unsigned long len) -{ - int fd, err; - char zero; - - fd = make_tempfile(TEMPNAME_TEMPLATE, NULL, 1); - if(fd < 0) { - os_print_error(fd, "make_tempfile"); - exit(1); - } - - err = os_mode_fd(fd, 0777); - if(err < 0){ - os_print_error(err, "os_mode_fd"); - exit(1); - } - err = os_seek_file(fd, len); - if(err < 0){ - os_print_error(err, "os_seek_file"); - exit(1); - } - zero = 0; - err = os_write_file(fd, &zero, 1); - if(err != 1){ - os_print_error(err, "os_write_file"); - exit(1); - } - - return(fd); -} - -void check_tmpexec(void) -{ - void *addr; - int err, fd = create_tmp_file(UM_KERN_PAGE_SIZE); - - addr = mmap(NULL, UM_KERN_PAGE_SIZE, - PROT_READ | PROT_WRITE | PROT_EXEC, MAP_PRIVATE, fd, 0); - printf("Checking PROT_EXEC mmap in /tmp..."); - fflush(stdout); - if(addr == MAP_FAILED){ - err = errno; - perror("failed"); - if(err == EPERM) - printf("/tmp must be not mounted noexec\n"); - exit(1); - } - printf("OK\n"); - munmap(addr, UM_KERN_PAGE_SIZE); - - os_close_file(fd); -} - -static int have_devanon = 0; - -void check_devanon(void) -{ - int fd; - - printk("Checking for /dev/anon on the host..."); - fd = open("/dev/anon", O_RDWR); - if(fd < 0){ - printk("Not available (open failed with errno %d)\n", errno); - return; - } - - printk("OK\n"); - have_devanon = 1; -} - -static int create_anon_file(unsigned long len) -{ - void *addr; - int fd; - - fd = open("/dev/anon", O_RDWR); - if(fd < 0) { - os_print_error(fd, "opening /dev/anon"); - exit(1); - } - - addr = mmap(NULL, len, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0); - if(addr == MAP_FAILED){ - perror("mapping physmem file"); - exit(1); - } - munmap(addr, len); - - return(fd); -} - -int create_mem_file(unsigned long len) -{ - int err, fd; - - if(have_devanon) - fd = create_anon_file(len); - else fd = create_tmp_file(len); - - err = os_set_exec_close(fd, 1); - if(err < 0) - os_print_error(err, "exec_close"); - return(fd); -} - -struct iomem_region *iomem_regions = NULL; -int iomem_size = 0; - -static int __init parse_iomem(char *str, int *add) -{ - struct iomem_region *new; - struct uml_stat buf; - char *file, *driver; - int fd, err, size; - - driver = str; - file = strchr(str,','); - if(file == NULL){ - printf("parse_iomem : failed to parse iomem\n"); - goto out; - } - *file = '\0'; - file++; - fd = os_open_file(file, of_rdwr(OPENFLAGS()), 0); - if(fd < 0){ - os_print_error(fd, "parse_iomem - Couldn't open io file"); - goto out; - } - - err = os_stat_fd(fd, &buf); - if(err < 0){ - os_print_error(err, "parse_iomem - cannot stat_fd file"); - goto out_close; - } - - new = malloc(sizeof(*new)); - if(new == NULL){ - perror("Couldn't allocate iomem_region struct"); - goto out_close; - } - - size = (buf.ust_size + UM_KERN_PAGE_SIZE) & ~(UM_KERN_PAGE_SIZE - 1); - - *new = ((struct iomem_region) { .next = iomem_regions, - .driver = driver, - .fd = fd, - .size = size, - .phys = 0, - .virt = 0 }); - iomem_regions = new; - iomem_size += new->size + UM_KERN_PAGE_SIZE; - - return(0); - out_close: - os_close_file(fd); - out: - return(1); -} - -__uml_setup("iomem=", parse_iomem, -"iomem=<name>,<file>\n" -" Configure <file> as an IO memory region named <name>.\n\n" -); - -int protect_memory(unsigned long addr, unsigned long len, int r, int w, int x, - int must_succeed) -{ - int err; - - err = os_protect_memory((void *) addr, len, r, w, x); - if(err < 0){ - if(must_succeed) - panic("protect failed, err = %d", -err); - else return(err); - } - return(0); -} - -#if 0 -/* Debugging facility for dumping stuff out to the host, avoiding the timing - * problems that come with printf and breakpoints. - * Enable in case of emergency. - */ - -int logging = 1; -int logging_fd = -1; - -int logging_line = 0; -char logging_buf[512]; - -void log(char *fmt, ...) -{ - va_list ap; - struct timeval tv; - struct openflags flags; - - if(logging == 0) return; - if(logging_fd < 0){ - flags = of_create(of_trunc(of_rdwr(OPENFLAGS()))); - logging_fd = os_open_file("log", flags, 0644); - } - gettimeofday(&tv, NULL); - sprintf(logging_buf, "%d\t %u.%u ", logging_line++, tv.tv_sec, - tv.tv_usec); - va_start(ap, fmt); - vsprintf(&logging_buf[strlen(logging_buf)], fmt, ap); - va_end(ap); - write(logging_fd, logging_buf, strlen(logging_buf)); -} -#endif - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-file-style: "linux" - * End: - */ diff --git a/arch/um/kernel/process_kern.c b/arch/um/kernel/process_kern.c index c23d8a0..ea65db6 100644 --- a/arch/um/kernel/process_kern.c +++ b/arch/um/kernel/process_kern.c @@ -82,7 +82,8 @@ unsigned long alloc_stack(int order, int atomic) unsigned long page; int flags = GFP_KERNEL; - if(atomic) flags |= GFP_ATOMIC; + if (atomic) + flags = GFP_ATOMIC; page = __get_free_pages(flags, order); if(page == 0) return(0); @@ -113,8 +114,23 @@ void set_current(void *t) void *_switch_to(void *prev, void *next, void *last) { - return(CHOOSE_MODE(switch_to_tt(prev, next), - switch_to_skas(prev, next))); + struct task_struct *from = prev; + struct task_struct *to= next; + + to->thread.prev_sched = from; + set_current(to); + + do { + current->thread.saved_task = NULL ; + CHOOSE_MODE_PROC(switch_to_tt, switch_to_skas, prev, next); + if(current->thread.saved_task) + show_regs(&(current->thread.regs)); + next= current->thread.saved_task; + prev= current; + } while(current->thread.saved_task); + + return(current->thread.prev_sched); + } void interrupt_end(void) diff --git a/arch/um/kernel/sigio_user.c b/arch/um/kernel/sigio_user.c index e892189..a527511 100644 --- a/arch/um/kernel/sigio_user.c +++ b/arch/um/kernel/sigio_user.c @@ -340,7 +340,7 @@ static int setup_initial_poll(int fd) { struct pollfd *p; - p = um_kmalloc(sizeof(struct pollfd)); + p = um_kmalloc_atomic(sizeof(struct pollfd)); if(p == NULL){ printk("setup_initial_poll : failed to allocate poll\n"); return(-1); diff --git a/arch/um/kernel/skas/include/mode_kern-skas.h b/arch/um/kernel/skas/include/mode_kern-skas.h index e484900..c97a80d 100644 --- a/arch/um/kernel/skas/include/mode_kern-skas.h +++ b/arch/um/kernel/skas/include/mode_kern-skas.h @@ -11,7 +11,7 @@ #include "asm/ptrace.h" extern void flush_thread_skas(void); -extern void *switch_to_skas(void *prev, void *next); +extern void switch_to_skas(void *prev, void *next); extern void start_thread_skas(struct pt_regs *regs, unsigned long eip, unsigned long esp); extern int copy_thread_skas(int nr, unsigned long clone_flags, diff --git a/arch/um/kernel/skas/include/uaccess-skas.h b/arch/um/kernel/skas/include/uaccess-skas.h index 6ee3f39..7da0c2d 100644 --- a/arch/um/kernel/skas/include/uaccess-skas.h +++ b/arch/um/kernel/skas/include/uaccess-skas.h @@ -18,12 +18,6 @@ ((unsigned long) (addr) + (size) <= FIXADDR_USER_END) && \ ((unsigned long) (addr) + (size) >= (unsigned long)(addr)))) -static inline int verify_area_skas(int type, const void __user * addr, - unsigned long size) -{ - return(access_ok_skas(type, addr, size) ? 0 : -EFAULT); -} - extern int copy_from_user_skas(void *to, const void __user *from, int n); extern int copy_to_user_skas(void __user *to, const void *from, int n); extern int strncpy_from_user_skas(char *dst, const char __user *src, int count); diff --git a/arch/um/kernel/skas/process_kern.c b/arch/um/kernel/skas/process_kern.c index 3d1b227..efe92e8 100644 --- a/arch/um/kernel/skas/process_kern.c +++ b/arch/um/kernel/skas/process_kern.c @@ -24,7 +24,7 @@ #include "proc_mm.h" #include "registers.h" -void *switch_to_skas(void *prev, void *next) +void switch_to_skas(void *prev, void *next) { struct task_struct *from, *to; @@ -35,16 +35,11 @@ void *switch_to_skas(void *prev, void *next) if(current->pid == 0) switch_timers(0); - to->thread.prev_sched = from; - set_current(to); - switch_threads(&from->thread.mode.skas.switch_buf, to->thread.mode.skas.switch_buf); if(current->pid == 0) switch_timers(1); - - return(current->thread.prev_sched); } extern void schedule_tail(struct task_struct *prev); diff --git a/arch/um/kernel/tempfile.c b/arch/um/kernel/tempfile.c deleted file mode 100644 index b1674bc..0000000 --- a/arch/um/kernel/tempfile.c +++ /dev/null @@ -1,82 +0,0 @@ -/* - * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) - * Licensed under the GPL - */ - -#include <stdio.h> -#include <stdlib.h> -#include <unistd.h> -#include <string.h> -#include <errno.h> -#include <sys/param.h> -#include "init.h" - -/* Modified from create_mem_file and start_debugger */ -static char *tempdir = NULL; - -static void __init find_tempdir(void) -{ - char *dirs[] = { "TMP", "TEMP", "TMPDIR", NULL }; - int i; - char *dir = NULL; - - if(tempdir != NULL) return; /* We've already been called */ - for(i = 0; dirs[i]; i++){ - dir = getenv(dirs[i]); - if((dir != NULL) && (*dir != '\0')) - break; - } - if((dir == NULL) || (*dir == '\0')) - dir = "/tmp"; - - tempdir = malloc(strlen(dir) + 2); - if(tempdir == NULL){ - fprintf(stderr, "Failed to malloc tempdir, " - "errno = %d\n", errno); - return; - } - strcpy(tempdir, dir); - strcat(tempdir, "/"); -} - -int make_tempfile(const char *template, char **out_tempname, int do_unlink) -{ - char tempname[MAXPATHLEN]; - int fd; - - find_tempdir(); - if (*template != '/') - strcpy(tempname, tempdir); - else - *tempname = 0; - strcat(tempname, template); - fd = mkstemp(tempname); - if(fd < 0){ - fprintf(stderr, "open - cannot create %s: %s\n", tempname, - strerror(errno)); - return -1; - } - if(do_unlink && (unlink(tempname) < 0)){ - perror("unlink"); - return -1; - } - if(out_tempname){ - *out_tempname = strdup(tempname); - if(*out_tempname == NULL){ - perror("strdup"); - return -1; - } - } - return(fd); -} - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-file-style: "linux" - * End: - */ diff --git a/arch/um/kernel/tlb.c b/arch/um/kernel/tlb.c index 80ed618..f5b0636 100644 --- a/arch/um/kernel/tlb.c +++ b/arch/um/kernel/tlb.c @@ -193,12 +193,12 @@ void fix_range_common(struct mm_struct *mm, unsigned long start_addr, r = pte_read(*npte); w = pte_write(*npte); x = pte_exec(*npte); - if(!pte_dirty(*npte)) - w = 0; - if(!pte_young(*npte)){ - r = 0; - w = 0; - } + if (!pte_young(*npte)) { + r = 0; + w = 0; + } else if (!pte_dirty(*npte)) { + w = 0; + } if(force || pte_newpage(*npte)){ if(pte_present(*npte)) ret = add_mmap(addr, @@ -307,7 +307,7 @@ int flush_tlb_kernel_range_common(unsigned long start, unsigned long end) } else if(pte_newprot(*pte)){ updated = 1; - protect_memory(addr, PAGE_SIZE, 1, 1, 1, 1); + os_protect_memory((void *) addr, PAGE_SIZE, 1, 1, 1); } addr += PAGE_SIZE; } diff --git a/arch/um/kernel/trap_kern.c b/arch/um/kernel/trap_kern.c index 87cc6fd..d297429 100644 --- a/arch/um/kernel/trap_kern.c +++ b/arch/um/kernel/trap_kern.c @@ -18,6 +18,7 @@ #include "asm/a.out.h" #include "asm/current.h" #include "asm/irq.h" +#include "sysdep/sigcontext.h" #include "user_util.h" #include "kern_util.h" #include "kern.h" @@ -39,6 +40,12 @@ int handle_page_fault(unsigned long address, unsigned long ip, int err = -EFAULT; *code_out = SEGV_MAPERR; + + /* If the fault was during atomic operation, don't take the fault, just + * fail. */ + if (in_atomic()) + goto out_nosemaphore; + down_read(&mm->mmap_sem); vma = find_vma(mm, address); if(!vma) @@ -89,6 +96,7 @@ survive: flush_tlb_page(vma, address); out: up_read(&mm->mmap_sem); +out_nosemaphore: return(err); /* @@ -125,7 +133,15 @@ unsigned long segv(struct faultinfo fi, unsigned long ip, int is_user, void *sc) } else if(current->mm == NULL) panic("Segfault with no mm"); - err = handle_page_fault(address, ip, is_write, is_user, &si.si_code); + + if (SEGV_IS_FIXABLE(&fi)) + err = handle_page_fault(address, ip, is_write, is_user, &si.si_code); + else { + err = -EFAULT; + /* A thread accessed NULL, we get a fault, but CR2 is invalid. + * This code is used in __do_copy_from_user() of TT mode. */ + address = 0; + } catcher = current->thread.fault_catcher; if(!err) diff --git a/arch/um/kernel/tt/include/mode_kern-tt.h b/arch/um/kernel/tt/include/mode_kern-tt.h index e0ca0e0..2a35b15 100644 --- a/arch/um/kernel/tt/include/mode_kern-tt.h +++ b/arch/um/kernel/tt/include/mode_kern-tt.h @@ -11,7 +11,7 @@ #include "asm/ptrace.h" #include "asm/uaccess.h" -extern void *switch_to_tt(void *prev, void *next); +extern void switch_to_tt(void *prev, void *next); extern void flush_thread_tt(void); extern void start_thread_tt(struct pt_regs *regs, unsigned long eip, unsigned long esp); diff --git a/arch/um/kernel/tt/include/uaccess-tt.h b/arch/um/kernel/tt/include/uaccess-tt.h index aa6db38..dc2ebfa 100644 --- a/arch/um/kernel/tt/include/uaccess-tt.h +++ b/arch/um/kernel/tt/include/uaccess-tt.h @@ -33,12 +33,6 @@ extern unsigned long uml_physmem; (((unsigned long) (addr) <= ((unsigned long) (addr) + (size))) && \ (under_task_size(addr, size) || is_stack(addr, size)))) -static inline int verify_area_tt(int type, const void __user * addr, - unsigned long size) -{ - return(access_ok_tt(type, addr, size) ? 0 : -EFAULT); -} - extern unsigned long get_fault_addr(void); extern int __do_copy_from_user(void *to, const void *from, int n, diff --git a/arch/um/kernel/tt/mem_user.c b/arch/um/kernel/tt/mem_user.c index 3085267..03e5898 100644 --- a/arch/um/kernel/tt/mem_user.c +++ b/arch/um/kernel/tt/mem_user.c @@ -12,6 +12,7 @@ #include "tt.h" #include "mem_user.h" #include "user_util.h" +#include "os.h" void remap_data(void *segment_start, void *segment_end, int w) { diff --git a/arch/um/kernel/tt/process_kern.c b/arch/um/kernel/tt/process_kern.c index a189a2b..cfaa373a 100644 --- a/arch/um/kernel/tt/process_kern.c +++ b/arch/um/kernel/tt/process_kern.c @@ -23,10 +23,11 @@ #include "mem_user.h" #include "tlb.h" #include "mode.h" +#include "mode_kern.h" #include "init.h" #include "tt.h" -void *switch_to_tt(void *prev, void *next, void *last) +void switch_to_tt(void *prev, void *next) { struct task_struct *from, *to, *prev_sched; unsigned long flags; @@ -36,8 +37,6 @@ void *switch_to_tt(void *prev, void *next, void *last) from = prev; to = next; - to->thread.prev_sched = from; - cpu = from->thread_info->cpu; if(cpu == 0) forward_interrupts(to->thread.mode.tt.extern_pid); @@ -53,7 +52,6 @@ void *switch_to_tt(void *prev, void *next, void *last) forward_pending_sigio(to->thread.mode.tt.extern_pid); c = 0; - set_current(to); err = os_write_file(to->thread.mode.tt.switch_pipe[1], &c, sizeof(c)); if(err != sizeof(c)) @@ -85,8 +83,6 @@ void *switch_to_tt(void *prev, void *next, void *last) flush_tlb_all(); local_irq_restore(flags); - - return(current->thread.prev_sched); } void release_thread_tt(struct task_struct *task) diff --git a/arch/um/kernel/tt/uaccess_user.c b/arch/um/kernel/tt/uaccess_user.c index f014755..8c220f0 100644 --- a/arch/um/kernel/tt/uaccess_user.c +++ b/arch/um/kernel/tt/uaccess_user.c @@ -22,8 +22,15 @@ int __do_copy_from_user(void *to, const void *from, int n, __do_copy, &faulted); TASK_REGS(get_current())->tt = save; - if(!faulted) return(0); - else return(n - (fault - (unsigned long) from)); + if(!faulted) + return 0; + else if (fault) + return n - (fault - (unsigned long) from); + else + /* In case of a general protection fault, we don't have the + * fault address, so NULL is used instead. Pretend we didn't + * copy anything. */ + return n; } static void __do_strncpy(void *dst, const void *src, int count) diff --git a/arch/um/kernel/um_arch.c b/arch/um/kernel/um_arch.c index 09f6f7c..f0a2759 100644 --- a/arch/um/kernel/um_arch.c +++ b/arch/um/kernel/um_arch.c @@ -361,11 +361,6 @@ int linux_main(int argc, char **argv) uml_start = CHOOSE_MODE_PROC(set_task_sizes_tt, set_task_sizes_skas, 0, &host_task_size, &task_size); - /* Need to check this early because mmapping happens before the - * kernel is running. - */ - check_tmpexec(); - brk_start = (unsigned long) sbrk(0); CHOOSE_MODE_PROC(before_mem_tt, before_mem_skas, brk_start); /* Increase physical memory size for exec-shield users diff --git a/arch/um/kernel/umid.c b/arch/um/kernel/umid.c index 186c288..0b21d59 100644 --- a/arch/um/kernel/umid.c +++ b/arch/um/kernel/umid.c @@ -31,6 +31,8 @@ static char *uml_dir = UML_DIR; /* Changed by set_umid */ static int umid_is_random = 1; static int umid_inited = 0; +/* Have we created the files? Should we remove them? */ +static int umid_owned = 0; static int make_umid(int (*printer)(const char *fmt, ...)); @@ -82,20 +84,21 @@ int __init umid_file_name(char *name, char *buf, int len) extern int tracing_pid; -static int __init create_pid_file(void) +static void __init create_pid_file(void) { char file[strlen(uml_dir) + UMID_LEN + sizeof("/pid\0")]; char pid[sizeof("nnnnn\0")]; int fd, n; - if(umid_file_name("pid", file, sizeof(file))) return 0; + if(umid_file_name("pid", file, sizeof(file))) + return; fd = os_open_file(file, of_create(of_excl(of_rdwr(OPENFLAGS()))), 0644); if(fd < 0){ printf("Open of machine pid file \"%s\" failed: %s\n", file, strerror(-fd)); - return 0; + return; } sprintf(pid, "%d\n", os_getpid()); @@ -103,7 +106,6 @@ static int __init create_pid_file(void) if(n != strlen(pid)) printf("Write of pid file failed - err = %d\n", -n); os_close_file(fd); - return 0; } static int actually_do_remove(char *dir) @@ -147,7 +149,8 @@ static int actually_do_remove(char *dir) void remove_umid_dir(void) { char dir[strlen(uml_dir) + UMID_LEN + 1]; - if(!umid_inited) return; + if (!umid_owned) + return; sprintf(dir, "%s%s", uml_dir, umid); actually_do_remove(dir); @@ -155,11 +158,12 @@ void remove_umid_dir(void) char *get_umid(int only_if_set) { - if(only_if_set && umid_is_random) return(NULL); - return(umid); + if(only_if_set && umid_is_random) + return NULL; + return umid; } -int not_dead_yet(char *dir) +static int not_dead_yet(char *dir) { char file[strlen(uml_dir) + UMID_LEN + sizeof("/pid\0")]; char pid[sizeof("nnnnn\0")], *end; @@ -193,7 +197,8 @@ int not_dead_yet(char *dir) (p == CHOOSE_MODE(tracing_pid, os_getpid()))) dead = 1; } - if(!dead) return(1); + if(!dead) + return(1); return(actually_do_remove(dir)); } @@ -232,16 +237,13 @@ static int __init make_uml_dir(void) strlcpy(dir, home, sizeof(dir)); uml_dir++; } + strlcat(dir, uml_dir, sizeof(dir)); len = strlen(dir); - strncat(dir, uml_dir, sizeof(dir) - len); - len = strlen(dir); - if((len > 0) && (len < sizeof(dir) - 1) && (dir[len - 1] != '/')){ - dir[len] = '/'; - dir[len + 1] = '\0'; - } + if (len > 0 && dir[len - 1] != '/') + strlcat(dir, "/", sizeof(dir)); uml_dir = malloc(strlen(dir) + 1); - if(uml_dir == NULL){ + if (uml_dir == NULL) { printf("make_uml_dir : malloc failed, errno = %d\n", errno); exit(1); } @@ -286,6 +288,7 @@ static int __init make_umid(int (*printer)(const char *fmt, ...)) if(errno == EEXIST){ if(not_dead_yet(tmp)){ (*printer)("umid '%s' is in use\n", umid); + umid_owned = 0; return(-1); } err = mkdir(tmp, 0777); @@ -296,7 +299,8 @@ static int __init make_umid(int (*printer)(const char *fmt, ...)) return(-1); } - return(0); + umid_owned = 1; + return 0; } __uml_setup("uml_dir=", set_uml_dir, @@ -309,7 +313,8 @@ static int __init make_umid_setup(void) /* one function with the ordering we need ... */ make_uml_dir(); make_umid(printf); - return create_pid_file(); + create_pid_file(); + return 0; } __uml_postsetup(make_umid_setup); diff --git a/arch/um/kernel/user_util.c b/arch/um/kernel/user_util.c index 954ff67..41d17c7 100644 --- a/arch/um/kernel/user_util.c +++ b/arch/um/kernel/user_util.c @@ -109,18 +109,14 @@ int raw(int fd) int err; CATCH_EINTR(err = tcgetattr(fd, &tt)); - if (err < 0) { - printk("tcgetattr failed, errno = %d\n", errno); - return(-errno); - } + if(err < 0) + return -errno; cfmakeraw(&tt); CATCH_EINTR(err = tcsetattr(fd, TCSADRAIN, &tt)); - if (err < 0) { - printk("tcsetattr failed, errno = %d\n", errno); - return(-errno); - } + if(err < 0) + return -errno; /* XXX tcsetattr could have applied only some changes * (and cfmakeraw() is a set of changes) */ @@ -132,6 +128,12 @@ void setup_machinename(char *machine_out) struct utsname host; uname(&host); +#if defined(UML_CONFIG_UML_X86) && !defined(UML_CONFIG_64BIT) + if (!strcmp(host.machine, "x86_64")) { + strcpy(machine_out, "i686"); + return; + } +#endif strcpy(machine_out, host.machine); } diff --git a/arch/um/os-Linux/Makefile b/arch/um/os-Linux/Makefile index 7a16624..d15ec2a 100644 --- a/arch/um/os-Linux/Makefile +++ b/arch/um/os-Linux/Makefile @@ -3,11 +3,11 @@ # Licensed under the GPL # -obj-y = aio.o elf_aux.o file.o process.o signal.o start_up.o time.o tt.o \ - tty.o user_syms.o drivers/ sys-$(SUBARCH)/ +obj-y = aio.o elf_aux.o file.o mem.o process.o signal.o start_up.o time.o \ + tt.o tty.o user_syms.o drivers/ sys-$(SUBARCH)/ -USER_OBJS := aio.o elf_aux.o file.o process.o signal.o start_up.o time.o tt.o \ - tty.o +USER_OBJS := aio.o elf_aux.o file.o mem.o process.o signal.o start_up.o \ + time.o tt.o tty.o elf_aux.o: $(ARCH_DIR)/kernel-offsets.h CFLAGS_elf_aux.o += -I$(objtree)/arch/um diff --git a/arch/um/os-Linux/aio.c b/arch/um/os-Linux/aio.c index b04897c..f6e6402 100644 --- a/arch/um/os-Linux/aio.c +++ b/arch/um/os-Linux/aio.c @@ -117,6 +117,8 @@ static int do_aio(aio_context_t ctx, struct aio_context *aio) err = io_submit(ctx, 1, &iocbp); if(err > 0) err = 0; + else + err = -errno; out: return err; @@ -142,7 +144,8 @@ static int aio_thread(void *arg) "errno = %d\n", errno); } else { - aio = (struct aio_context *) event.data; + /* This is safe as we've just a pointer here. */ + aio = (struct aio_context *) (long) event.data; if(update_aio(aio, event.res)){ do_aio(ctx, aio); continue; @@ -313,15 +316,16 @@ static int init_aio_26(void) int err; if(io_setup(256, &ctx)){ + err = -errno; printk("aio_thread failed to initialize context, err = %d\n", errno); - return -errno; + return err; } err = run_helper_thread(aio_thread, NULL, CLONE_FILES | CLONE_VM | SIGCHLD, &stack, 0); if(err < 0) - return -errno; + return err; aio_pid = err; diff --git a/arch/um/os-Linux/drivers/tuntap_user.c b/arch/um/os-Linux/drivers/tuntap_user.c index 4b83c6c..4ba9b17 100644 --- a/arch/um/os-Linux/drivers/tuntap_user.c +++ b/arch/um/os-Linux/drivers/tuntap_user.c @@ -75,7 +75,7 @@ static int tuntap_open_tramp(char *gate, int *fd_out, int me, int remote, struct msghdr msg; struct cmsghdr *cmsg; struct iovec iov; - int pid, n; + int pid, n, err; sprintf(version_buf, "%d", UML_NET_VERSION); @@ -105,9 +105,10 @@ static int tuntap_open_tramp(char *gate, int *fd_out, int me, int remote, n = recvmsg(me, &msg, 0); *used_out = n; if(n < 0){ + err = -errno; printk("tuntap_open_tramp : recvmsg failed - errno = %d\n", errno); - return(-errno); + return err; } CATCH_EINTR(waitpid(pid, NULL, 0)); @@ -147,9 +148,10 @@ static int tuntap_open(void *data) ifr.ifr_flags = IFF_TAP | IFF_NO_PI; strlcpy(ifr.ifr_name, pri->dev_name, sizeof(ifr.ifr_name)); if(ioctl(pri->fd, TUNSETIFF, (void *) &ifr) < 0){ + err = -errno; printk("TUNSETIFF failed, errno = %d\n", errno); os_close_file(pri->fd); - return(-errno); + return err; } } else { diff --git a/arch/um/os-Linux/elf_aux.c b/arch/um/os-Linux/elf_aux.c index 1399520..ab33cb3 100644 --- a/arch/um/os-Linux/elf_aux.c +++ b/arch/um/os-Linux/elf_aux.c @@ -14,7 +14,8 @@ #include "mem_user.h" #include <kernel-offsets.h> -#if HOST_ELF_CLASS == ELFCLASS32 +/* Use the one from the kernel - the host may miss it, if having old headers. */ +#if UM_ELF_CLASS == UM_ELFCLASS32 typedef Elf32_auxv_t elf_auxv_t; #else typedef Elf64_auxv_t elf_auxv_t; @@ -54,7 +55,8 @@ __init void scan_elf_aux( char **envp) * a_un, so we have to use a_val, which is * all that's left. */ - elf_aux_platform = (char *) auxv->a_un.a_val; + elf_aux_platform = + (char *) (long) auxv->a_un.a_val; break; case AT_PAGESZ: page_size = auxv->a_un.a_val; diff --git a/arch/um/os-Linux/file.c b/arch/um/os-Linux/file.c index fd45bb2..f55773c 100644 --- a/arch/um/os-Linux/file.c +++ b/arch/um/os-Linux/file.c @@ -119,15 +119,11 @@ int os_window_size(int fd, int *rows, int *cols) int os_new_tty_pgrp(int fd, int pid) { - if(ioctl(fd, TIOCSCTTY, 0) < 0){ - printk("TIOCSCTTY failed, errno = %d\n", errno); - return(-errno); - } + if(ioctl(fd, TIOCSCTTY, 0) < 0) + return -errno; - if(tcsetpgrp(fd, pid) < 0){ - printk("tcsetpgrp failed, errno = %d\n", errno); - return(-errno); - } + if(tcsetpgrp(fd, pid) < 0) + return -errno; return(0); } @@ -146,18 +142,12 @@ int os_set_slip(int fd) int disc, sencap; disc = N_SLIP; - if(ioctl(fd, TIOCSETD, &disc) < 0){ - printk("Failed to set slip line discipline - " - "errno = %d\n", errno); - return(-errno); - } + if(ioctl(fd, TIOCSETD, &disc) < 0) + return -errno; sencap = 0; - if(ioctl(fd, SIOCSIFENCAP, &sencap) < 0){ - printk("Failed to set slip encapsulation - " - "errno = %d\n", errno); - return(-errno); - } + if(ioctl(fd, SIOCSIFENCAP, &sencap) < 0) + return -errno; return(0); } @@ -180,22 +170,15 @@ int os_sigio_async(int master, int slave) int flags; flags = fcntl(master, F_GETFL); - if(flags < 0) { - printk("fcntl F_GETFL failed, errno = %d\n", errno); - return(-errno); - } + if(flags < 0) + return errno; if((fcntl(master, F_SETFL, flags | O_NONBLOCK | O_ASYNC) < 0) || - (fcntl(master, F_SETOWN, os_getpid()) < 0)){ - printk("fcntl F_SETFL or F_SETOWN failed, errno = %d\n", - errno); - return(-errno); - } + (fcntl(master, F_SETOWN, os_getpid()) < 0)) + return -errno; - if((fcntl(slave, F_SETFL, flags | O_NONBLOCK) < 0)){ - printk("fcntl F_SETFL failed, errno = %d\n", errno); - return(-errno); - } + if((fcntl(slave, F_SETFL, flags | O_NONBLOCK) < 0)) + return -errno; return(0); } @@ -255,7 +238,7 @@ int os_file_mode(char *file, struct openflags *mode_out) int os_open_file(char *file, struct openflags flags, int mode) { - int fd, f = 0; + int fd, err, f = 0; if(flags.r && flags.w) f = O_RDWR; else if(flags.r) f = O_RDONLY; @@ -272,8 +255,9 @@ int os_open_file(char *file, struct openflags flags, int mode) return(-errno); if(flags.cl && fcntl(fd, F_SETFD, 1)){ + err = -errno; os_close_file(fd); - return(-errno); + return err; } return(fd); @@ -383,9 +367,9 @@ int os_file_size(char *file, unsigned long long *size_out) return(fd); } if(ioctl(fd, BLKGETSIZE, &blocks) < 0){ + err = -errno; printk("Couldn't get the block size of \"%s\", " "errno = %d\n", file, errno); - err = -errno; os_close_file(fd); return(err); } @@ -473,11 +457,14 @@ int os_pipe(int *fds, int stream, int close_on_exec) int os_set_fd_async(int fd, int owner) { + int err; + /* XXX This should do F_GETFL first */ if(fcntl(fd, F_SETFL, O_ASYNC | O_NONBLOCK) < 0){ + err = -errno; printk("os_set_fd_async : failed to set O_ASYNC and " "O_NONBLOCK on fd # %d, errno = %d\n", fd, errno); - return(-errno); + return err; } #ifdef notdef if(fcntl(fd, F_SETFD, 1) < 0){ @@ -488,10 +475,11 @@ int os_set_fd_async(int fd, int owner) if((fcntl(fd, F_SETSIG, SIGIO) < 0) || (fcntl(fd, F_SETOWN, owner) < 0)){ + err = -errno; printk("os_set_fd_async : Failed to fcntl F_SETOWN " "(or F_SETSIG) fd %d to pid %d, errno = %d\n", fd, owner, errno); - return(-errno); + return err; } return(0); @@ -516,11 +504,9 @@ int os_set_fd_block(int fd, int blocking) if(blocking) flags &= ~O_NONBLOCK; else flags |= O_NONBLOCK; - if(fcntl(fd, F_SETFL, flags) < 0){ - printk("Failed to change blocking on fd # %d, errno = %d\n", - fd, errno); - return(-errno); - } + if(fcntl(fd, F_SETFL, flags) < 0) + return -errno; + return(0); } @@ -609,11 +595,8 @@ int os_create_unix_socket(char *file, int len, int close_on_exec) int sock, err; sock = socket(PF_UNIX, SOCK_DGRAM, 0); - if (sock < 0){ - printk("create_unix_socket - socket failed, errno = %d\n", - errno); - return(-errno); - } + if(sock < 0) + return -errno; if(close_on_exec) { err = os_set_exec_close(sock, 1); @@ -628,11 +611,8 @@ int os_create_unix_socket(char *file, int len, int close_on_exec) snprintf(addr.sun_path, len, "%s", file); err = bind(sock, (struct sockaddr *) &addr, sizeof(addr)); - if (err < 0){ - printk("create_listening_socket at '%s' - bind failed, " - "errno = %d\n", file, errno); - return(-errno); - } + if(err < 0) + return -errno; return(sock); } diff --git a/arch/um/os-Linux/mem.c b/arch/um/os-Linux/mem.c new file mode 100644 index 0000000..8e71eda --- /dev/null +++ b/arch/um/os-Linux/mem.c @@ -0,0 +1,161 @@ +#include <stdio.h> +#include <stdlib.h> +#include <stddef.h> +#include <stdarg.h> +#include <unistd.h> +#include <errno.h> +#include <string.h> +#include <fcntl.h> +#include <sys/types.h> +#include <sys/mman.h> +#include "kern_util.h" +#include "user.h" +#include "user_util.h" +#include "mem_user.h" +#include "init.h" +#include "os.h" +#include "tempfile.h" +#include "kern_constants.h" + +#include <sys/param.h> + +static char *tempdir = NULL; + +static void __init find_tempdir(void) +{ + char *dirs[] = { "TMP", "TEMP", "TMPDIR", NULL }; + int i; + char *dir = NULL; + + if(tempdir != NULL) return; /* We've already been called */ + for(i = 0; dirs[i]; i++){ + dir = getenv(dirs[i]); + if((dir != NULL) && (*dir != '\0')) + break; + } + if((dir == NULL) || (*dir == '\0')) + dir = "/tmp"; + + tempdir = malloc(strlen(dir) + 2); + if(tempdir == NULL){ + fprintf(stderr, "Failed to malloc tempdir, " + "errno = %d\n", errno); + return; + } + strcpy(tempdir, dir); + strcat(tempdir, "/"); +} + +/* + * This proc still used in tt-mode + * (file: kernel/tt/ptproxy/proxy.c, proc: start_debugger). + * So it isn't 'static' yet. + */ +int make_tempfile(const char *template, char **out_tempname, int do_unlink) +{ + char tempname[MAXPATHLEN]; + int fd; + + find_tempdir(); + if (*template != '/') + strcpy(tempname, tempdir); + else + *tempname = 0; + strcat(tempname, template); + fd = mkstemp(tempname); + if(fd < 0){ + fprintf(stderr, "open - cannot create %s: %s\n", tempname, + strerror(errno)); + return -1; + } + if(do_unlink && (unlink(tempname) < 0)){ + perror("unlink"); + return -1; + } + if(out_tempname){ + *out_tempname = strdup(tempname); + if(*out_tempname == NULL){ + perror("strdup"); + return -1; + } + } + return(fd); +} + +#define TEMPNAME_TEMPLATE "vm_file-XXXXXX" + +/* + * This proc is used in start_up.c + * So it isn't 'static'. + */ +int create_tmp_file(unsigned long len) +{ + int fd, err; + char zero; + + fd = make_tempfile(TEMPNAME_TEMPLATE, NULL, 1); + if(fd < 0) { + exit(1); + } + + err = fchmod(fd, 0777); + if(err < 0){ + perror("os_mode_fd"); + exit(1); + } + + if (lseek64(fd, len, SEEK_SET) < 0) { + perror("os_seek_file"); + exit(1); + } + + zero = 0; + + err = os_write_file(fd, &zero, 1); + if(err != 1){ + errno = -err; + perror("os_write_file"); + exit(1); + } + + return(fd); +} + +static int create_anon_file(unsigned long len) +{ + void *addr; + int fd; + + fd = open("/dev/anon", O_RDWR); + if(fd < 0) { + perror("opening /dev/anon"); + exit(1); + } + + addr = mmap(NULL, len, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0); + if(addr == MAP_FAILED){ + perror("mapping physmem file"); + exit(1); + } + munmap(addr, len); + + return(fd); +} + +extern int have_devanon; + +int create_mem_file(unsigned long len) +{ + int err, fd; + + if(have_devanon) + fd = create_anon_file(len); + else fd = create_tmp_file(len); + + err = os_set_exec_close(fd, 1); + if(err < 0){ + errno = -err; + perror("exec_close"); + } + return(fd); +} diff --git a/arch/um/os-Linux/process.c b/arch/um/os-Linux/process.c index d32413e..d9c5238 100644 --- a/arch/um/os-Linux/process.c +++ b/arch/um/os-Linux/process.c @@ -3,6 +3,7 @@ * Licensed under the GPL */ +#include <unistd.h> #include <stdio.h> #include <errno.h> #include <signal.h> diff --git a/arch/um/os-Linux/start_up.c b/arch/um/os-Linux/start_up.c index 040cc14..6af8317 100644 --- a/arch/um/os-Linux/start_up.c +++ b/arch/um/os-Linux/start_up.c @@ -4,18 +4,22 @@ */ #include <stdio.h> +#include <stddef.h> +#include <stdarg.h> +#include <stdlib.h> +#include <string.h> #include <unistd.h> #include <signal.h> #include <sched.h> +#include <fcntl.h> #include <errno.h> -#include <stdarg.h> -#include <stdlib.h> #include <setjmp.h> #include <sys/time.h> #include <sys/wait.h> #include <sys/mman.h> #include <asm/unistd.h> #include <asm/page.h> +#include <sys/types.h> #include "user_util.h" #include "kern_util.h" #include "user.h" @@ -25,6 +29,7 @@ #include "sysdep/sigcontext.h" #include "irq_user.h" #include "ptrace_user.h" +#include "mem_user.h" #include "time_user.h" #include "init.h" #include "os.h" @@ -32,6 +37,8 @@ #include "choose-mode.h" #include "mode.h" #include "tempfile.h" +#include "kern_constants.h" + #ifdef UML_CONFIG_MODE_SKAS #include "skas.h" #include "skas_ptrace.h" @@ -276,9 +283,38 @@ static void __init check_ptrace(void) check_sysemu(); } +extern int create_tmp_file(unsigned long len); + +static void check_tmpexec(void) +{ + void *addr; + int err, fd = create_tmp_file(UM_KERN_PAGE_SIZE); + + addr = mmap(NULL, UM_KERN_PAGE_SIZE, + PROT_READ | PROT_WRITE | PROT_EXEC, MAP_PRIVATE, fd, 0); + printf("Checking PROT_EXEC mmap in /tmp..."); + fflush(stdout); + if(addr == MAP_FAILED){ + err = errno; + perror("failed"); + if(err == EPERM) + printf("/tmp must be not mounted noexec\n"); + exit(1); + } + printf("OK\n"); + munmap(addr, UM_KERN_PAGE_SIZE); + + close(fd); +} + void os_early_checks(void) { check_ptrace(); + + /* Need to check this early because mmapping happens before the + * kernel is running. + */ + check_tmpexec(); } static int __init noprocmm_cmd_param(char *str, int* add) @@ -357,3 +393,72 @@ int can_do_skas(void) return(0); } #endif + +int have_devanon = 0; + +void check_devanon(void) +{ + int fd; + + printk("Checking for /dev/anon on the host..."); + fd = open("/dev/anon", O_RDWR); + if(fd < 0){ + printk("Not available (open failed with errno %d)\n", errno); + return; + } + + printk("OK\n"); + have_devanon = 1; +} + +int __init parse_iomem(char *str, int *add) +{ + struct iomem_region *new; + struct uml_stat buf; + char *file, *driver; + int fd, err, size; + + driver = str; + file = strchr(str,','); + if(file == NULL){ + printf("parse_iomem : failed to parse iomem\n"); + goto out; + } + *file = '\0'; + file++; + fd = os_open_file(file, of_rdwr(OPENFLAGS()), 0); + if(fd < 0){ + os_print_error(fd, "parse_iomem - Couldn't open io file"); + goto out; + } + + err = os_stat_fd(fd, &buf); + if(err < 0){ + os_print_error(err, "parse_iomem - cannot stat_fd file"); + goto out_close; + } + + new = malloc(sizeof(*new)); + if(new == NULL){ + perror("Couldn't allocate iomem_region struct"); + goto out_close; + } + + size = (buf.ust_size + UM_KERN_PAGE_SIZE) & ~(UM_KERN_PAGE_SIZE - 1); + + *new = ((struct iomem_region) { .next = iomem_regions, + .driver = driver, + .fd = fd, + .size = size, + .phys = 0, + .virt = 0 }); + iomem_regions = new; + iomem_size += new->size + UM_KERN_PAGE_SIZE; + + return(0); + out_close: + os_close_file(fd); + out: + return(1); +} + diff --git a/arch/um/os-Linux/tt.c b/arch/um/os-Linux/tt.c index 5b047ab..a6db887 100644 --- a/arch/um/os-Linux/tt.c +++ b/arch/um/os-Linux/tt.c @@ -36,6 +36,20 @@ #include "mode.h" #include "tempfile.h" +int protect_memory(unsigned long addr, unsigned long len, int r, int w, int x, + int must_succeed) +{ + int err; + + err = os_protect_memory((void *) addr, len, r, w, x); + if(err < 0){ + if(must_succeed) + panic("protect failed, err = %d", -err); + else return(err); + } + return(0); +} + /* *------------------------- * only for tt mode (will be deleted in future...) diff --git a/arch/um/sys-i386/ldt.c b/arch/um/sys-i386/ldt.c index bd3c34a..36b5c2c 100644 --- a/arch/um/sys-i386/ldt.c +++ b/arch/um/sys-i386/ldt.c @@ -83,6 +83,7 @@ int sys_modify_ldt(int func, void __user *ptr, unsigned long bytecount) goto out; } p = buf; + break; default: res = -ENOSYS; goto out; diff --git a/arch/x86_64/Kconfig b/arch/x86_64/Kconfig index e63323e..21afa69 100644 --- a/arch/x86_64/Kconfig +++ b/arch/x86_64/Kconfig @@ -277,11 +277,6 @@ source "mm/Kconfig" config HAVE_ARCH_EARLY_PFN_TO_NID def_bool y -config HAVE_DEC_LOCK - bool - depends on SMP - default y - config NR_CPUS int "Maximum number of CPUs (2-256)" range 2 256 @@ -313,7 +308,7 @@ config HPET_TIMER present. The HPET provides a stable time base on SMP systems, unlike the TSC, but it is more expensive to access, as it is off-chip. You can find the HPET spec at - <http://www.intel.com/labs/platcomp/hpet/hpetspec.htm>. + <http://www.intel.com/hardwaredesign/hpetspec.htm>. config X86_PM_TIMER bool "PM timer" diff --git a/arch/x86_64/ia32/ia32_binfmt.c b/arch/x86_64/ia32/ia32_binfmt.c index c8131f3..d9161e3 100644 --- a/arch/x86_64/ia32/ia32_binfmt.c +++ b/arch/x86_64/ia32/ia32_binfmt.c @@ -353,11 +353,6 @@ int setup_arg_pages(struct linux_binprm *bprm, unsigned long stack_top, int exec mpnt = kmem_cache_alloc(vm_area_cachep, SLAB_KERNEL); if (!mpnt) return -ENOMEM; - - if (security_vm_enough_memory((IA32_STACK_TOP - (PAGE_MASK & (unsigned long) bprm->p))>>PAGE_SHIFT)) { - kmem_cache_free(vm_area_cachep, mpnt); - return -ENOMEM; - } memset(mpnt, 0, sizeof(*mpnt)); diff --git a/arch/x86_64/ia32/syscall32.c b/arch/x86_64/ia32/syscall32.c index adbc5f8..3a01329 100644 --- a/arch/x86_64/ia32/syscall32.c +++ b/arch/x86_64/ia32/syscall32.c @@ -52,17 +52,13 @@ int syscall32_setup_pages(struct linux_binprm *bprm, int exstack) vma = kmem_cache_alloc(vm_area_cachep, SLAB_KERNEL); if (!vma) return -ENOMEM; - if (security_vm_enough_memory(npages)) { - kmem_cache_free(vm_area_cachep, vma); - return -ENOMEM; - } memset(vma, 0, sizeof(struct vm_area_struct)); /* Could randomize here */ vma->vm_start = VSYSCALL32_BASE; vma->vm_end = VSYSCALL32_END; /* MAYWRITE to allow gdb to COW and set breakpoints */ - vma->vm_flags = VM_READ|VM_EXEC|VM_MAYREAD|VM_MAYEXEC|VM_MAYEXEC|VM_MAYWRITE; + vma->vm_flags = VM_READ|VM_EXEC|VM_MAYREAD|VM_MAYEXEC|VM_MAYWRITE; vma->vm_flags |= mm->def_flags; vma->vm_page_prot = protection_map[vma->vm_flags & 7]; vma->vm_ops = &syscall32_vm_ops; diff --git a/arch/x86_64/kernel/e820.c b/arch/x86_64/kernel/e820.c index eb7929e..ab3f87a 100644 --- a/arch/x86_64/kernel/e820.c +++ b/arch/x86_64/kernel/e820.c @@ -17,6 +17,8 @@ #include <linux/ioport.h> #include <linux/string.h> #include <linux/kexec.h> +#include <linux/module.h> + #include <asm/page.h> #include <asm/e820.h> #include <asm/proto.h> @@ -28,6 +30,7 @@ extern char _end[]; * PFN of last memory page. */ unsigned long end_pfn; +EXPORT_SYMBOL(end_pfn); /* * end_pfn only includes RAM, while end_pfn_map includes all e820 entries. diff --git a/arch/x86_64/kernel/io_apic.c b/arch/x86_64/kernel/io_apic.c index 522944a..c8eee20 100644 --- a/arch/x86_64/kernel/io_apic.c +++ b/arch/x86_64/kernel/io_apic.c @@ -299,15 +299,6 @@ void __init check_ioapic(void) #endif /* RED-PEN skip them on mptables too? */ return; - case PCI_VENDOR_ID_ATI: - /* All timer interrupts on atiixp - are doubled. Disable one. */ - if (disable_timer_pin_1 == 0) { - disable_timer_pin_1 = 1; - printk(KERN_INFO - "ATI board detected. Disabling timer pin 1.\n"); - } - return; } /* No multi-function device? */ diff --git a/arch/x86_64/kernel/mce.c b/arch/x86_64/kernel/mce.c index 969365c..08203b0 100644 --- a/arch/x86_64/kernel/mce.c +++ b/arch/x86_64/kernel/mce.c @@ -217,7 +217,7 @@ void do_machine_check(struct pt_regs * regs, long error_code) panicm_found = 1; } - tainted |= TAINT_MACHINE_CHECK; + add_taint(TAINT_MACHINE_CHECK); } /* Never do anything final in the polling timer */ diff --git a/arch/x86_64/kernel/nmi.c b/arch/x86_64/kernel/nmi.c index 4388b8a5..39d445e 100644 --- a/arch/x86_64/kernel/nmi.c +++ b/arch/x86_64/kernel/nmi.c @@ -366,7 +366,7 @@ static void setup_k7_watchdog(void) | K7_NMI_EVENT; wrmsr(MSR_K7_EVNTSEL0, evntsel, 0); - wrmsr(MSR_K7_PERFCTR0, -(cpu_khz/nmi_hz*1000), -1); + wrmsrl(MSR_K7_PERFCTR0, -((u64)cpu_khz * 1000 / nmi_hz)); apic_write(APIC_LVTPC, APIC_DM_NMI); evntsel |= K7_EVNTSEL_ENABLE; wrmsr(MSR_K7_EVNTSEL0, evntsel, 0); @@ -407,8 +407,8 @@ static int setup_p4_watchdog(void) wrmsr(MSR_P4_CRU_ESCR0, P4_NMI_CRU_ESCR0, 0); wrmsr(MSR_P4_IQ_CCCR0, P4_NMI_IQ_CCCR0 & ~P4_CCCR_ENABLE, 0); - Dprintk("setting P4_IQ_COUNTER0 to 0x%08lx\n", -(cpu_khz/nmi_hz*1000)); - wrmsr(MSR_P4_IQ_COUNTER0, -(cpu_khz/nmi_hz*1000), -1); + Dprintk("setting P4_IQ_COUNTER0 to 0x%08lx\n", -(cpu_khz * 1000UL / nmi_hz)); + wrmsrl(MSR_P4_IQ_COUNTER0, -((u64)cpu_khz * 1000 / nmi_hz)); apic_write(APIC_LVTPC, APIC_DM_NMI); wrmsr(MSR_P4_IQ_CCCR0, nmi_p4_cccr_val, 0); return 1; @@ -506,7 +506,7 @@ void nmi_watchdog_tick (struct pt_regs * regs, unsigned reason) wrmsr(MSR_P4_IQ_CCCR0, nmi_p4_cccr_val, 0); apic_write(APIC_LVTPC, APIC_DM_NMI); } - wrmsr(nmi_perfctr_msr, -(cpu_khz/nmi_hz*1000), -1); + wrmsrl(nmi_perfctr_msr, -((u64)cpu_khz * 1000 / nmi_hz)); } } diff --git a/arch/x86_64/kernel/setup.c b/arch/x86_64/kernel/setup.c index 351d8d6..238f73e 100644 --- a/arch/x86_64/kernel/setup.c +++ b/arch/x86_64/kernel/setup.c @@ -831,11 +831,26 @@ static void __init amd_detect_cmp(struct cpuinfo_x86 *c) #endif } +#define HWCR 0xc0010015 + static int __init init_amd(struct cpuinfo_x86 *c) { int r; int level; +#ifdef CONFIG_SMP + unsigned long value; + + // Disable TLB flush filter by setting HWCR.FFDIS: + // bit 6 of msr C001_0015 + // + // Errata 63 for SH-B3 steppings + // Errata 122 for all(?) steppings + rdmsrl(HWCR, value); + value |= 1 << 6; + wrmsrl(HWCR, value); +#endif + /* Bit 31 in normal CPUID used for nonstandard 3DNow ID; 3DNow is IDd by bit 31 in extended CPUID (1*32+31) anyway */ clear_bit(0*32+31, &c->x86_capability); diff --git a/arch/x86_64/kernel/x8664_ksyms.c b/arch/x86_64/kernel/x8664_ksyms.c index 68ec030..fd99ddd00 100644 --- a/arch/x86_64/kernel/x8664_ksyms.c +++ b/arch/x86_64/kernel/x8664_ksyms.c @@ -178,10 +178,6 @@ EXPORT_SYMBOL(rwsem_down_write_failed_thunk); EXPORT_SYMBOL(empty_zero_page); -#ifdef CONFIG_HAVE_DEC_LOCK -EXPORT_SYMBOL(_atomic_dec_and_lock); -#endif - EXPORT_SYMBOL(die_chain); EXPORT_SYMBOL(register_die_notifier); diff --git a/arch/x86_64/lib/Makefile b/arch/x86_64/lib/Makefile index 6b26a1c..bba5db6 100644 --- a/arch/x86_64/lib/Makefile +++ b/arch/x86_64/lib/Makefile @@ -10,5 +10,3 @@ lib-y := csum-partial.o csum-copy.o csum-wrappers.o delay.o \ usercopy.o getuser.o putuser.o \ thunk.o clear_page.o copy_page.o bitstr.o bitops.o lib-y += memcpy.o memmove.o memset.o copy_user.o - -lib-$(CONFIG_HAVE_DEC_LOCK) += dec_and_lock.o diff --git a/arch/x86_64/lib/dec_and_lock.c b/arch/x86_64/lib/dec_and_lock.c deleted file mode 100644 index ab43394..0000000 --- a/arch/x86_64/lib/dec_and_lock.c +++ /dev/null @@ -1,40 +0,0 @@ -/* - * x86 version of "atomic_dec_and_lock()" using - * the atomic "cmpxchg" instruction. - * - * (For CPU's lacking cmpxchg, we use the slow - * generic version, and this one never even gets - * compiled). - */ - -#include <linux/spinlock.h> -#include <asm/atomic.h> - -int _atomic_dec_and_lock(atomic_t *atomic, spinlock_t *lock) -{ - int counter; - int newcount; - -repeat: - counter = atomic_read(atomic); - newcount = counter-1; - - if (!newcount) - goto slow_path; - - asm volatile("lock; cmpxchgl %1,%2" - :"=a" (newcount) - :"r" (newcount), "m" (atomic->counter), "0" (counter)); - - /* If the above failed, "eax" will have changed */ - if (newcount != counter) - goto repeat; - return 0; - -slow_path: - spin_lock(lock); - if (atomic_dec_and_test(atomic)) - return 1; - spin_unlock(lock); - return 0; -} diff --git a/arch/xtensa/Kconfig b/arch/xtensa/Kconfig index 2b6257b..7e841aa 100644 --- a/arch/xtensa/Kconfig +++ b/arch/xtensa/Kconfig @@ -26,10 +26,6 @@ config RWSEM_XCHGADD_ALGORITHM bool default y -config HAVE_DEC_LOCK - bool - default y - config GENERIC_HARDIRQS bool default y diff --git a/arch/xtensa/kernel/pci.c b/arch/xtensa/kernel/pci.c index 09887c9..de19501 100644 --- a/arch/xtensa/kernel/pci.c +++ b/arch/xtensa/kernel/pci.c @@ -402,8 +402,8 @@ int pci_mmap_page_range(struct pci_dev *dev, struct vm_area_struct *vma, __pci_mmap_set_flags(dev, vma, mmap_state); __pci_mmap_set_pgprot(dev, vma, mmap_state, write_combine); - ret = io_remap_page_range(vma, vma->vm_start, vma->vm_pgoff<<PAGE_SHIFT, - vma->vm_end - vma->vm_start, vma->vm_page_prot); + ret = io_remap_pfn_range(vma, vma->vm_start, vma->vm_pgoff, + vma->vm_end - vma->vm_start,vma->vm_page_prot); return ret; } diff --git a/arch/xtensa/kernel/platform.c b/arch/xtensa/kernel/platform.c index cf13627..03674da 100644 --- a/arch/xtensa/kernel/platform.c +++ b/arch/xtensa/kernel/platform.c @@ -39,7 +39,7 @@ _F(int, pcibios_fixup, (void), { return 0; }); _F(int, get_rtc_time, (time_t* t), { return 0; }); _F(int, set_rtc_time, (time_t t), { return 0; }); -#if CONFIG_XTENSA_CALIBRATE_CCOUNT +#ifdef CONFIG_XTENSA_CALIBRATE_CCOUNT _F(void, calibrate_ccount, (void), { printk ("ERROR: Cannot calibrate cpu frequency! Assuming 100MHz.\n"); diff --git a/arch/xtensa/kernel/process.c b/arch/xtensa/kernel/process.c index c83bb0d..08ef6d8 100644 --- a/arch/xtensa/kernel/process.c +++ b/arch/xtensa/kernel/process.c @@ -457,7 +457,7 @@ int dump_task_fpu(struct pt_regs *regs, struct task_struct *task, elf_fpregset_t *r) { /* see asm/coprocessor.h for this magic number 16 */ -#if TOTAL_CPEXTRA_SIZE > 16 +#if XTENSA_CP_EXTRA_SIZE > 16 do_save_fpregs (r, regs, task); /* For now, bit 16 means some extra state may be present: */ diff --git a/arch/xtensa/kernel/setup.c b/arch/xtensa/kernel/setup.c index 1f5bf5d..513ed8d 100644 --- a/arch/xtensa/kernel/setup.c +++ b/arch/xtensa/kernel/setup.c @@ -304,7 +304,7 @@ void __init setup_arch(char **cmdline_p) # endif #endif -#if CONFIG_PCI +#ifdef CONFIG_PCI platform_pcibios_init(); #endif } diff --git a/arch/xtensa/kernel/signal.c b/arch/xtensa/kernel/signal.c index dc42ced..e252b61 100644 --- a/arch/xtensa/kernel/signal.c +++ b/arch/xtensa/kernel/signal.c @@ -182,7 +182,7 @@ restore_cpextra (struct _cpstate *buf) struct task_struct *tsk = current; release_all_cp(tsk); - return __copy_from_user(tsk->thread.cpextra, buf, TOTAL_CPEXTRA_SIZE); + return __copy_from_user(tsk->thread.cpextra, buf, XTENSA_CP_EXTRA_SIZE); #endif return 0; } diff --git a/arch/xtensa/kernel/time.c b/arch/xtensa/kernel/time.c index 1ac7d5c..8e423d1 100644 --- a/arch/xtensa/kernel/time.c +++ b/arch/xtensa/kernel/time.c @@ -68,7 +68,7 @@ void __init time_init(void) * speed for the CALIBRATE. */ -#if CONFIG_XTENSA_CALIBRATE_CCOUNT +#ifdef CONFIG_XTENSA_CALIBRATE_CCOUNT printk("Calibrating CPU frequency "); platform_calibrate_ccount(); printk("%d.%02d MHz\n", (int)ccount_per_jiffy/(1000000/HZ), diff --git a/arch/xtensa/mm/init.c b/arch/xtensa/mm/init.c index 56aace8..5a91d6c 100644 --- a/arch/xtensa/mm/init.c +++ b/arch/xtensa/mm/init.c @@ -239,7 +239,7 @@ void __init mem_init(void) high_memory = (void *) __va(max_mapnr << PAGE_SHIFT); highmemsize = 0; -#if CONFIG_HIGHMEM +#ifdef CONFIG_HIGHMEM #error HIGHGMEM not implemented in init.c #endif diff --git a/drivers/acorn/char/pcf8583.c b/drivers/acorn/char/pcf8583.c index 141b4c2..2b850e5 100644 --- a/drivers/acorn/char/pcf8583.c +++ b/drivers/acorn/char/pcf8583.c @@ -23,12 +23,13 @@ static struct i2c_driver pcf8583_driver; static unsigned short ignore[] = { I2C_CLIENT_END }; static unsigned short normal_addr[] = { 0x50, I2C_CLIENT_END }; +static unsigned short *forces[] = { NULL }; static struct i2c_client_address_data addr_data = { .normal_i2c = normal_addr, .probe = ignore, .ignore = ignore, - .force = ignore, + .forces = forces, }; #define DAT(x) ((unsigned int)(x->dev.driver_data)) diff --git a/drivers/base/attribute_container.c b/drivers/base/attribute_container.c index 373e7b7..6b2eb6f 100644 --- a/drivers/base/attribute_container.c +++ b/drivers/base/attribute_container.c @@ -152,12 +152,13 @@ attribute_container_add_device(struct device *dev, if (!cont->match(cont, dev)) continue; - ic = kmalloc(sizeof(struct internal_container), GFP_KERNEL); + + ic = kzalloc(sizeof(*ic), GFP_KERNEL); if (!ic) { dev_printk(KERN_ERR, dev, "failed to allocate class container\n"); continue; } - memset(ic, 0, sizeof(struct internal_container)); + ic->cont = cont; class_device_initialize(&ic->classdev); ic->classdev.dev = get_device(dev); diff --git a/drivers/base/class.c b/drivers/base/class.c index d164c32..ce23dc8 100644 --- a/drivers/base/class.c +++ b/drivers/base/class.c @@ -189,12 +189,11 @@ struct class *class_create(struct module *owner, char *name) struct class *cls; int retval; - cls = kmalloc(sizeof(struct class), GFP_KERNEL); + cls = kzalloc(sizeof(*cls), GFP_KERNEL); if (!cls) { retval = -ENOMEM; goto error; } - memset(cls, 0x00, sizeof(struct class)); cls->name = name; cls->owner = owner; @@ -500,13 +499,13 @@ int class_device_add(struct class_device *class_dev) /* add the needed attributes to this device */ if (MAJOR(class_dev->devt)) { struct class_device_attribute *attr; - attr = kmalloc(sizeof(*attr), GFP_KERNEL); + attr = kzalloc(sizeof(*attr), GFP_KERNEL); if (!attr) { error = -ENOMEM; kobject_del(&class_dev->kobj); goto register_done; } - memset(attr, sizeof(*attr), 0x00); + attr->attr.name = "dev"; attr->attr.mode = S_IRUGO; attr->attr.owner = parent->owner; @@ -577,12 +576,11 @@ struct class_device *class_device_create(struct class *cls, dev_t devt, if (cls == NULL || IS_ERR(cls)) goto error; - class_dev = kmalloc(sizeof(struct class_device), GFP_KERNEL); + class_dev = kzalloc(sizeof(*class_dev), GFP_KERNEL); if (!class_dev) { retval = -ENOMEM; goto error; } - memset(class_dev, 0x00, sizeof(struct class_device)); class_dev->devt = devt; class_dev->dev = device; @@ -671,6 +669,7 @@ void class_device_destroy(struct class *cls, dev_t devt) int class_device_rename(struct class_device *class_dev, char *new_name) { int error = 0; + char *old_class_name = NULL, *new_class_name = NULL; class_dev = class_device_get(class_dev); if (!class_dev) @@ -679,12 +678,24 @@ int class_device_rename(struct class_device *class_dev, char *new_name) pr_debug("CLASS: renaming '%s' to '%s'\n", class_dev->class_id, new_name); + if (class_dev->dev) + old_class_name = make_class_name(class_dev); + strlcpy(class_dev->class_id, new_name, KOBJ_NAME_LEN); error = kobject_rename(&class_dev->kobj, new_name); + if (class_dev->dev) { + new_class_name = make_class_name(class_dev); + sysfs_create_link(&class_dev->dev->kobj, &class_dev->kobj, + new_class_name); + sysfs_remove_link(&class_dev->dev->kobj, old_class_name); + } class_device_put(class_dev); + kfree(old_class_name); + kfree(new_class_name); + return error; } diff --git a/drivers/base/dd.c b/drivers/base/dd.c index d5bbce3..3565e97 100644 --- a/drivers/base/dd.c +++ b/drivers/base/dd.c @@ -40,6 +40,9 @@ */ void device_bind_driver(struct device * dev) { + if (klist_node_attached(&dev->knode_driver)) + return; + pr_debug("bound device '%s' to driver '%s'\n", dev->bus_id, dev->driver->name); klist_add_tail(&dev->knode_driver, &dev->driver->klist_devices); diff --git a/drivers/base/firmware_class.c b/drivers/base/firmware_class.c index 5bfa2e9..4acb2c5 100644 --- a/drivers/base/firmware_class.c +++ b/drivers/base/firmware_class.c @@ -301,9 +301,9 @@ fw_register_class_device(struct class_device **class_dev_p, const char *fw_name, struct device *device) { int retval; - struct firmware_priv *fw_priv = kmalloc(sizeof (struct firmware_priv), + struct firmware_priv *fw_priv = kzalloc(sizeof(*fw_priv), GFP_KERNEL); - struct class_device *class_dev = kmalloc(sizeof (struct class_device), + struct class_device *class_dev = kzalloc(sizeof(*class_dev), GFP_KERNEL); *class_dev_p = NULL; @@ -313,8 +313,6 @@ fw_register_class_device(struct class_device **class_dev_p, retval = -ENOMEM; goto error_kfree; } - memset(fw_priv, 0, sizeof (*fw_priv)); - memset(class_dev, 0, sizeof (*class_dev)); init_completion(&fw_priv->completion); fw_priv->attr_data = firmware_attr_data_tmpl; @@ -402,14 +400,13 @@ _request_firmware(const struct firmware **firmware_p, const char *name, if (!firmware_p) return -EINVAL; - *firmware_p = firmware = kmalloc(sizeof (struct firmware), GFP_KERNEL); + *firmware_p = firmware = kzalloc(sizeof(*firmware), GFP_KERNEL); if (!firmware) { printk(KERN_ERR "%s: kmalloc(struct firmware) failed\n", __FUNCTION__); retval = -ENOMEM; goto out; } - memset(firmware, 0, sizeof (*firmware)); retval = fw_setup_class_device(firmware, &class_dev, name, device, hotplug); diff --git a/drivers/base/map.c b/drivers/base/map.c index 2f455d8..b449dae 100644 --- a/drivers/base/map.c +++ b/drivers/base/map.c @@ -135,7 +135,7 @@ retry: struct kobj_map *kobj_map_init(kobj_probe_t *base_probe, struct semaphore *sem) { struct kobj_map *p = kmalloc(sizeof(struct kobj_map), GFP_KERNEL); - struct probe *base = kmalloc(sizeof(struct probe), GFP_KERNEL); + struct probe *base = kzalloc(sizeof(*base), GFP_KERNEL); int i; if ((p == NULL) || (base == NULL)) { @@ -144,7 +144,6 @@ struct kobj_map *kobj_map_init(kobj_probe_t *base_probe, struct semaphore *sem) return NULL; } - memset(base, 0, sizeof(struct probe)); base->dev = 1; base->range = ~0; base->get = base_probe; diff --git a/drivers/base/platform.c b/drivers/base/platform.c index 3a5f4c9..361e204 100644 --- a/drivers/base/platform.c +++ b/drivers/base/platform.c @@ -225,13 +225,12 @@ struct platform_device *platform_device_register_simple(char *name, unsigned int struct platform_object *pobj; int retval; - pobj = kmalloc(sizeof(struct platform_object) + sizeof(struct resource) * num, GFP_KERNEL); + pobj = kzalloc(sizeof(*pobj) + sizeof(struct resource) * num, GFP_KERNEL); if (!pobj) { retval = -ENOMEM; goto error; } - memset(pobj, 0, sizeof(*pobj)); pobj->pdev.name = name; pobj->pdev.id = id; pobj->pdev.dev.release = platform_device_release_simple; diff --git a/drivers/block/cciss.c b/drivers/block/cciss.c index 28f2c17..486b6e1 100644 --- a/drivers/block/cciss.c +++ b/drivers/block/cciss.c @@ -47,14 +47,14 @@ #include <linux/completion.h> #define CCISS_DRIVER_VERSION(maj,min,submin) ((maj<<16)|(min<<8)|(submin)) -#define DRIVER_NAME "HP CISS Driver (v 2.6.6)" -#define DRIVER_VERSION CCISS_DRIVER_VERSION(2,6,6) +#define DRIVER_NAME "HP CISS Driver (v 2.6.8)" +#define DRIVER_VERSION CCISS_DRIVER_VERSION(2,6,8) /* Embedded module documentation macros - see modules.h */ MODULE_AUTHOR("Hewlett-Packard Company"); -MODULE_DESCRIPTION("Driver for HP Controller SA5xxx SA6xxx version 2.6.6"); +MODULE_DESCRIPTION("Driver for HP Controller SA5xxx SA6xxx version 2.6.8"); MODULE_SUPPORTED_DEVICE("HP SA5i SA5i+ SA532 SA5300 SA5312 SA641 SA642 SA6400" - " SA6i P600 P800 E400 E300"); + " SA6i P600 P800 P400 P400i E200 E200i"); MODULE_LICENSE("GPL"); #include "cciss_cmd.h" @@ -83,12 +83,22 @@ static const struct pci_device_id cciss_pci_device_id[] = { 0x0E11, 0x4091, 0, 0, 0}, { PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSA, 0x103C, 0x3225, 0, 0, 0}, - { PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSB, + { PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSC, 0x103c, 0x3223, 0, 0, 0}, { PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSC, - 0x103c, 0x3231, 0, 0, 0}, + 0x103c, 0x3234, 0, 0, 0}, { PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSC, - 0x103c, 0x3233, 0, 0, 0}, + 0x103c, 0x3235, 0, 0, 0}, + { PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSD, + 0x103c, 0x3211, 0, 0, 0}, + { PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSD, + 0x103c, 0x3212, 0, 0, 0}, + { PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSD, + 0x103c, 0x3213, 0, 0, 0}, + { PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSD, + 0x103c, 0x3214, 0, 0, 0}, + { PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSD, + 0x103c, 0x3215, 0, 0, 0}, {0,} }; MODULE_DEVICE_TABLE(pci, cciss_pci_device_id); @@ -111,8 +121,13 @@ static struct board_type products[] = { { 0x40910E11, "Smart Array 6i", &SA5_access}, { 0x3225103C, "Smart Array P600", &SA5_access}, { 0x3223103C, "Smart Array P800", &SA5_access}, - { 0x3231103C, "Smart Array E400", &SA5_access}, - { 0x3233103C, "Smart Array E300", &SA5_access}, + { 0x3234103C, "Smart Array P400", &SA5_access}, + { 0x3235103C, "Smart Array P400i", &SA5_access}, + { 0x3211103C, "Smart Array E200i", &SA5_access}, + { 0x3212103C, "Smart Array E200", &SA5_access}, + { 0x3213103C, "Smart Array E200i", &SA5_access}, + { 0x3214103C, "Smart Array E200i", &SA5_access}, + { 0x3215103C, "Smart Array E200i", &SA5_access}, }; /* How long to wait (in millesconds) for board to go into simple mode */ @@ -140,15 +155,26 @@ static int cciss_ioctl(struct inode *inode, struct file *filep, static int revalidate_allvol(ctlr_info_t *host); static int cciss_revalidate(struct gendisk *disk); -static int deregister_disk(struct gendisk *disk); -static int register_new_disk(ctlr_info_t *h); +static int rebuild_lun_table(ctlr_info_t *h, struct gendisk *del_disk); +static int deregister_disk(struct gendisk *disk, drive_info_struct *drv, int clear_all); +static void cciss_read_capacity(int ctlr, int logvol, ReadCapdata_struct *buf, + int withirq, unsigned int *total_size, unsigned int *block_size); +static void cciss_geometry_inquiry(int ctlr, int logvol, + int withirq, unsigned int total_size, + unsigned int block_size, InquiryData_struct *inq_buff, + drive_info_struct *drv); static void cciss_getgeometry(int cntl_num); static void start_io( ctlr_info_t *h); static int sendcmd( __u8 cmd, int ctlr, void *buff, size_t size, unsigned int use_unit_num, unsigned int log_unit, __u8 page_code, unsigned char *scsi3addr, int cmd_type); +static int sendcmd_withirq(__u8 cmd, int ctlr, void *buff, size_t size, + unsigned int use_unit_num, unsigned int log_unit, __u8 page_code, + int cmd_type); + +static void fail_all_cmds(unsigned long ctlr); #ifdef CONFIG_PROC_FS static int cciss_proc_get_info(char *buffer, char **start, off_t offset, @@ -265,7 +291,7 @@ static int cciss_proc_get_info(char *buffer, char **start, off_t offset, for(i=0; i<=h->highest_lun; i++) { drv = &h->drv[i]; - if (drv->block_size == 0) + if (drv->heads == 0) continue; vol_sz = drv->nr_blocks; @@ -363,6 +389,8 @@ static CommandList_struct * cmd_alloc(ctlr_info_t *h, int get_from_pool) return NULL; memset(c, 0, sizeof(CommandList_struct)); + c->cmdindex = -1; + c->err_info = (ErrorInfo_struct *)pci_alloc_consistent( h->pdev, sizeof(ErrorInfo_struct), &err_dma_handle); @@ -393,6 +421,8 @@ static CommandList_struct * cmd_alloc(ctlr_info_t *h, int get_from_pool) err_dma_handle = h->errinfo_pool_dhandle + i*sizeof(ErrorInfo_struct); h->nr_allocs++; + + c->cmdindex = i; } c->busaddr = (__u32) cmd_dma_handle; @@ -453,6 +483,8 @@ static int cciss_open(struct inode *inode, struct file *filep) printk(KERN_DEBUG "cciss_open %s\n", inode->i_bdev->bd_disk->disk_name); #endif /* CCISS_DEBUG */ + if (host->busy_initializing || drv->busy_configuring) + return -EBUSY; /* * Root is allowed to open raw volume zero even if it's not configured * so array config can still work. Root is also allowed to open any @@ -796,10 +828,10 @@ static int cciss_ioctl(struct inode *inode, struct file *filep, return(0); } case CCISS_DEREGDISK: - return deregister_disk(disk); + return rebuild_lun_table(host, disk); case CCISS_REGNEWD: - return register_new_disk(host); + return rebuild_lun_table(host, NULL); case CCISS_PASSTHRU: { @@ -1143,48 +1175,323 @@ static int revalidate_allvol(ctlr_info_t *host) return 0; } -static int deregister_disk(struct gendisk *disk) +/* This function will check the usage_count of the drive to be updated/added. + * If the usage_count is zero then the drive information will be updated and + * the disk will be re-registered with the kernel. If not then it will be + * left alone for the next reboot. The exception to this is disk 0 which + * will always be left registered with the kernel since it is also the + * controller node. Any changes to disk 0 will show up on the next + * reboot. +*/ +static void cciss_update_drive_info(int ctlr, int drv_index) + { + ctlr_info_t *h = hba[ctlr]; + struct gendisk *disk; + ReadCapdata_struct *size_buff = NULL; + InquiryData_struct *inq_buff = NULL; + unsigned int block_size; + unsigned int total_size; + unsigned long flags = 0; + int ret = 0; + + /* if the disk already exists then deregister it before proceeding*/ + if (h->drv[drv_index].raid_level != -1){ + spin_lock_irqsave(CCISS_LOCK(h->ctlr), flags); + h->drv[drv_index].busy_configuring = 1; + spin_unlock_irqrestore(CCISS_LOCK(h->ctlr), flags); + ret = deregister_disk(h->gendisk[drv_index], + &h->drv[drv_index], 0); + h->drv[drv_index].busy_configuring = 0; + } + + /* If the disk is in use return */ + if (ret) + return; + + + /* Get information about the disk and modify the driver sturcture */ + size_buff = kmalloc(sizeof( ReadCapdata_struct), GFP_KERNEL); + if (size_buff == NULL) + goto mem_msg; + inq_buff = kmalloc(sizeof( InquiryData_struct), GFP_KERNEL); + if (inq_buff == NULL) + goto mem_msg; + + cciss_read_capacity(ctlr, drv_index, size_buff, 1, + &total_size, &block_size); + cciss_geometry_inquiry(ctlr, drv_index, 1, total_size, block_size, + inq_buff, &h->drv[drv_index]); + + ++h->num_luns; + disk = h->gendisk[drv_index]; + set_capacity(disk, h->drv[drv_index].nr_blocks); + + + /* if it's the controller it's already added */ + if (drv_index){ + disk->queue = blk_init_queue(do_cciss_request, &h->lock); + + /* Set up queue information */ + disk->queue->backing_dev_info.ra_pages = READ_AHEAD; + blk_queue_bounce_limit(disk->queue, hba[ctlr]->pdev->dma_mask); + + /* This is a hardware imposed limit. */ + blk_queue_max_hw_segments(disk->queue, MAXSGENTRIES); + + /* This is a limit in the driver and could be eliminated. */ + blk_queue_max_phys_segments(disk->queue, MAXSGENTRIES); + + blk_queue_max_sectors(disk->queue, 512); + + disk->queue->queuedata = hba[ctlr]; + + blk_queue_hardsect_size(disk->queue, + hba[ctlr]->drv[drv_index].block_size); + + h->drv[drv_index].queue = disk->queue; + add_disk(disk); + } + +freeret: + kfree(size_buff); + kfree(inq_buff); + return; +mem_msg: + printk(KERN_ERR "cciss: out of memory\n"); + goto freeret; +} + +/* This function will find the first index of the controllers drive array + * that has a -1 for the raid_level and will return that index. This is + * where new drives will be added. If the index to be returned is greater + * than the highest_lun index for the controller then highest_lun is set + * to this new index. If there are no available indexes then -1 is returned. +*/ +static int cciss_find_free_drive_index(int ctlr) { + int i; + + for (i=0; i < CISS_MAX_LUN; i++){ + if (hba[ctlr]->drv[i].raid_level == -1){ + if (i > hba[ctlr]->highest_lun) + hba[ctlr]->highest_lun = i; + return i; + } + } + return -1; +} + +/* This function will add and remove logical drives from the Logical + * drive array of the controller and maintain persistancy of ordering + * so that mount points are preserved until the next reboot. This allows + * for the removal of logical drives in the middle of the drive array + * without a re-ordering of those drives. + * INPUT + * h = The controller to perform the operations on + * del_disk = The disk to remove if specified. If the value given + * is NULL then no disk is removed. +*/ +static int rebuild_lun_table(ctlr_info_t *h, struct gendisk *del_disk) +{ + int ctlr = h->ctlr; + int num_luns; + ReportLunData_struct *ld_buff = NULL; + drive_info_struct *drv = NULL; + int return_code; + int listlength = 0; + int i; + int drv_found; + int drv_index = 0; + __u32 lunid = 0; unsigned long flags; + + /* Set busy_configuring flag for this operation */ + spin_lock_irqsave(CCISS_LOCK(h->ctlr), flags); + if (h->num_luns >= CISS_MAX_LUN){ + spin_unlock_irqrestore(CCISS_LOCK(h->ctlr), flags); + return -EINVAL; + } + + if (h->busy_configuring){ + spin_unlock_irqrestore(CCISS_LOCK(h->ctlr), flags); + return -EBUSY; + } + h->busy_configuring = 1; + + /* if del_disk is NULL then we are being called to add a new disk + * and update the logical drive table. If it is not NULL then + * we will check if the disk is in use or not. + */ + if (del_disk != NULL){ + drv = get_drv(del_disk); + drv->busy_configuring = 1; + spin_unlock_irqrestore(CCISS_LOCK(h->ctlr), flags); + return_code = deregister_disk(del_disk, drv, 1); + drv->busy_configuring = 0; + h->busy_configuring = 0; + return return_code; + } else { + spin_unlock_irqrestore(CCISS_LOCK(h->ctlr), flags); + if (!capable(CAP_SYS_RAWIO)) + return -EPERM; + + ld_buff = kzalloc(sizeof(ReportLunData_struct), GFP_KERNEL); + if (ld_buff == NULL) + goto mem_msg; + + return_code = sendcmd_withirq(CISS_REPORT_LOG, ctlr, ld_buff, + sizeof(ReportLunData_struct), 0, 0, 0, + TYPE_CMD); + + if (return_code == IO_OK){ + listlength |= (0xff & (unsigned int)(ld_buff->LUNListLength[0])) << 24; + listlength |= (0xff & (unsigned int)(ld_buff->LUNListLength[1])) << 16; + listlength |= (0xff & (unsigned int)(ld_buff->LUNListLength[2])) << 8; + listlength |= 0xff & (unsigned int)(ld_buff->LUNListLength[3]); + } else{ /* reading number of logical volumes failed */ + printk(KERN_WARNING "cciss: report logical volume" + " command failed\n"); + listlength = 0; + goto freeret; + } + + num_luns = listlength / 8; /* 8 bytes per entry */ + if (num_luns > CISS_MAX_LUN){ + num_luns = CISS_MAX_LUN; + printk(KERN_WARNING "cciss: more luns configured" + " on controller than can be handled by" + " this driver.\n"); + } + + /* Compare controller drive array to drivers drive array. + * Check for updates in the drive information and any new drives + * on the controller. + */ + for (i=0; i < num_luns; i++){ + int j; + + drv_found = 0; + + lunid = (0xff & + (unsigned int)(ld_buff->LUN[i][3])) << 24; + lunid |= (0xff & + (unsigned int)(ld_buff->LUN[i][2])) << 16; + lunid |= (0xff & + (unsigned int)(ld_buff->LUN[i][1])) << 8; + lunid |= 0xff & + (unsigned int)(ld_buff->LUN[i][0]); + + /* Find if the LUN is already in the drive array + * of the controller. If so then update its info + * if not is use. If it does not exist then find + * the first free index and add it. + */ + for (j=0; j <= h->highest_lun; j++){ + if (h->drv[j].LunID == lunid){ + drv_index = j; + drv_found = 1; + } + } + + /* check if the drive was found already in the array */ + if (!drv_found){ + drv_index = cciss_find_free_drive_index(ctlr); + if (drv_index == -1) + goto freeret; + + } + h->drv[drv_index].LunID = lunid; + cciss_update_drive_info(ctlr, drv_index); + } /* end for */ + } /* end else */ + +freeret: + kfree(ld_buff); + h->busy_configuring = 0; + /* We return -1 here to tell the ACU that we have registered/updated + * all of the drives that we can and to keep it from calling us + * additional times. + */ + return -1; +mem_msg: + printk(KERN_ERR "cciss: out of memory\n"); + goto freeret; +} + +/* This function will deregister the disk and it's queue from the + * kernel. It must be called with the controller lock held and the + * drv structures busy_configuring flag set. It's parameters are: + * + * disk = This is the disk to be deregistered + * drv = This is the drive_info_struct associated with the disk to be + * deregistered. It contains information about the disk used + * by the driver. + * clear_all = This flag determines whether or not the disk information + * is going to be completely cleared out and the highest_lun + * reset. Sometimes we want to clear out information about + * the disk in preperation for re-adding it. In this case + * the highest_lun should be left unchanged and the LunID + * should not be cleared. +*/ +static int deregister_disk(struct gendisk *disk, drive_info_struct *drv, + int clear_all) +{ ctlr_info_t *h = get_host(disk); - drive_info_struct *drv = get_drv(disk); - int ctlr = h->ctlr; if (!capable(CAP_SYS_RAWIO)) return -EPERM; - spin_lock_irqsave(CCISS_LOCK(ctlr), flags); /* make sure logical volume is NOT is use */ - if( drv->usage_count > 1) { - spin_unlock_irqrestore(CCISS_LOCK(ctlr), flags); + if(clear_all || (h->gendisk[0] == disk)) { + if (drv->usage_count > 1) return -EBUSY; } - drv->usage_count++; - spin_unlock_irqrestore(CCISS_LOCK(ctlr), flags); + else + if( drv->usage_count > 0 ) + return -EBUSY; - /* invalidate the devices and deregister the disk */ - if (disk->flags & GENHD_FL_UP) + /* invalidate the devices and deregister the disk. If it is disk + * zero do not deregister it but just zero out it's values. This + * allows us to delete disk zero but keep the controller registered. + */ + if (h->gendisk[0] != disk){ + if (disk->flags & GENHD_FL_UP){ + blk_cleanup_queue(disk->queue); del_gendisk(disk); + drv->queue = NULL; + } + } + + --h->num_luns; + /* zero out the disk size info */ + drv->nr_blocks = 0; + drv->block_size = 0; + drv->heads = 0; + drv->sectors = 0; + drv->cylinders = 0; + drv->raid_level = -1; /* This can be used as a flag variable to + * indicate that this element of the drive + * array is free. + */ + + if (clear_all){ /* check to see if it was the last disk */ if (drv == h->drv + h->highest_lun) { /* if so, find the new hightest lun */ int i, newhighest =-1; for(i=0; i<h->highest_lun; i++) { /* if the disk has size > 0, it is available */ - if (h->drv[i].nr_blocks) + if (h->drv[i].heads) newhighest = i; } h->highest_lun = newhighest; - } - --h->num_luns; - /* zero out the disk size info */ - drv->nr_blocks = 0; - drv->block_size = 0; - drv->cylinders = 0; + drv->LunID = 0; + } return(0); } + static int fill_cmd(CommandList_struct *c, __u8 cmd, int ctlr, void *buff, size_t size, unsigned int use_unit_num, /* 0: address the controller, @@ -1420,8 +1727,10 @@ case CMD_HARDWARE_ERR: } } /* unlock the buffers from DMA */ + buff_dma_handle.val32.lower = c->SG[0].Addr.lower; + buff_dma_handle.val32.upper = c->SG[0].Addr.upper; pci_unmap_single( h->pdev, (dma_addr_t) buff_dma_handle.val, - size, PCI_DMA_BIDIRECTIONAL); + c->SG[0].Len, PCI_DMA_BIDIRECTIONAL); cmd_free(h, c, 0); return(return_status); @@ -1495,164 +1804,6 @@ cciss_read_capacity(int ctlr, int logvol, ReadCapdata_struct *buf, return; } -static int register_new_disk(ctlr_info_t *h) -{ - struct gendisk *disk; - int ctlr = h->ctlr; - int i; - int num_luns; - int logvol; - int new_lun_found = 0; - int new_lun_index = 0; - int free_index_found = 0; - int free_index = 0; - ReportLunData_struct *ld_buff = NULL; - ReadCapdata_struct *size_buff = NULL; - InquiryData_struct *inq_buff = NULL; - int return_code; - int listlength = 0; - __u32 lunid = 0; - unsigned int block_size; - unsigned int total_size; - - if (!capable(CAP_SYS_RAWIO)) - return -EPERM; - /* if we have no space in our disk array left to add anything */ - if( h->num_luns >= CISS_MAX_LUN) - return -EINVAL; - - ld_buff = kmalloc(sizeof(ReportLunData_struct), GFP_KERNEL); - if (ld_buff == NULL) - goto mem_msg; - memset(ld_buff, 0, sizeof(ReportLunData_struct)); - size_buff = kmalloc(sizeof( ReadCapdata_struct), GFP_KERNEL); - if (size_buff == NULL) - goto mem_msg; - inq_buff = kmalloc(sizeof( InquiryData_struct), GFP_KERNEL); - if (inq_buff == NULL) - goto mem_msg; - - return_code = sendcmd_withirq(CISS_REPORT_LOG, ctlr, ld_buff, - sizeof(ReportLunData_struct), 0, 0, 0, TYPE_CMD); - - if( return_code == IO_OK) - { - - // printk("LUN Data\n--------------------------\n"); - - listlength |= (0xff & (unsigned int)(ld_buff->LUNListLength[0])) << 24; - listlength |= (0xff & (unsigned int)(ld_buff->LUNListLength[1])) << 16; - listlength |= (0xff & (unsigned int)(ld_buff->LUNListLength[2])) << 8; - listlength |= 0xff & (unsigned int)(ld_buff->LUNListLength[3]); - } else /* reading number of logical volumes failed */ - { - printk(KERN_WARNING "cciss: report logical volume" - " command failed\n"); - listlength = 0; - goto free_err; - } - num_luns = listlength / 8; // 8 bytes pre entry - if (num_luns > CISS_MAX_LUN) - { - num_luns = CISS_MAX_LUN; - } -#ifdef CCISS_DEBUG - printk(KERN_DEBUG "Length = %x %x %x %x = %d\n", ld_buff->LUNListLength[0], - ld_buff->LUNListLength[1], ld_buff->LUNListLength[2], - ld_buff->LUNListLength[3], num_luns); -#endif - for(i=0; i< num_luns; i++) - { - int j; - int lunID_found = 0; - - lunid = (0xff & (unsigned int)(ld_buff->LUN[i][3])) << 24; - lunid |= (0xff & (unsigned int)(ld_buff->LUN[i][2])) << 16; - lunid |= (0xff & (unsigned int)(ld_buff->LUN[i][1])) << 8; - lunid |= 0xff & (unsigned int)(ld_buff->LUN[i][0]); - - /* check to see if this is a new lun */ - for(j=0; j <= h->highest_lun; j++) - { -#ifdef CCISS_DEBUG - printk("Checking %d %x against %x\n", j,h->drv[j].LunID, - lunid); -#endif /* CCISS_DEBUG */ - if (h->drv[j].LunID == lunid) - { - lunID_found = 1; - break; - } - - } - if( lunID_found == 1) - continue; - else - { /* It is the new lun we have been looking for */ -#ifdef CCISS_DEBUG - printk("new lun found at %d\n", i); -#endif /* CCISS_DEBUG */ - new_lun_index = i; - new_lun_found = 1; - break; - } - } - if (!new_lun_found) - { - printk(KERN_WARNING "cciss: New Logical Volume not found\n"); - goto free_err; - } - /* Now find the free index */ - for(i=0; i <CISS_MAX_LUN; i++) - { -#ifdef CCISS_DEBUG - printk("Checking Index %d\n", i); -#endif /* CCISS_DEBUG */ - if(h->drv[i].LunID == 0) - { -#ifdef CCISS_DEBUG - printk("free index found at %d\n", i); -#endif /* CCISS_DEBUG */ - free_index_found = 1; - free_index = i; - break; - } - } - if (!free_index_found) - { - printk(KERN_WARNING "cciss: unable to find free slot for disk\n"); - goto free_err; - } - - logvol = free_index; - h->drv[logvol].LunID = lunid; - /* there could be gaps in lun numbers, track hightest */ - if(h->highest_lun < lunid) - h->highest_lun = logvol; - cciss_read_capacity(ctlr, logvol, size_buff, 1, - &total_size, &block_size); - cciss_geometry_inquiry(ctlr, logvol, 1, total_size, block_size, - inq_buff, &h->drv[logvol]); - h->drv[logvol].usage_count = 0; - ++h->num_luns; - /* setup partitions per disk */ - disk = h->gendisk[logvol]; - set_capacity(disk, h->drv[logvol].nr_blocks); - /* if it's the controller it's already added */ - if(logvol) - add_disk(disk); -freeret: - kfree(ld_buff); - kfree(size_buff); - kfree(inq_buff); - return (logvol); -mem_msg: - printk(KERN_ERR "cciss: out of memory\n"); -free_err: - logvol = -1; - goto freeret; -} - static int cciss_revalidate(struct gendisk *disk) { ctlr_info_t *h = get_host(disk); @@ -1859,8 +2010,10 @@ resend_cmd1: cleanup1: /* unlock the data buffer from DMA */ + buff_dma_handle.val32.lower = c->SG[0].Addr.lower; + buff_dma_handle.val32.upper = c->SG[0].Addr.upper; pci_unmap_single(info_p->pdev, (dma_addr_t) buff_dma_handle.val, - size, PCI_DMA_BIDIRECTIONAL); + c->SG[0].Len, PCI_DMA_BIDIRECTIONAL); cmd_free(info_p, c, 1); return (status); } @@ -2111,7 +2264,11 @@ queue: /* fill in the request */ drv = creq->rq_disk->private_data; c->Header.ReplyQueue = 0; // unused in simple mode - c->Header.Tag.lower = c->busaddr; // use the physical address the cmd block for tag + /* got command from pool, so use the command block index instead */ + /* for direct lookups. */ + /* The first 2 bits are reserved for controller error reporting. */ + c->Header.Tag.lower = (c->cmdindex << 3); + c->Header.Tag.lower |= 0x04; /* flag for direct lookup. */ c->Header.LUN.LogDev.VolId= drv->LunID; c->Header.LUN.LogDev.Mode = 1; c->Request.CDBLen = 10; // 12 byte commands not in FW yet; @@ -2186,7 +2343,7 @@ static irqreturn_t do_cciss_intr(int irq, void *dev_id, struct pt_regs *regs) ctlr_info_t *h = dev_id; CommandList_struct *c; unsigned long flags; - __u32 a, a1; + __u32 a, a1, a2; int j; int start_queue = h->next_to_run; @@ -2204,10 +2361,21 @@ static irqreturn_t do_cciss_intr(int irq, void *dev_id, struct pt_regs *regs) while((a = h->access.command_completed(h)) != FIFO_EMPTY) { a1 = a; + if ((a & 0x04)) { + a2 = (a >> 3); + if (a2 >= NR_CMDS) { + printk(KERN_WARNING "cciss: controller cciss%d failed, stopping.\n", h->ctlr); + fail_all_cmds(h->ctlr); + return IRQ_HANDLED; + } + + c = h->cmd_pool + a2; + a = c->busaddr; + + } else { a &= ~3; - if ((c = h->cmpQ) == NULL) - { - printk(KERN_WARNING "cciss: Completion of %08lx ignored\n", (unsigned long)a1); + if ((c = h->cmpQ) == NULL) { + printk(KERN_WARNING "cciss: Completion of %08x ignored\n", a1); continue; } while(c->busaddr != a) { @@ -2215,6 +2383,7 @@ static irqreturn_t do_cciss_intr(int irq, void *dev_id, struct pt_regs *regs) if (c == h->cmpQ) break; } + } /* * If we've found the command, take it off the * completion Q and free it @@ -2634,12 +2803,16 @@ static void cciss_getgeometry(int cntl_num) #endif /* CCISS_DEBUG */ hba[cntl_num]->highest_lun = hba[cntl_num]->num_luns-1; - for(i=0; i< hba[cntl_num]->num_luns; i++) +// for(i=0; i< hba[cntl_num]->num_luns; i++) + for(i=0; i < CISS_MAX_LUN; i++) { - - lunid = (0xff & (unsigned int)(ld_buff->LUN[i][3])) << 24; - lunid |= (0xff & (unsigned int)(ld_buff->LUN[i][2])) << 16; - lunid |= (0xff & (unsigned int)(ld_buff->LUN[i][1])) << 8; + if (i < hba[cntl_num]->num_luns){ + lunid = (0xff & (unsigned int)(ld_buff->LUN[i][3])) + << 24; + lunid |= (0xff & (unsigned int)(ld_buff->LUN[i][2])) + << 16; + lunid |= (0xff & (unsigned int)(ld_buff->LUN[i][1])) + << 8; lunid |= 0xff & (unsigned int)(ld_buff->LUN[i][0]); hba[cntl_num]->drv[i].LunID = lunid; @@ -2647,13 +2820,18 @@ static void cciss_getgeometry(int cntl_num) #ifdef CCISS_DEBUG printk(KERN_DEBUG "LUN[%d]: %x %x %x %x = %x\n", i, - ld_buff->LUN[i][0], ld_buff->LUN[i][1],ld_buff->LUN[i][2], - ld_buff->LUN[i][3], hba[cntl_num]->drv[i].LunID); + ld_buff->LUN[i][0], ld_buff->LUN[i][1], + ld_buff->LUN[i][2], ld_buff->LUN[i][3], + hba[cntl_num]->drv[i].LunID); #endif /* CCISS_DEBUG */ cciss_read_capacity(cntl_num, i, size_buff, 0, &total_size, &block_size); - cciss_geometry_inquiry(cntl_num, i, 0, total_size, block_size, - inq_buff, &hba[cntl_num]->drv[i]); + cciss_geometry_inquiry(cntl_num, i, 0, total_size, + block_size, inq_buff, &hba[cntl_num]->drv[i]); + } else { + /* initialize raid_level to indicate a free space */ + hba[cntl_num]->drv[i].raid_level = -1; + } } kfree(ld_buff); kfree(size_buff); @@ -2727,6 +2905,9 @@ static int __devinit cciss_init_one(struct pci_dev *pdev, i = alloc_cciss_hba(); if(i < 0) return (-1); + + hba[i]->busy_initializing = 1; + if (cciss_pci_init(hba[i], pdev) != 0) goto clean1; @@ -2807,6 +2988,7 @@ static int __devinit cciss_init_one(struct pci_dev *pdev, hba[i]->access.set_intr_mask(hba[i], CCISS_INTR_ON); cciss_procinit(i); + hba[i]->busy_initializing = 0; for(j=0; j < NWD; j++) { /* mfm */ drive_info_struct *drv = &(hba[i]->drv[j]); @@ -2869,6 +3051,7 @@ clean2: clean1: release_io_mem(hba[i]); free_hba(i); + hba[i]->busy_initializing = 0; return(-1); } @@ -2913,9 +3096,10 @@ static void __devexit cciss_remove_one (struct pci_dev *pdev) /* remove it from the disk list */ for (j = 0; j < NWD; j++) { struct gendisk *disk = hba[i]->gendisk[j]; - if (disk->flags & GENHD_FL_UP) - blk_cleanup_queue(disk->queue); + if (disk->flags & GENHD_FL_UP) { del_gendisk(disk); + blk_cleanup_queue(disk->queue); + } } pci_free_consistent(hba[i]->pdev, NR_CMDS * sizeof(CommandList_struct), @@ -2964,5 +3148,43 @@ static void __exit cciss_cleanup(void) remove_proc_entry("cciss", proc_root_driver); } +static void fail_all_cmds(unsigned long ctlr) +{ + /* If we get here, the board is apparently dead. */ + ctlr_info_t *h = hba[ctlr]; + CommandList_struct *c; + unsigned long flags; + + printk(KERN_WARNING "cciss%d: controller not responding.\n", h->ctlr); + h->alive = 0; /* the controller apparently died... */ + + spin_lock_irqsave(CCISS_LOCK(ctlr), flags); + + pci_disable_device(h->pdev); /* Make sure it is really dead. */ + + /* move everything off the request queue onto the completed queue */ + while( (c = h->reqQ) != NULL ) { + removeQ(&(h->reqQ), c); + h->Qdepth--; + addQ (&(h->cmpQ), c); + } + + /* Now, fail everything on the completed queue with a HW error */ + while( (c = h->cmpQ) != NULL ) { + removeQ(&h->cmpQ, c); + c->err_info->CommandStatus = CMD_HARDWARE_ERR; + if (c->cmd_type == CMD_RWREQ) { + complete_command(h, c, 0); + } else if (c->cmd_type == CMD_IOCTL_PEND) + complete(c->waiting); +#ifdef CONFIG_CISS_SCSI_TAPE + else if (c->cmd_type == CMD_SCSI) + complete_scsi_command(c, 0, 0); +#endif + } + spin_unlock_irqrestore(CCISS_LOCK(ctlr), flags); + return; +} + module_init(cciss_init); module_exit(cciss_cleanup); diff --git a/drivers/block/cciss.h b/drivers/block/cciss.h index 566587d..ef277ba 100644 --- a/drivers/block/cciss.h +++ b/drivers/block/cciss.h @@ -35,7 +35,13 @@ typedef struct _drive_info_struct int heads; int sectors; int cylinders; - int raid_level; + int raid_level; /* set to -1 to indicate that + * the drive is not in use/configured + */ + int busy_configuring; /*This is set when the drive is being removed + *to prevent it from being opened or it's queue + *from being started. + */ } drive_info_struct; struct ctlr_info @@ -83,6 +89,7 @@ struct ctlr_info int nr_allocs; int nr_frees; int busy_configuring; + int busy_initializing; /* This element holds the zero based queue number of the last * queue to be started. It is used for fairness. @@ -94,6 +101,7 @@ struct ctlr_info #ifdef CONFIG_CISS_SCSI_TAPE void *scsi_ctlr; /* ptr to structure containing scsi related stuff */ #endif + unsigned char alive; }; /* Defining the diffent access_menthods */ diff --git a/drivers/block/cciss_cmd.h b/drivers/block/cciss_cmd.h index a88a888..53fea54 100644 --- a/drivers/block/cciss_cmd.h +++ b/drivers/block/cciss_cmd.h @@ -226,6 +226,10 @@ typedef struct _ErrorInfo_struct { #define CMD_MSG_DONE 0x04 #define CMD_MSG_TIMEOUT 0x05 +/* This structure needs to be divisible by 8 for new + * indexing method. + */ +#define PADSIZE (sizeof(long) - 4) typedef struct _CommandList_struct { CommandListHeader_struct Header; RequestBlock_struct Request; @@ -236,14 +240,14 @@ typedef struct _CommandList_struct { ErrorInfo_struct * err_info; /* pointer to the allocated mem */ int ctlr; int cmd_type; + long cmdindex; struct _CommandList_struct *prev; struct _CommandList_struct *next; struct request * rq; struct completion *waiting; int retry_count; -#ifdef CONFIG_CISS_SCSI_TAPE void * scsi_cmd; -#endif + char pad[PADSIZE]; } CommandList_struct; //Configuration Table Structure diff --git a/drivers/block/cciss_scsi.c b/drivers/block/cciss_scsi.c index f16e3ca..e183a3e 100644 --- a/drivers/block/cciss_scsi.c +++ b/drivers/block/cciss_scsi.c @@ -93,6 +93,7 @@ struct cciss_scsi_cmd_stack_elem_t { CommandList_struct cmd; ErrorInfo_struct Err; __u32 busaddr; + __u32 pad; }; #pragma pack() @@ -877,7 +878,7 @@ cciss_scsi_interpret_error(CommandList_struct *cp) static int cciss_scsi_do_inquiry(ctlr_info_t *c, unsigned char *scsi3addr, - InquiryData_struct *buf) + unsigned char *buf, unsigned char bufsize) { int rc; CommandList_struct *cp; @@ -900,11 +901,10 @@ cciss_scsi_do_inquiry(ctlr_info_t *c, unsigned char *scsi3addr, cdb[1] = 0; cdb[2] = 0; cdb[3] = 0; - cdb[4] = sizeof(*buf) & 0xff; + cdb[4] = bufsize; cdb[5] = 0; rc = cciss_scsi_do_simple_cmd(c, cp, scsi3addr, cdb, - 6, (unsigned char *) buf, - sizeof(*buf), XFER_READ); + 6, buf, bufsize, XFER_READ); if (rc != 0) return rc; /* something went wrong */ @@ -1000,9 +1000,10 @@ cciss_update_non_disk_devices(int cntl_num, int hostno) that though. */ - +#define OBDR_TAPE_INQ_SIZE 49 +#define OBDR_TAPE_SIG "$DR-10" ReportLunData_struct *ld_buff; - InquiryData_struct *inq_buff; + unsigned char *inq_buff; unsigned char scsi3addr[8]; ctlr_info_t *c; __u32 num_luns=0; @@ -1020,7 +1021,7 @@ cciss_update_non_disk_devices(int cntl_num, int hostno) return; } memset(ld_buff, 0, reportlunsize); - inq_buff = kmalloc(sizeof( InquiryData_struct), GFP_KERNEL); + inq_buff = kmalloc(OBDR_TAPE_INQ_SIZE, GFP_KERNEL); if (inq_buff == NULL) { printk(KERN_ERR "cciss: out of memory\n"); kfree(ld_buff); @@ -1051,19 +1052,36 @@ cciss_update_non_disk_devices(int cntl_num, int hostno) /* for each physical lun, do an inquiry */ if (ld_buff->LUN[i][3] & 0xC0) continue; - memset(inq_buff, 0, sizeof(InquiryData_struct)); + memset(inq_buff, 0, OBDR_TAPE_INQ_SIZE); memcpy(&scsi3addr[0], &ld_buff->LUN[i][0], 8); - if (cciss_scsi_do_inquiry(hba[cntl_num], - scsi3addr, inq_buff) != 0) - { + if (cciss_scsi_do_inquiry(hba[cntl_num], scsi3addr, inq_buff, + (unsigned char) OBDR_TAPE_INQ_SIZE) != 0) { /* Inquiry failed (msg printed already) */ devtype = 0; /* so we will skip this device. */ } else /* what kind of device is this? */ - devtype = (inq_buff->data_byte[0] & 0x1f); + devtype = (inq_buff[0] & 0x1f); switch (devtype) { + case 0x05: /* CD-ROM */ { + + /* We don't *really* support actual CD-ROM devices, + * just this "One Button Disaster Recovery" tape drive + * which temporarily pretends to be a CD-ROM drive. + * So we check that the device is really an OBDR tape + * device by checking for "$DR-10" in bytes 43-48 of + * the inquiry data. + */ + char obdr_sig[7]; + + strncpy(obdr_sig, &inq_buff[43], 6); + obdr_sig[6] = '\0'; + if (strncmp(obdr_sig, OBDR_TAPE_SIG, 6) != 0) + /* Not OBDR device, ignore it. */ + break; + } + /* fall through . . . */ case 0x01: /* sequential access, (tape) */ case 0x08: /* medium changer */ if (ncurrent >= CCISS_MAX_SCSI_DEVS_PER_HBA) { @@ -1126,6 +1144,7 @@ cciss_scsi_proc_info(struct Scsi_Host *sh, int buflen, datalen; ctlr_info_t *ci; + int i; int cntl_num; @@ -1136,8 +1155,28 @@ cciss_scsi_proc_info(struct Scsi_Host *sh, cntl_num = ci->ctlr; /* Get our index into the hba[] array */ if (func == 0) { /* User is reading from /proc/scsi/ciss*?/?* */ - buflen = sprintf(buffer, "hostnum=%d\n", sh->host_no); - + buflen = sprintf(buffer, "cciss%d: SCSI host: %d\n", + cntl_num, sh->host_no); + + /* this information is needed by apps to know which cciss + device corresponds to which scsi host number without + having to open a scsi target device node. The device + information is not a duplicate of /proc/scsi/scsi because + the two may be out of sync due to scsi hotplug, rather + this info is for an app to be able to use to know how to + get them back in sync. */ + + for (i=0;i<ccissscsi[cntl_num].ndevices;i++) { + struct cciss_scsi_dev_t *sd = &ccissscsi[cntl_num].dev[i]; + buflen += sprintf(&buffer[buflen], "c%db%dt%dl%d %02d " + "0x%02x%02x%02x%02x%02x%02x%02x%02x\n", + sh->host_no, sd->bus, sd->target, sd->lun, + sd->devtype, + sd->scsi3addr[0], sd->scsi3addr[1], + sd->scsi3addr[2], sd->scsi3addr[3], + sd->scsi3addr[4], sd->scsi3addr[5], + sd->scsi3addr[6], sd->scsi3addr[7]); + } datalen = buflen - offset; if (datalen < 0) { /* they're reading past EOF. */ datalen = 0; @@ -1399,7 +1438,7 @@ cciss_proc_tape_report(int ctlr, unsigned char *buffer, off_t *pos, off_t *len) CPQ_TAPE_LOCK(ctlr, flags); size = sprintf(buffer + *len, - " Sequential access devices: %d\n\n", + "Sequential access devices: %d\n\n", ccissscsi[ctlr].ndevices); CPQ_TAPE_UNLOCK(ctlr, flags); *pos += size; *len += size; diff --git a/drivers/block/ll_rw_blk.c b/drivers/block/ll_rw_blk.c index 483d71b..baedac5 100644 --- a/drivers/block/ll_rw_blk.c +++ b/drivers/block/ll_rw_blk.c @@ -2373,44 +2373,6 @@ int blkdev_issue_flush(struct block_device *bdev, sector_t *error_sector) EXPORT_SYMBOL(blkdev_issue_flush); -/** - * blkdev_scsi_issue_flush_fn - issue flush for SCSI devices - * @q: device queue - * @disk: gendisk - * @error_sector: error offset - * - * Description: - * Devices understanding the SCSI command set, can use this function as - * a helper for issuing a cache flush. Note: driver is required to store - * the error offset (in case of error flushing) in ->sector of struct - * request. - */ -int blkdev_scsi_issue_flush_fn(request_queue_t *q, struct gendisk *disk, - sector_t *error_sector) -{ - struct request *rq = blk_get_request(q, WRITE, __GFP_WAIT); - int ret; - - rq->flags |= REQ_BLOCK_PC | REQ_SOFTBARRIER; - rq->sector = 0; - memset(rq->cmd, 0, sizeof(rq->cmd)); - rq->cmd[0] = 0x35; - rq->cmd_len = 12; - rq->data = NULL; - rq->data_len = 0; - rq->timeout = 60 * HZ; - - ret = blk_execute_rq(q, disk, rq, 0); - - if (ret && error_sector) - *error_sector = rq->sector; - - blk_put_request(rq); - return ret; -} - -EXPORT_SYMBOL(blkdev_scsi_issue_flush_fn); - static void drive_stat_acct(struct request *rq, int nr_sectors, int new_io) { int rw = rq_data_dir(rq); diff --git a/drivers/block/paride/pf.c b/drivers/block/paride/pf.c index 711d2f3..94af920 100644 --- a/drivers/block/paride/pf.c +++ b/drivers/block/paride/pf.c @@ -750,6 +750,14 @@ static int pf_ready(void) static struct request_queue *pf_queue; +static void pf_end_request(int uptodate) +{ + if (pf_req) { + end_request(pf_req, uptodate); + pf_req = NULL; + } +} + static void do_pf_request(request_queue_t * q) { if (pf_busy) @@ -765,7 +773,7 @@ repeat: pf_count = pf_req->current_nr_sectors; if (pf_block + pf_count > get_capacity(pf_req->rq_disk)) { - end_request(pf_req, 0); + pf_end_request(0); goto repeat; } @@ -780,7 +788,7 @@ repeat: pi_do_claimed(pf_current->pi, do_pf_write); else { pf_busy = 0; - end_request(pf_req, 0); + pf_end_request(0); goto repeat; } } @@ -798,9 +806,11 @@ static int pf_next_buf(void) if (!pf_count) return 1; spin_lock_irqsave(&pf_spin_lock, saved_flags); - end_request(pf_req, 1); - pf_count = pf_req->current_nr_sectors; - pf_buf = pf_req->buffer; + pf_end_request(1); + if (pf_req) { + pf_count = pf_req->current_nr_sectors; + pf_buf = pf_req->buffer; + } spin_unlock_irqrestore(&pf_spin_lock, saved_flags); return 1; } @@ -810,7 +820,7 @@ static inline void next_request(int success) unsigned long saved_flags; spin_lock_irqsave(&pf_spin_lock, saved_flags); - end_request(pf_req, success); + pf_end_request(success); pf_busy = 0; do_pf_request(pf_queue); spin_unlock_irqrestore(&pf_spin_lock, saved_flags); diff --git a/drivers/block/pktcdvd.c b/drivers/block/pktcdvd.c index 7b83834..7e22a58 100644 --- a/drivers/block/pktcdvd.c +++ b/drivers/block/pktcdvd.c @@ -5,29 +5,41 @@ * May be copied or modified under the terms of the GNU General Public * License. See linux/COPYING for more information. * - * Packet writing layer for ATAPI and SCSI CD-R, CD-RW, DVD-R, and - * DVD-RW devices (aka an exercise in block layer masturbation) + * Packet writing layer for ATAPI and SCSI CD-RW, DVD+RW, DVD-RW and + * DVD-RAM devices. * + * Theory of operation: * - * TODO: (circa order of when I will fix it) - * - Only able to write on CD-RW media right now. - * - check host application code on media and set it in write page - * - interface for UDF <-> packet to negotiate a new location when a write - * fails. - * - handle OPC, especially for -RW media + * At the lowest level, there is the standard driver for the CD/DVD device, + * typically ide-cd.c or sr.c. This driver can handle read and write requests, + * but it doesn't know anything about the special restrictions that apply to + * packet writing. One restriction is that write requests must be aligned to + * packet boundaries on the physical media, and the size of a write request + * must be equal to the packet size. Another restriction is that a + * GPCMD_FLUSH_CACHE command has to be issued to the drive before a read + * command, if the previous command was a write. * - * Theory of operation: + * The purpose of the packet writing driver is to hide these restrictions from + * higher layers, such as file systems, and present a block device that can be + * randomly read and written using 2kB-sized blocks. + * + * The lowest layer in the packet writing driver is the packet I/O scheduler. + * Its data is defined by the struct packet_iosched and includes two bio + * queues with pending read and write requests. These queues are processed + * by the pkt_iosched_process_queue() function. The write requests in this + * queue are already properly aligned and sized. This layer is responsible for + * issuing the flush cache commands and scheduling the I/O in a good order. * - * We use a custom make_request_fn function that forwards reads directly to - * the underlying CD device. Write requests are either attached directly to - * a live packet_data object, or simply stored sequentially in a list for - * later processing by the kcdrwd kernel thread. This driver doesn't use - * any elevator functionally as defined by the elevator_s struct, but the - * underlying CD device uses a standard elevator. + * The next layer transforms unaligned write requests to aligned writes. This + * transformation requires reading missing pieces of data from the underlying + * block device, assembling the pieces to full packets and queuing them to the + * packet I/O scheduler. * - * This strategy makes it possible to do very late merging of IO requests. - * A new bio sent to pkt_make_request can be merged with a live packet_data - * object even if the object is in the data gathering state. + * At the top layer there is a custom make_request_fn function that forwards + * read requests directly to the iosched queue and puts write requests in the + * unaligned write queue. A kernel thread performs the necessary read + * gathering to convert the unaligned writes to aligned writes and then feeds + * them to the packet I/O scheduler. * *************************************************************************/ @@ -100,10 +112,9 @@ static struct bio *pkt_bio_alloc(int nr_iovecs) goto no_bio; bio_init(bio); - bvl = kmalloc(nr_iovecs * sizeof(struct bio_vec), GFP_KERNEL); + bvl = kcalloc(nr_iovecs, sizeof(struct bio_vec), GFP_KERNEL); if (!bvl) goto no_bvl; - memset(bvl, 0, nr_iovecs * sizeof(struct bio_vec)); bio->bi_max_vecs = nr_iovecs; bio->bi_io_vec = bvl; @@ -125,10 +136,9 @@ static struct packet_data *pkt_alloc_packet_data(void) int i; struct packet_data *pkt; - pkt = kmalloc(sizeof(struct packet_data), GFP_KERNEL); + pkt = kzalloc(sizeof(struct packet_data), GFP_KERNEL); if (!pkt) goto no_pkt; - memset(pkt, 0, sizeof(struct packet_data)); pkt->w_bio = pkt_bio_alloc(PACKET_MAX_SIZE); if (!pkt->w_bio) @@ -659,7 +669,6 @@ static void pkt_make_local_copy(struct packet_data *pkt, struct page **pages, in } offs += CD_FRAMESIZE; if (offs >= PAGE_SIZE) { - BUG_ON(offs > PAGE_SIZE); offs = 0; p++; } @@ -724,12 +733,6 @@ static void pkt_gather_data(struct pktcdvd_device *pd, struct packet_data *pkt) atomic_set(&pkt->io_wait, 0); atomic_set(&pkt->io_errors, 0); - if (pkt->cache_valid) { - VPRINTK("pkt_gather_data: zone %llx cached\n", - (unsigned long long)pkt->sector); - goto out_account; - } - /* * Figure out which frames we need to read before we can write. */ @@ -738,6 +741,7 @@ static void pkt_gather_data(struct pktcdvd_device *pd, struct packet_data *pkt) for (bio = pkt->orig_bios; bio; bio = bio->bi_next) { int first_frame = (bio->bi_sector - pkt->sector) / (CD_FRAMESIZE >> 9); int num_frames = bio->bi_size / CD_FRAMESIZE; + pd->stats.secs_w += num_frames * (CD_FRAMESIZE >> 9); BUG_ON(first_frame < 0); BUG_ON(first_frame + num_frames > pkt->frames); for (f = first_frame; f < first_frame + num_frames; f++) @@ -745,6 +749,12 @@ static void pkt_gather_data(struct pktcdvd_device *pd, struct packet_data *pkt) } spin_unlock(&pkt->lock); + if (pkt->cache_valid) { + VPRINTK("pkt_gather_data: zone %llx cached\n", + (unsigned long long)pkt->sector); + goto out_account; + } + /* * Schedule reads for missing parts of the packet. */ @@ -778,7 +788,6 @@ out_account: frames_read, (unsigned long long)pkt->sector); pd->stats.pkt_started++; pd->stats.secs_rg += frames_read * (CD_FRAMESIZE >> 9); - pd->stats.secs_w += pd->settings.size; } /* @@ -794,10 +803,11 @@ static struct packet_data *pkt_get_packet_data(struct pktcdvd_device *pd, int zo list_del_init(&pkt->list); if (pkt->sector != zone) pkt->cache_valid = 0; - break; + return pkt; } } - return pkt; + BUG(); + return NULL; } static void pkt_put_packet_data(struct pktcdvd_device *pd, struct packet_data *pkt) @@ -941,12 +951,10 @@ try_next_bio: } pkt = pkt_get_packet_data(pd, zone); - BUG_ON(!pkt); pd->current_sector = zone + pd->settings.size; pkt->sector = zone; pkt->frames = pd->settings.size >> 2; - BUG_ON(pkt->frames > PACKET_MAX_SIZE); pkt->write_size = 0; /* @@ -1636,6 +1644,10 @@ static int pkt_probe_settings(struct pktcdvd_device *pd) printk("pktcdvd: detected zero packet size!\n"); pd->settings.size = 128; } + if (pd->settings.size > PACKET_MAX_SECTORS) { + printk("pktcdvd: packet size is too big\n"); + return -ENXIO; + } pd->settings.fp = ti.fp; pd->offset = (be32_to_cpu(ti.track_start) << 2) & (pd->settings.size - 1); @@ -2198,7 +2210,6 @@ static int pkt_make_request(request_queue_t *q, struct bio *bio) * No matching packet found. Store the bio in the work queue. */ node = mempool_alloc(pd->rb_pool, GFP_NOIO); - BUG_ON(!node); node->bio = bio; spin_lock(&pd->lock); BUG_ON(pd->bio_queue_size < 0); @@ -2406,7 +2417,6 @@ static int pkt_ioctl(struct inode *inode, struct file *file, unsigned int cmd, u struct pktcdvd_device *pd = inode->i_bdev->bd_disk->private_data; VPRINTK("pkt_ioctl: cmd %x, dev %d:%d\n", cmd, imajor(inode), iminor(inode)); - BUG_ON(!pd); switch (cmd) { /* @@ -2477,10 +2487,9 @@ static int pkt_setup_dev(struct pkt_ctrl_command *ctrl_cmd) return -EBUSY; } - pd = kmalloc(sizeof(struct pktcdvd_device), GFP_KERNEL); + pd = kzalloc(sizeof(struct pktcdvd_device), GFP_KERNEL); if (!pd) return ret; - memset(pd, 0, sizeof(struct pktcdvd_device)); pd->rb_pool = mempool_create(PKT_RB_POOL_SIZE, pkt_rb_alloc, pkt_rb_free, NULL); if (!pd->rb_pool) diff --git a/drivers/block/scsi_ioctl.c b/drivers/block/scsi_ioctl.c index 856c227..079ec34 100644 --- a/drivers/block/scsi_ioctl.c +++ b/drivers/block/scsi_ioctl.c @@ -168,6 +168,7 @@ static int verify_command(struct file *file, unsigned char *cmd) safe_for_write(WRITE_VERIFY_12), safe_for_write(WRITE_16), safe_for_write(WRITE_LONG), + safe_for_write(WRITE_LONG_2), safe_for_write(ERASE), safe_for_write(GPCMD_MODE_SELECT_10), safe_for_write(MODE_SELECT), diff --git a/drivers/block/ub.c b/drivers/block/ub.c index aa0bf7e..ed4d500 100644 --- a/drivers/block/ub.c +++ b/drivers/block/ub.c @@ -172,7 +172,7 @@ struct bulk_cs_wrap { */ struct ub_dev; -#define UB_MAX_REQ_SG 4 +#define UB_MAX_REQ_SG 9 /* cdrecord requires 32KB and maybe a header */ #define UB_MAX_SECTORS 64 /* @@ -387,7 +387,7 @@ struct ub_dev { struct bulk_cs_wrap work_bcs; struct usb_ctrlrequest work_cr; - int sg_stat[UB_MAX_REQ_SG+1]; + int sg_stat[6]; struct ub_scsi_trace tr; }; @@ -525,12 +525,13 @@ static ssize_t ub_diag_show(struct device *dev, struct device_attribute *attr, "qlen %d qmax %d\n", sc->cmd_queue.qlen, sc->cmd_queue.qmax); cnt += sprintf(page + cnt, - "sg %d %d %d %d %d\n", + "sg %d %d %d %d %d .. %d\n", sc->sg_stat[0], sc->sg_stat[1], sc->sg_stat[2], sc->sg_stat[3], - sc->sg_stat[4]); + sc->sg_stat[4], + sc->sg_stat[5]); list_for_each (p, &sc->luns) { lun = list_entry(p, struct ub_lun, link); @@ -835,7 +836,7 @@ static int ub_cmd_build_block(struct ub_dev *sc, struct ub_lun *lun, return -1; } cmd->nsg = n_elem; - sc->sg_stat[n_elem]++; + sc->sg_stat[n_elem < 5 ? n_elem : 5]++; /* * build the command @@ -891,7 +892,7 @@ static int ub_cmd_build_packet(struct ub_dev *sc, struct ub_lun *lun, return -1; } cmd->nsg = n_elem; - sc->sg_stat[n_elem]++; + sc->sg_stat[n_elem < 5 ? n_elem : 5]++; memcpy(&cmd->cdb, rq->cmd, rq->cmd_len); cmd->cdb_len = rq->cmd_len; @@ -1010,7 +1011,6 @@ static int ub_scsi_cmd_start(struct ub_dev *sc, struct ub_scsi_cmd *cmd) sc->last_pipe = sc->send_bulk_pipe; usb_fill_bulk_urb(&sc->work_urb, sc->dev, sc->send_bulk_pipe, bcb, US_BULK_CB_WRAP_LEN, ub_urb_complete, sc); - sc->work_urb.transfer_flags = 0; /* Fill what we shouldn't be filling, because usb-storage did so. */ sc->work_urb.actual_length = 0; @@ -1019,7 +1019,6 @@ static int ub_scsi_cmd_start(struct ub_dev *sc, struct ub_scsi_cmd *cmd) if ((rc = usb_submit_urb(&sc->work_urb, GFP_ATOMIC)) != 0) { /* XXX Clear stalls */ - printk("ub: cmd #%d start failed (%d)\n", cmd->tag, rc); /* P3 */ ub_complete(&sc->work_done); return rc; } @@ -1190,11 +1189,9 @@ static void ub_scsi_urb_compl(struct ub_dev *sc, struct ub_scsi_cmd *cmd) return; } if (urb->status != 0) { - printk("ub: cmd #%d cmd status (%d)\n", cmd->tag, urb->status); /* P3 */ goto Bad_End; } if (urb->actual_length != US_BULK_CB_WRAP_LEN) { - printk("ub: cmd #%d xferred %d\n", cmd->tag, urb->actual_length); /* P3 */ /* XXX Must do reset here to unconfuse the device */ goto Bad_End; } @@ -1395,14 +1392,12 @@ static void ub_data_start(struct ub_dev *sc, struct ub_scsi_cmd *cmd) usb_fill_bulk_urb(&sc->work_urb, sc->dev, pipe, page_address(sg->page) + sg->offset, sg->length, ub_urb_complete, sc); - sc->work_urb.transfer_flags = 0; sc->work_urb.actual_length = 0; sc->work_urb.error_count = 0; sc->work_urb.status = 0; if ((rc = usb_submit_urb(&sc->work_urb, GFP_ATOMIC)) != 0) { /* XXX Clear stalls */ - printk("ub: data #%d submit failed (%d)\n", cmd->tag, rc); /* P3 */ ub_complete(&sc->work_done); ub_state_done(sc, cmd, rc); return; @@ -1442,7 +1437,6 @@ static int __ub_state_stat(struct ub_dev *sc, struct ub_scsi_cmd *cmd) sc->last_pipe = sc->recv_bulk_pipe; usb_fill_bulk_urb(&sc->work_urb, sc->dev, sc->recv_bulk_pipe, &sc->work_bcs, US_BULK_CS_WRAP_LEN, ub_urb_complete, sc); - sc->work_urb.transfer_flags = 0; sc->work_urb.actual_length = 0; sc->work_urb.error_count = 0; sc->work_urb.status = 0; @@ -1563,7 +1557,6 @@ static int ub_submit_clear_stall(struct ub_dev *sc, struct ub_scsi_cmd *cmd, usb_fill_control_urb(&sc->work_urb, sc->dev, sc->send_ctrl_pipe, (unsigned char*) cr, NULL, 0, ub_urb_complete, sc); - sc->work_urb.transfer_flags = 0; sc->work_urb.actual_length = 0; sc->work_urb.error_count = 0; sc->work_urb.status = 0; @@ -2000,17 +1993,16 @@ static int ub_sync_getmaxlun(struct ub_dev *sc) usb_fill_control_urb(&sc->work_urb, sc->dev, sc->recv_ctrl_pipe, (unsigned char*) cr, p, 1, ub_probe_urb_complete, &compl); - sc->work_urb.transfer_flags = 0; sc->work_urb.actual_length = 0; sc->work_urb.error_count = 0; sc->work_urb.status = 0; if ((rc = usb_submit_urb(&sc->work_urb, GFP_KERNEL)) != 0) { if (rc == -EPIPE) { - printk("%s: Stall at GetMaxLUN, using 1 LUN\n", + printk("%s: Stall submitting GetMaxLUN, using 1 LUN\n", sc->name); /* P3 */ } else { - printk(KERN_WARNING + printk(KERN_NOTICE "%s: Unable to submit GetMaxLUN (%d)\n", sc->name, rc); } @@ -2028,6 +2020,18 @@ static int ub_sync_getmaxlun(struct ub_dev *sc) del_timer_sync(&timer); usb_kill_urb(&sc->work_urb); + if ((rc = sc->work_urb.status) < 0) { + if (rc == -EPIPE) { + printk("%s: Stall at GetMaxLUN, using 1 LUN\n", + sc->name); /* P3 */ + } else { + printk(KERN_NOTICE + "%s: Error at GetMaxLUN (%d)\n", + sc->name, rc); + } + goto err_io; + } + if (sc->work_urb.actual_length != 1) { printk("%s: GetMaxLUN returned %d bytes\n", sc->name, sc->work_urb.actual_length); /* P3 */ @@ -2048,6 +2052,7 @@ static int ub_sync_getmaxlun(struct ub_dev *sc) kfree(p); return nluns; +err_io: err_submit: kfree(p); err_alloc: @@ -2080,7 +2085,6 @@ static int ub_probe_clear_stall(struct ub_dev *sc, int stalled_pipe) usb_fill_control_urb(&sc->work_urb, sc->dev, sc->send_ctrl_pipe, (unsigned char*) cr, NULL, 0, ub_probe_urb_complete, &compl); - sc->work_urb.transfer_flags = 0; sc->work_urb.actual_length = 0; sc->work_urb.error_count = 0; sc->work_urb.status = 0; @@ -2213,8 +2217,10 @@ static int ub_probe(struct usb_interface *intf, * This is needed to clear toggles. It is a problem only if we do * `rmmod ub && modprobe ub` without disconnects, but we like that. */ +#if 0 /* iPod Mini fails if we do this (big white iPod works) */ ub_probe_clear_stall(sc, sc->recv_bulk_pipe); ub_probe_clear_stall(sc, sc->send_bulk_pipe); +#endif /* * The way this is used by the startup code is a little specific. @@ -2241,10 +2247,10 @@ static int ub_probe(struct usb_interface *intf, for (i = 0; i < 3; i++) { if ((rc = ub_sync_getmaxlun(sc)) < 0) { /* - * Some devices (i.e. Iomega Zip100) need this -- - * apparently the bulk pipes get STALLed when the - * GetMaxLUN request is processed. - * XXX I have a ZIP-100, verify it does this. + * This segment is taken from usb-storage. They say + * that ZIP-100 needs this, but my own ZIP-100 works + * fine without this. + * Still, it does not seem to hurt anything. */ if (rc == -EPIPE) { ub_probe_clear_stall(sc, sc->recv_bulk_pipe); @@ -2313,7 +2319,7 @@ static int ub_probe_lun(struct ub_dev *sc, int lnum) disk->first_minor = lun->id * UB_MINORS_PER_MAJOR; disk->fops = &ub_bd_fops; disk->private_data = lun; - disk->driverfs_dev = &sc->intf->dev; /* XXX Many to one ok? */ + disk->driverfs_dev = &sc->intf->dev; rc = -ENOMEM; if ((q = blk_init_queue(ub_request_fn, &sc->lock)) == NULL) @@ -2466,9 +2472,6 @@ static int __init ub_init(void) { int rc; - /* P3 */ printk("ub: sizeof ub_scsi_cmd %zu ub_dev %zu ub_lun %zu\n", - sizeof(struct ub_scsi_cmd), sizeof(struct ub_dev), sizeof(struct ub_lun)); - if ((rc = register_blkdev(UB_MAJOR, DRV_NAME)) != 0) goto err_regblkdev; devfs_mk_dir(DEVFS_NAME); diff --git a/drivers/bluetooth/hci_usb.c b/drivers/bluetooth/hci_usb.c index 67d96b5..57c48bb 100644 --- a/drivers/bluetooth/hci_usb.c +++ b/drivers/bluetooth/hci_usb.c @@ -65,13 +65,15 @@ #endif static int ignore = 0; +static int ignore_csr = 0; +static int ignore_sniffer = 0; static int reset = 0; #ifdef CONFIG_BT_HCIUSB_SCO static int isoc = 2; #endif -#define VERSION "2.8" +#define VERSION "2.9" static struct usb_driver hci_usb_driver; @@ -98,6 +100,9 @@ static struct usb_device_id bluetooth_ids[] = { MODULE_DEVICE_TABLE (usb, bluetooth_ids); static struct usb_device_id blacklist_ids[] = { + /* CSR BlueCore devices */ + { USB_DEVICE(0x0a12, 0x0001), .driver_info = HCI_CSR }, + /* Broadcom BCM2033 without firmware */ { USB_DEVICE(0x0a5c, 0x2033), .driver_info = HCI_IGNORE }, @@ -836,6 +841,12 @@ static int hci_usb_probe(struct usb_interface *intf, const struct usb_device_id if (ignore || id->driver_info & HCI_IGNORE) return -ENODEV; + if (ignore_csr && id->driver_info & HCI_CSR) + return -ENODEV; + + if (ignore_sniffer && id->driver_info & HCI_SNIFFER) + return -ENODEV; + if (intf->cur_altsetting->desc.bInterfaceNumber > 0) return -ENODEV; @@ -1061,6 +1072,12 @@ module_exit(hci_usb_exit); module_param(ignore, bool, 0644); MODULE_PARM_DESC(ignore, "Ignore devices from the matching table"); +module_param(ignore_csr, bool, 0644); +MODULE_PARM_DESC(ignore_csr, "Ignore devices with id 0a12:0001"); + +module_param(ignore_sniffer, bool, 0644); +MODULE_PARM_DESC(ignore_sniffer, "Ignore devices with id 0a12:0002"); + module_param(reset, bool, 0644); MODULE_PARM_DESC(reset, "Send HCI reset command on initialization"); diff --git a/drivers/bluetooth/hci_usb.h b/drivers/bluetooth/hci_usb.h index 29936b4..37100a6 100644 --- a/drivers/bluetooth/hci_usb.h +++ b/drivers/bluetooth/hci_usb.h @@ -31,9 +31,10 @@ #define HCI_IGNORE 0x01 #define HCI_RESET 0x02 #define HCI_DIGIANSWER 0x04 -#define HCI_SNIFFER 0x08 -#define HCI_BROKEN_ISOC 0x10 +#define HCI_CSR 0x08 +#define HCI_SNIFFER 0x10 #define HCI_BCM92035 0x20 +#define HCI_BROKEN_ISOC 0x40 #define HCI_MAX_IFACE_NUM 3 diff --git a/drivers/char/agp/hp-agp.c b/drivers/char/agp/hp-agp.c index 99762b6..de5d6d2 100644 --- a/drivers/char/agp/hp-agp.c +++ b/drivers/char/agp/hp-agp.c @@ -252,7 +252,7 @@ hp_zx1_configure (void) readl(hp->ioc_regs+HP_ZX1_PDIR_BASE); writel(hp->io_tlb_ps, hp->ioc_regs+HP_ZX1_TCNFG); readl(hp->ioc_regs+HP_ZX1_TCNFG); - writel(~(HP_ZX1_IOVA_SIZE-1), hp->ioc_regs+HP_ZX1_IMASK); + writel((unsigned int)(~(HP_ZX1_IOVA_SIZE-1)), hp->ioc_regs+HP_ZX1_IMASK); readl(hp->ioc_regs+HP_ZX1_IMASK); writel(hp->iova_base|1, hp->ioc_regs+HP_ZX1_IBASE); readl(hp->ioc_regs+HP_ZX1_IBASE); diff --git a/drivers/char/amiserial.c b/drivers/char/amiserial.c index 2a36561..a124f8c 100644 --- a/drivers/char/amiserial.c +++ b/drivers/char/amiserial.c @@ -2053,10 +2053,6 @@ static int __init rs_init(void) state->icount.rx = state->icount.tx = 0; state->icount.frame = state->icount.parity = 0; state->icount.overrun = state->icount.brk = 0; - /* - if(state->port && check_region(state->port,REGION_LENGTH(state))) - continue; - */ printk(KERN_INFO "ttyS%d is the amiga builtin serial port\n", state->line); diff --git a/drivers/char/epca.c b/drivers/char/epca.c index 58d3738..407708a 100644 --- a/drivers/char/epca.c +++ b/drivers/char/epca.c @@ -534,7 +534,7 @@ static void shutdown(struct channel *ch) unsigned long flags; struct tty_struct *tty; - struct board_chan *bc; + struct board_chan __iomem *bc; if (!(ch->asyncflags & ASYNC_INITIALIZED)) return; @@ -618,7 +618,7 @@ static int pc_write(struct tty_struct * tty, struct channel *ch; unsigned long flags; int remain; - struct board_chan *bc; + struct board_chan __iomem *bc; /* ---------------------------------------------------------------- pc_write is primarily called directly by the kernel routine @@ -685,7 +685,7 @@ static int pc_write(struct tty_struct * tty, ------------------------------------------------------------------- */ dataLen = min(bytesAvailable, dataLen); - memcpy(ch->txptr + head, buf, dataLen); + memcpy_toio(ch->txptr + head, buf, dataLen); buf += dataLen; head += dataLen; amountCopied += dataLen; @@ -726,7 +726,7 @@ static int pc_write_room(struct tty_struct *tty) struct channel *ch; unsigned long flags; unsigned int head, tail; - struct board_chan *bc; + struct board_chan __iomem *bc; remain = 0; @@ -773,7 +773,7 @@ static int pc_chars_in_buffer(struct tty_struct *tty) int remain; unsigned long flags; struct channel *ch; - struct board_chan *bc; + struct board_chan __iomem *bc; /* --------------------------------------------------------- verifyChannel returns the channel from the tty struct @@ -830,7 +830,7 @@ static void pc_flush_buffer(struct tty_struct *tty) unsigned int tail; unsigned long flags; struct channel *ch; - struct board_chan *bc; + struct board_chan __iomem *bc; /* --------------------------------------------------------- verifyChannel returns the channel from the tty struct if it is valid. This serves as a sanity check. @@ -976,7 +976,7 @@ static int pc_open(struct tty_struct *tty, struct file * filp) struct channel *ch; unsigned long flags; int line, retval, boardnum; - struct board_chan *bc; + struct board_chan __iomem *bc; unsigned int head; line = tty->index; @@ -1041,7 +1041,7 @@ static int pc_open(struct tty_struct *tty, struct file * filp) ch->statusflags = 0; /* Save boards current modem status */ - ch->imodem = bc->mstat; + ch->imodem = readb(&bc->mstat); /* ---------------------------------------------------------------- Set receive head and tail ptrs to each other. This indicates @@ -1399,10 +1399,10 @@ static void post_fep_init(unsigned int crd) { /* Begin post_fep_init */ int i; - unsigned char *memaddr; - struct global_data *gd; + void __iomem *memaddr; + struct global_data __iomem *gd; struct board_info *bd; - struct board_chan *bc; + struct board_chan __iomem *bc; struct channel *ch; int shrinkmem = 0, lowwater ; @@ -1461,7 +1461,7 @@ static void post_fep_init(unsigned int crd) 8 and 64 of these structures. -------------------------------------------------------------------- */ - bc = (struct board_chan *)(memaddr + CHANSTRUCT); + bc = memaddr + CHANSTRUCT; /* ------------------------------------------------------------------- The below assignment will set gd to point at the BEGINING of @@ -1470,7 +1470,7 @@ static void post_fep_init(unsigned int crd) pointer begins at 0xd10. ---------------------------------------------------------------------- */ - gd = (struct global_data *)(memaddr + GLOBAL); + gd = memaddr + GLOBAL; /* -------------------------------------------------------------------- XEPORTS (address 0xc22) points at the number of channels the @@ -1493,6 +1493,7 @@ static void post_fep_init(unsigned int crd) for (i = 0; i < bd->numports; i++, ch++, bc++) { /* Begin for each port */ unsigned long flags; + u16 tseg, rseg; ch->brdchan = bc; ch->mailbox = gd; @@ -1553,50 +1554,53 @@ static void post_fep_init(unsigned int crd) shrinkmem = 0; } + tseg = readw(&bc->tseg); + rseg = readw(&bc->rseg); + switch (bd->type) { case PCIXEM: case PCIXRJ: case PCIXR: /* Cover all the 2MEG cards */ - ch->txptr = memaddr + (((bc->tseg) << 4) & 0x1fffff); - ch->rxptr = memaddr + (((bc->rseg) << 4) & 0x1fffff); - ch->txwin = FEPWIN | ((bc->tseg) >> 11); - ch->rxwin = FEPWIN | ((bc->rseg) >> 11); + ch->txptr = memaddr + ((tseg << 4) & 0x1fffff); + ch->rxptr = memaddr + ((rseg << 4) & 0x1fffff); + ch->txwin = FEPWIN | (tseg >> 11); + ch->rxwin = FEPWIN | (rseg >> 11); break; case PCXEM: case EISAXEM: /* Cover all the 32K windowed cards */ /* Mask equal to window size - 1 */ - ch->txptr = memaddr + (((bc->tseg) << 4) & 0x7fff); - ch->rxptr = memaddr + (((bc->rseg) << 4) & 0x7fff); - ch->txwin = FEPWIN | ((bc->tseg) >> 11); - ch->rxwin = FEPWIN | ((bc->rseg) >> 11); + ch->txptr = memaddr + ((tseg << 4) & 0x7fff); + ch->rxptr = memaddr + ((rseg << 4) & 0x7fff); + ch->txwin = FEPWIN | (tseg >> 11); + ch->rxwin = FEPWIN | (rseg >> 11); break; case PCXEVE: case PCXE: - ch->txptr = memaddr + (((bc->tseg - bd->memory_seg) << 4) & 0x1fff); - ch->txwin = FEPWIN | ((bc->tseg - bd->memory_seg) >> 9); - ch->rxptr = memaddr + (((bc->rseg - bd->memory_seg) << 4) & 0x1fff); - ch->rxwin = FEPWIN | ((bc->rseg - bd->memory_seg) >>9 ); + ch->txptr = memaddr + (((tseg - bd->memory_seg) << 4) & 0x1fff); + ch->txwin = FEPWIN | ((tseg - bd->memory_seg) >> 9); + ch->rxptr = memaddr + (((rseg - bd->memory_seg) << 4) & 0x1fff); + ch->rxwin = FEPWIN | ((rseg - bd->memory_seg) >>9 ); break; case PCXI: case PC64XE: - ch->txptr = memaddr + ((bc->tseg - bd->memory_seg) << 4); - ch->rxptr = memaddr + ((bc->rseg - bd->memory_seg) << 4); + ch->txptr = memaddr + ((tseg - bd->memory_seg) << 4); + ch->rxptr = memaddr + ((rseg - bd->memory_seg) << 4); ch->txwin = ch->rxwin = 0; break; } /* End switch bd->type */ ch->txbufhead = 0; - ch->txbufsize = bc->tmax + 1; + ch->txbufsize = readw(&bc->tmax) + 1; ch->rxbufhead = 0; - ch->rxbufsize = bc->rmax + 1; + ch->rxbufsize = readw(&bc->rmax) + 1; lowwater = ch->txbufsize >= 2000 ? 1024 : (ch->txbufsize / 2); @@ -1718,11 +1722,11 @@ static void epcapoll(unsigned long ignored) static void doevent(int crd) { /* Begin doevent */ - void *eventbuf; + void __iomem *eventbuf; struct channel *ch, *chan0; static struct tty_struct *tty; struct board_info *bd; - struct board_chan *bc; + struct board_chan __iomem *bc; unsigned int tail, head; int event, channel; int mstat, lstat; @@ -1817,7 +1821,7 @@ static void doevent(int crd) static void fepcmd(struct channel *ch, int cmd, int word_or_byte, int byte2, int ncmds, int bytecmd) { /* Begin fepcmd */ - unchar *memaddr; + unchar __iomem *memaddr; unsigned int head, cmdTail, cmdStart, cmdMax; long count; int n; @@ -2000,7 +2004,7 @@ static void epcaparam(struct tty_struct *tty, struct channel *ch) unsigned int cmdHead; struct termios *ts; - struct board_chan *bc; + struct board_chan __iomem *bc; unsigned mval, hflow, cflag, iflag; bc = ch->brdchan; @@ -2010,7 +2014,7 @@ static void epcaparam(struct tty_struct *tty, struct channel *ch) ts = tty->termios; if ((ts->c_cflag & CBAUD) == 0) { /* Begin CBAUD detected */ cmdHead = readw(&bc->rin); - bc->rout = cmdHead; + writew(cmdHead, &bc->rout); cmdHead = readw(&bc->tin); /* Changing baud in mid-stream transmission can be wonderful */ /* --------------------------------------------------------------- @@ -2116,7 +2120,7 @@ static void receive_data(struct channel *ch) unchar *rptr; struct termios *ts = NULL; struct tty_struct *tty; - struct board_chan *bc; + struct board_chan __iomem *bc; int dataToRead, wrapgap, bytesAvailable; unsigned int tail, head; unsigned int wrapmask; @@ -2154,7 +2158,7 @@ static void receive_data(struct channel *ch) --------------------------------------------------------------------- */ if (!tty || !ts || !(ts->c_cflag & CREAD)) { - bc->rout = head; + writew(head, &bc->rout); return; } @@ -2270,7 +2274,7 @@ static int info_ioctl(struct tty_struct *tty, struct file * file, static int pc_tiocmget(struct tty_struct *tty, struct file *file) { struct channel *ch = (struct channel *) tty->driver_data; - struct board_chan *bc; + struct board_chan __iomem *bc; unsigned int mstat, mflag = 0; unsigned long flags; @@ -2351,7 +2355,7 @@ static int pc_ioctl(struct tty_struct *tty, struct file * file, unsigned long flags; unsigned int mflag, mstat; unsigned char startc, stopc; - struct board_chan *bc; + struct board_chan __iomem *bc; struct channel *ch = (struct channel *) tty->driver_data; void __user *argp = (void __user *)arg; @@ -2633,7 +2637,7 @@ static void pc_start(struct tty_struct *tty) spin_lock_irqsave(&epca_lock, flags); /* Just in case output was resumed because of a change in Digi-flow */ if (ch->statusflags & TXSTOPPED) { /* Begin transmit resume requested */ - struct board_chan *bc; + struct board_chan __iomem *bc; globalwinon(ch); bc = ch->brdchan; if (ch->statusflags & LOWWAIT) @@ -2727,7 +2731,7 @@ void digi_send_break(struct channel *ch, int msec) static void setup_empty_event(struct tty_struct *tty, struct channel *ch) { /* Begin setup_empty_event */ - struct board_chan *bc = ch->brdchan; + struct board_chan __iomem *bc = ch->brdchan; globalwinon(ch); ch->statusflags |= EMPTYWAIT; diff --git a/drivers/char/epca.h b/drivers/char/epca.h index 20eeb5a..456d6c8 100644 --- a/drivers/char/epca.h +++ b/drivers/char/epca.h @@ -128,17 +128,17 @@ struct channel unsigned long c_cflag; unsigned long c_lflag; unsigned long c_oflag; - unsigned char *txptr; - unsigned char *rxptr; + unsigned char __iomem *txptr; + unsigned char __iomem *rxptr; unsigned char *tmp_buf; struct board_info *board; - struct board_chan *brdchan; + struct board_chan __iomem *brdchan; struct digi_struct digiext; struct tty_struct *tty; wait_queue_head_t open_wait; wait_queue_head_t close_wait; struct work_struct tqueue; - struct global_data *mailbox; + struct global_data __iomem *mailbox; }; struct board_info @@ -149,8 +149,8 @@ struct board_info unsigned short numports; unsigned long port; unsigned long membase; - unsigned char __iomem *re_map_port; - unsigned char *re_map_membase; + void __iomem *re_map_port; + void __iomem *re_map_membase; unsigned long memory_seg; void ( * memwinon ) (struct board_info *, unsigned int) ; void ( * memwinoff ) (struct board_info *, unsigned int) ; diff --git a/drivers/char/hpet.c b/drivers/char/hpet.c index de0379b..c055bb6 100644 --- a/drivers/char/hpet.c +++ b/drivers/char/hpet.c @@ -273,7 +273,6 @@ static int hpet_mmap(struct file *file, struct vm_area_struct *vma) vma->vm_flags |= VM_IO; vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); - addr = __pa(addr); if (io_remap_pfn_range(vma, vma->vm_start, addr >> PAGE_SHIFT, PAGE_SIZE, vma->vm_page_prot)) { diff --git a/drivers/char/hvc_console.c b/drivers/char/hvc_console.c index cddb789..f921776 100644 --- a/drivers/char/hvc_console.c +++ b/drivers/char/hvc_console.c @@ -839,9 +839,6 @@ int __init hvc_init(void) hvc_driver->flags = TTY_DRIVER_REAL_RAW; tty_set_operations(hvc_driver, &hvc_ops); - if (tty_register_driver(hvc_driver)) - panic("Couldn't register hvc console driver\n"); - /* Always start the kthread because there can be hotplug vty adapters * added later. */ hvc_task = kthread_run(khvcd, NULL, "khvcd"); @@ -851,6 +848,9 @@ int __init hvc_init(void) return -EIO; } + if (tty_register_driver(hvc_driver)) + panic("Couldn't register hvc console driver\n"); + return 0; } module_init(hvc_init); diff --git a/drivers/char/ipmi/ipmi_msghandler.c b/drivers/char/ipmi/ipmi_msghandler.c index 463351d..32fa82c 100644 --- a/drivers/char/ipmi/ipmi_msghandler.c +++ b/drivers/char/ipmi/ipmi_msghandler.c @@ -2620,7 +2620,7 @@ void ipmi_smi_msg_received(ipmi_smi_t intf, spin_lock_irqsave(&(intf->waiting_msgs_lock), flags); if (!list_empty(&(intf->waiting_msgs))) { list_add_tail(&(msg->link), &(intf->waiting_msgs)); - spin_unlock(&(intf->waiting_msgs_lock)); + spin_unlock_irqrestore(&(intf->waiting_msgs_lock), flags); goto out_unlock; } spin_unlock_irqrestore(&(intf->waiting_msgs_lock), flags); @@ -2629,9 +2629,9 @@ void ipmi_smi_msg_received(ipmi_smi_t intf, if (rv > 0) { /* Could not handle the message now, just add it to a list to handle later. */ - spin_lock(&(intf->waiting_msgs_lock)); + spin_lock_irqsave(&(intf->waiting_msgs_lock), flags); list_add_tail(&(msg->link), &(intf->waiting_msgs)); - spin_unlock(&(intf->waiting_msgs_lock)); + spin_unlock_irqrestore(&(intf->waiting_msgs_lock), flags); } else if (rv == 0) { ipmi_free_smi_msg(msg); } diff --git a/drivers/char/vt.c b/drivers/char/vt.c index 1e33cb0..e91268e 100644 --- a/drivers/char/vt.c +++ b/drivers/char/vt.c @@ -810,13 +810,14 @@ int vc_resize(struct vc_data *vc, unsigned int cols, unsigned int lines) * from the top and bottom of cursor position */ old_origin += (vc->vc_y - new_rows/2) * old_row_size; - end = old_origin + new_screen_size; + end = old_origin + (old_row_size * new_rows); } } else /* * Cursor near the top, copy contents from the top of buffer */ - end = (old_rows > new_rows) ? old_origin + new_screen_size : + end = (old_rows > new_rows) ? old_origin + + (old_row_size * new_rows) : vc->vc_scr_end; update_attr(vc); diff --git a/drivers/char/watchdog/Kconfig b/drivers/char/watchdog/Kconfig index fa789ea..344001b 100644 --- a/drivers/char/watchdog/Kconfig +++ b/drivers/char/watchdog/Kconfig @@ -84,6 +84,17 @@ config 977_WATCHDOG Not sure? It's safe to say N. +config IXP2000_WATCHDOG + tristate "IXP2000 Watchdog" + depends on WATCHDOG && ARCH_IXP2000 + help + Say Y here if to include support for the watchdog timer + in the Intel IXP2000(2400, 2800, 2850) network processors. + This driver can be built as a module by choosing M. The module + will be called ixp2000_wdt. + + Say N if you are unsure. + config IXP4XX_WATCHDOG tristate "IXP4xx Watchdog" depends on WATCHDOG && ARCH_IXP4XX @@ -100,17 +111,6 @@ config IXP4XX_WATCHDOG Say N if you are unsure. -config IXP2000_WATCHDOG - tristate "IXP2000 Watchdog" - depends on WATCHDOG && ARCH_IXP2000 - help - Say Y here if to include support for the watchdog timer - in the Intel IXP2000(2400, 2800, 2850) network processors. - This driver can be built as a module by choosing M. The module - will be called ixp2000_wdt. - - Say N if you are unsure. - config S3C2410_WATCHDOG tristate "S3C2410 Watchdog" depends on WATCHDOG && ARCH_S3C2410 @@ -233,6 +233,16 @@ config IB700_WDT Most people will say N. +config IBMASR + tristate "IBM Automatic Server Restart" + depends on WATCHDOG && X86 + help + This is the driver for the IBM Automatic Server Restart watchdog + timer builtin into some eServer xSeries machines. + + To compile this driver as a module, choose M here: the + module will be called ibmasr. + config WAFER_WDT tristate "ICP Wafer 5823 Single Board Computer Watchdog" depends on WATCHDOG && X86 @@ -243,6 +253,16 @@ config WAFER_WDT To compile this driver as a module, choose M here: the module will be called wafer5823wdt. +config I6300ESB_WDT + tristate "Intel 6300ESB Timer/Watchdog" + depends on WATCHDOG && X86 && PCI + ---help--- + Hardware driver for the watchdog timer built into the Intel + 6300ESB controller hub. + + To compile this driver as a module, choose M here: the + module will be called i6300esb. + config I8XX_TCO tristate "Intel i8xx TCO Timer/Watchdog" depends on WATCHDOG && (X86 || IA64) && PCI @@ -298,6 +318,19 @@ config 60XX_WDT You can compile this driver directly into the kernel, or use it as a module. The module will be called sbc60xxwdt. +config SBC8360_WDT + tristate "SBC8360 Watchdog Timer" + depends on WATCHDOG && X86 + ---help--- + + This is the driver for the hardware watchdog on the SBC8360 Single + Board Computer produced by Axiomtek Co., Ltd. (www.axiomtek.com). + + To compile this driver as a module, choose M here: the + module will be called sbc8360.ko. + + Most people will say N. + config CPU5_WDT tristate "SMA CPU5 Watchdog" depends on WATCHDOG && X86 @@ -336,6 +369,19 @@ config W83877F_WDT Most people will say N. +config W83977F_WDT + tristate "W83977F (PCM-5335) Watchdog Timer" + depends on WATCHDOG && X86 + ---help--- + This is the driver for the hardware watchdog on the W83977F I/O chip + as used in AAEON's PCM-5335 SBC (and likely others). This + watchdog simply watches your kernel to make sure it doesn't freeze, + and if it does, it reboots your computer after a certain amount of + time. + + To compile this driver as a module, choose M here: the + module will be called w83977f_wdt. + config MACHZ_WDT tristate "ZF MachZ Watchdog" depends on WATCHDOG && X86 @@ -355,6 +401,10 @@ config 8xx_WDT tristate "MPC8xx Watchdog Timer" depends on WATCHDOG && 8xx +config MV64X60_WDT + tristate "MV64X60 (Marvell Discovery) Watchdog Timer" + depends on WATCHDOG && MV64X60 + config BOOKE_WDT tristate "PowerPC Book-E Watchdog Timer" depends on WATCHDOG && (BOOKE || 4xx) @@ -362,6 +412,17 @@ config BOOKE_WDT Please see Documentation/watchdog/watchdog-api.txt for more information. +# PPC64 Architecture + +config WATCHDOG_RTAS + tristate "RTAS watchdog" + depends on WATCHDOG && PPC_RTAS + help + This driver adds watchdog support for the RTAS watchdog. + + To compile this driver as a module, choose M here. The module + will be called wdrtas. + # MIPS Architecture config INDYDOG @@ -430,16 +491,6 @@ config WATCHDOG_RIO machines. The watchdog timeout period is normally one minute but can be changed with a boot-time parameter. -# ppc64 RTAS watchdog -config WATCHDOG_RTAS - tristate "RTAS watchdog" - depends on WATCHDOG && PPC_RTAS - help - This driver adds watchdog support for the RTAS watchdog. - - To compile this driver as a module, choose M here. The module - will be called wdrtas. - # # ISA-based Watchdog Cards # diff --git a/drivers/char/watchdog/Makefile b/drivers/char/watchdog/Makefile index bc6f5fe..cfd0a39 100644 --- a/drivers/char/watchdog/Makefile +++ b/drivers/char/watchdog/Makefile @@ -39,22 +39,27 @@ obj-$(CONFIG_ALIM7101_WDT) += alim7101_wdt.o obj-$(CONFIG_SC520_WDT) += sc520_wdt.o obj-$(CONFIG_EUROTECH_WDT) += eurotechwdt.o obj-$(CONFIG_IB700_WDT) += ib700wdt.o +obj-$(CONFIG_IBMASR) += ibmasr.o obj-$(CONFIG_WAFER_WDT) += wafer5823wdt.o +obj-$(CONFIG_I6300ESB_WDT) += i6300esb.o obj-$(CONFIG_I8XX_TCO) += i8xx_tco.o obj-$(CONFIG_SC1200_WDT) += sc1200wdt.o obj-$(CONFIG_SCx200_WDT) += scx200_wdt.o obj-$(CONFIG_60XX_WDT) += sbc60xxwdt.o +obj-$(CONFIG_SBC8360_WDT) += sbc8360.o obj-$(CONFIG_CPU5_WDT) += cpu5wdt.o obj-$(CONFIG_W83627HF_WDT) += w83627hf_wdt.o obj-$(CONFIG_W83877F_WDT) += w83877f_wdt.o +obj-$(CONFIG_W83977F_WDT) += w83977f_wdt.o obj-$(CONFIG_MACHZ_WDT) += machzwd.o # PowerPC Architecture obj-$(CONFIG_8xx_WDT) += mpc8xx_wdt.o +obj-$(CONFIG_MV64X60_WDT) += mv64x60_wdt.o +obj-$(CONFIG_BOOKE_WDT) += booke_wdt.o # PPC64 Architecture obj-$(CONFIG_WATCHDOG_RTAS) += wdrtas.o -obj-$(CONFIG_BOOKE_WDT) += booke_wdt.o # MIPS Architecture obj-$(CONFIG_INDYDOG) += indydog.o diff --git a/drivers/char/watchdog/i6300esb.c b/drivers/char/watchdog/i6300esb.c new file mode 100644 index 0000000..93785f1 --- /dev/null +++ b/drivers/char/watchdog/i6300esb.c @@ -0,0 +1,527 @@ +/* + * i6300esb: Watchdog timer driver for Intel 6300ESB chipset + * + * (c) Copyright 2004 Google Inc. + * (c) Copyright 2005 David Härdeman <david@2gen.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. + * + * based on i810-tco.c which is in turn based on softdog.c + * + * The timer is implemented in the following I/O controller hubs: + * (See the intel documentation on http://developer.intel.com.) + * 6300ESB chip : document number 300641-003 + * + * 2004YYZZ Ross Biro + * Initial version 0.01 + * 2004YYZZ Ross Biro + * Version 0.02 + * 20050210 David Härdeman <david@2gen.com> + * Ported driver to kernel 2.6 + */ + +/* + * Includes, defines, variables, module parameters, ... + */ + +#include <linux/module.h> +#include <linux/types.h> +#include <linux/kernel.h> +#include <linux/fs.h> +#include <linux/mm.h> +#include <linux/miscdevice.h> +#include <linux/watchdog.h> +#include <linux/reboot.h> +#include <linux/init.h> +#include <linux/pci.h> +#include <linux/ioport.h> + +#include <asm/uaccess.h> +#include <asm/io.h> + +/* Module and version information */ +#define ESB_VERSION "0.03" +#define ESB_MODULE_NAME "i6300ESB timer" +#define ESB_DRIVER_NAME ESB_MODULE_NAME ", v" ESB_VERSION +#define PFX ESB_MODULE_NAME ": " + +/* PCI configuration registers */ +#define ESB_CONFIG_REG 0x60 /* Config register */ +#define ESB_LOCK_REG 0x68 /* WDT lock register */ + +/* Memory mapped registers */ +#define ESB_TIMER1_REG BASEADDR + 0x00 /* Timer1 value after each reset */ +#define ESB_TIMER2_REG BASEADDR + 0x04 /* Timer2 value after each reset */ +#define ESB_GINTSR_REG BASEADDR + 0x08 /* General Interrupt Status Register */ +#define ESB_RELOAD_REG BASEADDR + 0x0c /* Reload register */ + +/* Lock register bits */ +#define ESB_WDT_FUNC ( 0x01 << 2 ) /* Watchdog functionality */ +#define ESB_WDT_ENABLE ( 0x01 << 1 ) /* Enable WDT */ +#define ESB_WDT_LOCK ( 0x01 << 0 ) /* Lock (nowayout) */ + +/* Config register bits */ +#define ESB_WDT_REBOOT ( 0x01 << 5 ) /* Enable reboot on timeout */ +#define ESB_WDT_FREQ ( 0x01 << 2 ) /* Decrement frequency */ +#define ESB_WDT_INTTYPE ( 0x11 << 0 ) /* Interrupt type on timer1 timeout */ + +/* Reload register bits */ +#define ESB_WDT_RELOAD ( 0x01 << 8 ) /* prevent timeout */ + +/* Magic constants */ +#define ESB_UNLOCK1 0x80 /* Step 1 to unlock reset registers */ +#define ESB_UNLOCK2 0x86 /* Step 2 to unlock reset registers */ + +/* internal variables */ +static void __iomem *BASEADDR; +static spinlock_t esb_lock; /* Guards the hardware */ +static unsigned long timer_alive; +static struct pci_dev *esb_pci; +static unsigned short triggered; /* The status of the watchdog upon boot */ +static char esb_expect_close; + +/* module parameters */ +#define WATCHDOG_HEARTBEAT 30 /* 30 sec default heartbeat (1<heartbeat<2*1023) */ +static int heartbeat = WATCHDOG_HEARTBEAT; /* in seconds */ +module_param(heartbeat, int, 0); +MODULE_PARM_DESC(heartbeat, "Watchdog heartbeat in seconds. (1<heartbeat<2046, default=" __MODULE_STRING(WATCHDOG_HEARTBEAT) ")"); + +static int nowayout = WATCHDOG_NOWAYOUT; +module_param(nowayout, int, 0); +MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)"); + +/* + * Some i6300ESB specific functions + */ + +/* + * Prepare for reloading the timer by unlocking the proper registers. + * This is performed by first writing 0x80 followed by 0x86 to the + * reload register. After this the appropriate registers can be written + * to once before they need to be unlocked again. + */ +static inline void esb_unlock_registers(void) { + writeb(ESB_UNLOCK1, ESB_RELOAD_REG); + writeb(ESB_UNLOCK2, ESB_RELOAD_REG); +} + +static void esb_timer_start(void) +{ + u8 val; + + /* Enable or Enable + Lock? */ + val = 0x02 | (nowayout ? 0x01 : 0x00); + + pci_write_config_byte(esb_pci, ESB_LOCK_REG, val); +} + +static int esb_timer_stop(void) +{ + u8 val; + + spin_lock(&esb_lock); + /* First, reset timers as suggested by the docs */ + esb_unlock_registers(); + writew(ESB_WDT_RELOAD, ESB_RELOAD_REG); + /* Then disable the WDT */ + pci_write_config_byte(esb_pci, ESB_LOCK_REG, 0x0); + pci_read_config_byte(esb_pci, ESB_LOCK_REG, &val); + spin_unlock(&esb_lock); + + /* Returns 0 if the timer was disabled, non-zero otherwise */ + return (val & 0x01); +} + +static void esb_timer_keepalive(void) +{ + spin_lock(&esb_lock); + esb_unlock_registers(); + writew(ESB_WDT_RELOAD, ESB_RELOAD_REG); + /* FIXME: Do we need to flush anything here? */ + spin_unlock(&esb_lock); +} + +static int esb_timer_set_heartbeat(int time) +{ + u32 val; + + if (time < 0x1 || time > (2 * 0x03ff)) + return -EINVAL; + + spin_lock(&esb_lock); + + /* We shift by 9, so if we are passed a value of 1 sec, + * val will be 1 << 9 = 512, then write that to two + * timers => 2 * 512 = 1024 (which is decremented at 1KHz) + */ + val = time << 9; + + /* Write timer 1 */ + esb_unlock_registers(); + writel(val, ESB_TIMER1_REG); + + /* Write timer 2 */ + esb_unlock_registers(); + writel(val, ESB_TIMER2_REG); + + /* Reload */ + esb_unlock_registers(); + writew(ESB_WDT_RELOAD, ESB_RELOAD_REG); + + /* FIXME: Do we need to flush everything out? */ + + /* Done */ + heartbeat = time; + spin_unlock(&esb_lock); + return 0; +} + +static int esb_timer_read (void) +{ + u32 count; + + /* This isn't documented, and doesn't take into + * acount which stage is running, but it looks + * like a 20 bit count down, so we might as well report it. + */ + pci_read_config_dword(esb_pci, 0x64, &count); + return (int)count; +} + +/* + * /dev/watchdog handling + */ + +static int esb_open (struct inode *inode, struct file *file) +{ + /* /dev/watchdog can only be opened once */ + if (test_and_set_bit(0, &timer_alive)) + return -EBUSY; + + /* Reload and activate timer */ + esb_timer_keepalive (); + esb_timer_start (); + + return nonseekable_open(inode, file); +} + +static int esb_release (struct inode *inode, struct file *file) +{ + /* Shut off the timer. */ + if (esb_expect_close == 42) { + esb_timer_stop (); + } else { + printk(KERN_CRIT PFX "Unexpected close, not stopping watchdog!\n"); + esb_timer_keepalive (); + } + clear_bit(0, &timer_alive); + esb_expect_close = 0; + return 0; +} + +static ssize_t esb_write (struct file *file, const char __user *data, + size_t len, loff_t * ppos) +{ + /* See if we got the magic character 'V' and reload the timer */ + if (len) { + if (!nowayout) { + size_t i; + + /* note: just in case someone wrote the magic character + * five months ago... */ + esb_expect_close = 0; + + /* scan to see whether or not we got the magic character */ + for (i = 0; i != len; i++) { + char c; + if(get_user(c, data+i)) + return -EFAULT; + if (c == 'V') + esb_expect_close = 42; + } + } + + /* someone wrote to us, we should reload the timer */ + esb_timer_keepalive (); + } + return len; +} + +static int esb_ioctl (struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg) +{ + int new_options, retval = -EINVAL; + int new_heartbeat; + void __user *argp = (void __user *)arg; + int __user *p = argp; + static struct watchdog_info ident = { + .options = WDIOF_SETTIMEOUT | + WDIOF_KEEPALIVEPING | + WDIOF_MAGICCLOSE, + .firmware_version = 0, + .identity = ESB_MODULE_NAME, + }; + + switch (cmd) { + case WDIOC_GETSUPPORT: + return copy_to_user(argp, &ident, + sizeof (ident)) ? -EFAULT : 0; + + case WDIOC_GETSTATUS: + return put_user (esb_timer_read(), p); + + case WDIOC_GETBOOTSTATUS: + return put_user (triggered, p); + + case WDIOC_KEEPALIVE: + esb_timer_keepalive (); + return 0; + + case WDIOC_SETOPTIONS: + { + if (get_user (new_options, p)) + return -EFAULT; + + if (new_options & WDIOS_DISABLECARD) { + esb_timer_stop (); + retval = 0; + } + + if (new_options & WDIOS_ENABLECARD) { + esb_timer_keepalive (); + esb_timer_start (); + retval = 0; + } + + return retval; + } + + case WDIOC_SETTIMEOUT: + { + if (get_user(new_heartbeat, p)) + return -EFAULT; + + if (esb_timer_set_heartbeat(new_heartbeat)) + return -EINVAL; + + esb_timer_keepalive (); + /* Fall */ + } + + case WDIOC_GETTIMEOUT: + return put_user(heartbeat, p); + + default: + return -ENOIOCTLCMD; + } +} + +/* + * Notify system + */ + +static int esb_notify_sys (struct notifier_block *this, unsigned long code, void *unused) +{ + if (code==SYS_DOWN || code==SYS_HALT) { + /* Turn the WDT off */ + esb_timer_stop (); + } + + return NOTIFY_DONE; +} + +/* + * Kernel Interfaces + */ + +static struct file_operations esb_fops = { + .owner = THIS_MODULE, + .llseek = no_llseek, + .write = esb_write, + .ioctl = esb_ioctl, + .open = esb_open, + .release = esb_release, +}; + +static struct miscdevice esb_miscdev = { + .minor = WATCHDOG_MINOR, + .name = "watchdog", + .fops = &esb_fops, +}; + +static struct notifier_block esb_notifier = { + .notifier_call = esb_notify_sys, +}; + +/* + * Data for PCI driver interface + * + * This data only exists for exporting the supported + * PCI ids via MODULE_DEVICE_TABLE. We do not actually + * register a pci_driver, because someone else might one day + * want to register another driver on the same PCI id. + */ +static struct pci_device_id esb_pci_tbl[] = { + { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ESB_9), }, + { 0, }, /* End of list */ +}; +MODULE_DEVICE_TABLE (pci, esb_pci_tbl); + +/* + * Init & exit routines + */ + +static unsigned char __init esb_getdevice (void) +{ + u8 val1; + unsigned short val2; + + struct pci_dev *dev = NULL; + /* + * Find the PCI device + */ + + for_each_pci_dev(dev) { + if (pci_match_id(esb_pci_tbl, dev)) { + esb_pci = dev; + break; + } + } + + if (esb_pci) { + if (pci_enable_device(esb_pci)) { + printk (KERN_ERR PFX "failed to enable device\n"); + goto err_devput; + } + + if (pci_request_region(esb_pci, 0, ESB_MODULE_NAME)) { + printk (KERN_ERR PFX "failed to request region\n"); + goto err_disable; + } + + BASEADDR = ioremap(pci_resource_start(esb_pci, 0), + pci_resource_len(esb_pci, 0)); + if (BASEADDR == NULL) { + /* Something's wrong here, BASEADDR has to be set */ + printk (KERN_ERR PFX "failed to get BASEADDR\n"); + goto err_release; + } + + /* + * The watchdog has two timers, it can be setup so that the + * expiry of timer1 results in an interrupt and the expiry of + * timer2 results in a reboot. We set it to not generate + * any interrupts as there is not much we can do with it + * right now. + * + * We also enable reboots and set the timer frequency to + * the PCI clock divided by 2^15 (approx 1KHz). + */ + pci_write_config_word(esb_pci, ESB_CONFIG_REG, 0x0003); + + /* Check that the WDT isn't already locked */ + pci_read_config_byte(esb_pci, ESB_LOCK_REG, &val1); + if (val1 & ESB_WDT_LOCK) + printk (KERN_WARNING PFX "nowayout already set\n"); + + /* Set the timer to watchdog mode and disable it for now */ + pci_write_config_byte(esb_pci, ESB_LOCK_REG, 0x00); + + /* Check if the watchdog was previously triggered */ + esb_unlock_registers(); + val2 = readw(ESB_RELOAD_REG); + triggered = (val2 & (0x01 << 9) >> 9); + + /* Reset trigger flag and timers */ + esb_unlock_registers(); + writew((0x11 << 8), ESB_RELOAD_REG); + + /* Done */ + return 1; + +err_release: + pci_release_region(esb_pci, 0); +err_disable: + pci_disable_device(esb_pci); +err_devput: + pci_dev_put(esb_pci); + } + return 0; +} + +static int __init watchdog_init (void) +{ + int ret; + + spin_lock_init(&esb_lock); + + /* Check whether or not the hardware watchdog is there */ + if (!esb_getdevice () || esb_pci == NULL) + return -ENODEV; + + /* Check that the heartbeat value is within it's range ; if not reset to the default */ + if (esb_timer_set_heartbeat (heartbeat)) { + esb_timer_set_heartbeat (WATCHDOG_HEARTBEAT); + printk(KERN_INFO PFX "heartbeat value must be 1<heartbeat<2046, using %d\n", + heartbeat); + } + + ret = register_reboot_notifier(&esb_notifier); + if (ret != 0) { + printk(KERN_ERR PFX "cannot register reboot notifier (err=%d)\n", + ret); + goto err_unmap; + } + + ret = misc_register(&esb_miscdev); + if (ret != 0) { + printk(KERN_ERR PFX "cannot register miscdev on minor=%d (err=%d)\n", + WATCHDOG_MINOR, ret); + goto err_notifier; + } + + esb_timer_stop (); + + printk (KERN_INFO PFX "initialized (0x%p). heartbeat=%d sec (nowayout=%d)\n", + BASEADDR, heartbeat, nowayout); + + return 0; + +err_notifier: + unregister_reboot_notifier(&esb_notifier); +err_unmap: + iounmap(BASEADDR); +/* err_release: */ + pci_release_region(esb_pci, 0); +/* err_disable: */ + pci_disable_device(esb_pci); +/* err_devput: */ + pci_dev_put(esb_pci); + return ret; +} + +static void __exit watchdog_cleanup (void) +{ + /* Stop the timer before we leave */ + if (!nowayout) + esb_timer_stop (); + + /* Deregister */ + misc_deregister(&esb_miscdev); + unregister_reboot_notifier(&esb_notifier); + iounmap(BASEADDR); + pci_release_region(esb_pci, 0); + pci_disable_device(esb_pci); + pci_dev_put(esb_pci); +} + +module_init(watchdog_init); +module_exit(watchdog_cleanup); + +MODULE_AUTHOR("Ross Biro and David Härdeman"); +MODULE_DESCRIPTION("Watchdog driver for Intel 6300ESB chipsets"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR); diff --git a/drivers/char/watchdog/ibmasr.c b/drivers/char/watchdog/ibmasr.c new file mode 100644 index 0000000..294c474 --- /dev/null +++ b/drivers/char/watchdog/ibmasr.c @@ -0,0 +1,405 @@ +/* + * IBM Automatic Server Restart driver. + * + * Copyright (c) 2005 Andrey Panin <pazke@donpac.ru> + * + * Based on driver written by Pete Reynolds. + * Copyright (c) IBM Corporation, 1998-2004. + * + * This software may be used and distributed according to the terms + * of the GNU Public License, incorporated herein by reference. + */ + +#include <linux/config.h> +#include <linux/fs.h> +#include <linux/kernel.h> +#include <linux/slab.h> +#include <linux/module.h> +#include <linux/pci.h> +#include <linux/timer.h> +#include <linux/miscdevice.h> +#include <linux/watchdog.h> +#include <linux/dmi.h> + +#include <asm/io.h> +#include <asm/uaccess.h> + + +enum { + ASMTYPE_UNKNOWN, + ASMTYPE_TOPAZ, + ASMTYPE_JASPER, + ASMTYPE_PEARL, + ASMTYPE_JUNIPER, + ASMTYPE_SPRUCE, +}; + +#define PFX "ibmasr: " + +#define TOPAZ_ASR_REG_OFFSET 4 +#define TOPAZ_ASR_TOGGLE 0x40 +#define TOPAZ_ASR_DISABLE 0x80 + +/* PEARL ASR S/W REGISTER SUPERIO PORT ADDRESSES */ +#define PEARL_BASE 0xe04 +#define PEARL_WRITE 0xe06 +#define PEARL_READ 0xe07 + +#define PEARL_ASR_DISABLE_MASK 0x80 /* bit 7: disable = 1, enable = 0 */ +#define PEARL_ASR_TOGGLE_MASK 0x40 /* bit 6: 0, then 1, then 0 */ + +/* JASPER OFFSET FROM SIO BASE ADDR TO ASR S/W REGISTERS. */ +#define JASPER_ASR_REG_OFFSET 0x38 + +#define JASPER_ASR_DISABLE_MASK 0x01 /* bit 0: disable = 1, enable = 0 */ +#define JASPER_ASR_TOGGLE_MASK 0x02 /* bit 1: 0, then 1, then 0 */ + +#define JUNIPER_BASE_ADDRESS 0x54b /* Base address of Juniper ASR */ +#define JUNIPER_ASR_DISABLE_MASK 0x01 /* bit 0: disable = 1 enable = 0 */ +#define JUNIPER_ASR_TOGGLE_MASK 0x02 /* bit 1: 0, then 1, then 0 */ + +#define SPRUCE_BASE_ADDRESS 0x118e /* Base address of Spruce ASR */ +#define SPRUCE_ASR_DISABLE_MASK 0x01 /* bit 1: disable = 1 enable = 0 */ +#define SPRUCE_ASR_TOGGLE_MASK 0x02 /* bit 0: 0, then 1, then 0 */ + + +static int nowayout = WATCHDOG_NOWAYOUT; + +static unsigned long asr_is_open; +static char asr_expect_close; + +static unsigned int asr_type, asr_base, asr_length; +static unsigned int asr_read_addr, asr_write_addr; +static unsigned char asr_toggle_mask, asr_disable_mask; + +static void asr_toggle(void) +{ + unsigned char reg = inb(asr_read_addr); + + outb(reg & ~asr_toggle_mask, asr_write_addr); + reg = inb(asr_read_addr); + + outb(reg | asr_toggle_mask, asr_write_addr); + reg = inb(asr_read_addr); + + outb(reg & ~asr_toggle_mask, asr_write_addr); + reg = inb(asr_read_addr); +} + +static void asr_enable(void) +{ + unsigned char reg; + + if (asr_type == ASMTYPE_TOPAZ) { + /* asr_write_addr == asr_read_addr */ + reg = inb(asr_read_addr); + outb(reg & ~(TOPAZ_ASR_TOGGLE | TOPAZ_ASR_DISABLE), + asr_read_addr); + } else { + /* + * First make sure the hardware timer is reset by toggling + * ASR hardware timer line. + */ + asr_toggle(); + + reg = inb(asr_read_addr); + outb(reg & ~asr_disable_mask, asr_write_addr); + } + reg = inb(asr_read_addr); +} + +static void asr_disable(void) +{ + unsigned char reg = inb(asr_read_addr); + + if (asr_type == ASMTYPE_TOPAZ) + /* asr_write_addr == asr_read_addr */ + outb(reg | TOPAZ_ASR_TOGGLE | TOPAZ_ASR_DISABLE, + asr_read_addr); + else { + outb(reg | asr_toggle_mask, asr_write_addr); + reg = inb(asr_read_addr); + + outb(reg | asr_disable_mask, asr_write_addr); + } + reg = inb(asr_read_addr); +} + +static int __init asr_get_base_address(void) +{ + unsigned char low, high; + const char *type = ""; + + asr_length = 1; + + switch (asr_type) { + case ASMTYPE_TOPAZ: + /* SELECT SuperIO CHIP FOR QUERYING (WRITE 0x07 TO BOTH 0x2E and 0x2F) */ + outb(0x07, 0x2e); + outb(0x07, 0x2f); + + /* SELECT AND READ THE HIGH-NIBBLE OF THE GPIO BASE ADDRESS */ + outb(0x60, 0x2e); + high = inb(0x2f); + + /* SELECT AND READ THE LOW-NIBBLE OF THE GPIO BASE ADDRESS */ + outb(0x61, 0x2e); + low = inb(0x2f); + + asr_base = (high << 16) | low; + asr_read_addr = asr_write_addr = + asr_base + TOPAZ_ASR_REG_OFFSET; + asr_length = 5; + + break; + + case ASMTYPE_JASPER: + type = "Jaspers "; + + /* FIXME: need to use pci_config_lock here, but it's not exported */ + +/* spin_lock_irqsave(&pci_config_lock, flags);*/ + + /* Select the SuperIO chip in the PCI I/O port register */ + outl(0x8000f858, 0xcf8); + + /* + * Read the base address for the SuperIO chip. + * Only the lower 16 bits are valid, but the address is word + * aligned so the last bit must be masked off. + */ + asr_base = inl(0xcfc) & 0xfffe; + +/* spin_unlock_irqrestore(&pci_config_lock, flags);*/ + + asr_read_addr = asr_write_addr = + asr_base + JASPER_ASR_REG_OFFSET; + asr_toggle_mask = JASPER_ASR_TOGGLE_MASK; + asr_disable_mask = JASPER_ASR_DISABLE_MASK; + asr_length = JASPER_ASR_REG_OFFSET + 1; + + break; + + case ASMTYPE_PEARL: + type = "Pearls "; + asr_base = PEARL_BASE; + asr_read_addr = PEARL_READ; + asr_write_addr = PEARL_WRITE; + asr_toggle_mask = PEARL_ASR_TOGGLE_MASK; + asr_disable_mask = PEARL_ASR_DISABLE_MASK; + asr_length = 4; + break; + + case ASMTYPE_JUNIPER: + type = "Junipers "; + asr_base = JUNIPER_BASE_ADDRESS; + asr_read_addr = asr_write_addr = asr_base; + asr_toggle_mask = JUNIPER_ASR_TOGGLE_MASK; + asr_disable_mask = JUNIPER_ASR_DISABLE_MASK; + break; + + case ASMTYPE_SPRUCE: + type = "Spruce's "; + asr_base = SPRUCE_BASE_ADDRESS; + asr_read_addr = asr_write_addr = asr_base; + asr_toggle_mask = SPRUCE_ASR_TOGGLE_MASK; + asr_disable_mask = SPRUCE_ASR_DISABLE_MASK; + break; + } + + if (!request_region(asr_base, asr_length, "ibmasr")) { + printk(KERN_ERR PFX "address %#x already in use\n", + asr_base); + return -EBUSY; + } + + printk(KERN_INFO PFX "found %sASR @ addr %#x\n", type, asr_base); + + return 0; +} + + +static ssize_t asr_write(struct file *file, const char __user *buf, + size_t count, loff_t *ppos) +{ + if (count) { + if (!nowayout) { + size_t i; + + /* In case it was set long ago */ + asr_expect_close = 0; + + for (i = 0; i != count; i++) { + char c; + if (get_user(c, buf + i)) + return -EFAULT; + if (c == 'V') + asr_expect_close = 42; + } + } + asr_toggle(); + } + return count; +} + +static int asr_ioctl(struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg) +{ + static const struct watchdog_info ident = { + .options = WDIOF_KEEPALIVEPING | + WDIOF_MAGICCLOSE, + .identity = "IBM ASR" + }; + void __user *argp = (void __user *)arg; + int __user *p = argp; + int heartbeat; + + switch (cmd) { + case WDIOC_GETSUPPORT: + return copy_to_user(argp, &ident, sizeof(ident)) ? + -EFAULT : 0; + + case WDIOC_GETSTATUS: + case WDIOC_GETBOOTSTATUS: + return put_user(0, p); + + case WDIOC_KEEPALIVE: + asr_toggle(); + return 0; + + /* + * The hardware has a fixed timeout value, so no WDIOC_SETTIMEOUT + * and WDIOC_GETTIMEOUT always returns 256. + */ + case WDIOC_GETTIMEOUT: + heartbeat = 256; + return put_user(heartbeat, p); + + case WDIOC_SETOPTIONS: { + int new_options, retval = -EINVAL; + + if (get_user(new_options, p)) + return -EFAULT; + + if (new_options & WDIOS_DISABLECARD) { + asr_disable(); + retval = 0; + } + + if (new_options & WDIOS_ENABLECARD) { + asr_enable(); + asr_toggle(); + retval = 0; + } + + return retval; + } + } + + return -ENOIOCTLCMD; +} + +static int asr_open(struct inode *inode, struct file *file) +{ + if(test_and_set_bit(0, &asr_is_open)) + return -EBUSY; + + asr_toggle(); + asr_enable(); + + return nonseekable_open(inode, file); +} + +static int asr_release(struct inode *inode, struct file *file) +{ + if (asr_expect_close == 42) + asr_disable(); + else { + printk(KERN_CRIT PFX "unexpected close, not stopping watchdog!\n"); + asr_toggle(); + } + clear_bit(0, &asr_is_open); + asr_expect_close = 0; + return 0; +} + +static struct file_operations asr_fops = { + .owner = THIS_MODULE, + .llseek = no_llseek, + .write = asr_write, + .ioctl = asr_ioctl, + .open = asr_open, + .release = asr_release, +}; + +static struct miscdevice asr_miscdev = { + .minor = WATCHDOG_MINOR, + .name = "watchdog", + .fops = &asr_fops, +}; + + +struct ibmasr_id { + const char *desc; + int type; +}; + +static struct ibmasr_id __initdata ibmasr_id_table[] = { + { "IBM Automatic Server Restart - eserver xSeries 220", ASMTYPE_TOPAZ }, + { "IBM Automatic Server Restart - Machine Type 8673", ASMTYPE_PEARL }, + { "IBM Automatic Server Restart - Machine Type 8480", ASMTYPE_JASPER }, + { "IBM Automatic Server Restart - Machine Type 8482", ASMTYPE_JUNIPER }, + { "IBM Automatic Server Restart - Machine Type 8648", ASMTYPE_SPRUCE }, + { NULL } +}; + +static int __init ibmasr_init(void) +{ + struct ibmasr_id *id; + int rc; + + for (id = ibmasr_id_table; id->desc; id++) { + if (dmi_find_device(DMI_DEV_TYPE_OTHER, id->desc, NULL)) { + asr_type = id->type; + break; + } + } + + if (!asr_type) + return -ENODEV; + + rc = misc_register(&asr_miscdev); + if (rc < 0) { + printk(KERN_ERR PFX "failed to register misc device\n"); + return rc; + } + + rc = asr_get_base_address(); + if (rc) { + misc_deregister(&asr_miscdev); + return rc; + } + + return 0; +} + +static void __exit ibmasr_exit(void) +{ + if (!nowayout) + asr_disable(); + + misc_deregister(&asr_miscdev); + + release_region(asr_base, asr_length); +} + +module_init(ibmasr_init); +module_exit(ibmasr_exit); + +module_param(nowayout, int, 0); +MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)"); + +MODULE_DESCRIPTION("IBM Automatic Server Restart driver"); +MODULE_AUTHOR("Andrey Panin"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR); diff --git a/drivers/char/watchdog/mpcore_wdt.c b/drivers/char/watchdog/mpcore_wdt.c index c694eee..75ca84e 100644 --- a/drivers/char/watchdog/mpcore_wdt.c +++ b/drivers/char/watchdog/mpcore_wdt.c @@ -30,6 +30,8 @@ #include <linux/init.h> #include <linux/interrupt.h> #include <linux/device.h> + +#include <asm/hardware/arm_twd.h> #include <asm/uaccess.h> struct mpcore_wdt { diff --git a/drivers/char/watchdog/mv64x60_wdt.c b/drivers/char/watchdog/mv64x60_wdt.c new file mode 100644 index 0000000..1436aea --- /dev/null +++ b/drivers/char/watchdog/mv64x60_wdt.c @@ -0,0 +1,252 @@ +/* + * mv64x60_wdt.c - MV64X60 (Marvell Discovery) watchdog userspace interface + * + * Author: James Chapman <jchapman@katalix.com> + * + * Platform-specific setup code should configure the dog to generate + * interrupt or reset as required. This code only enables/disables + * and services the watchdog. + * + * Derived from mpc8xx_wdt.c, with the following copyright. + * + * 2002 (c) Florian Schirmer <jolt@tuxbox.org> 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. + */ + +#include <linux/config.h> +#include <linux/fs.h> +#include <linux/init.h> +#include <linux/kernel.h> +#include <linux/miscdevice.h> +#include <linux/module.h> +#include <linux/watchdog.h> +#include <asm/mv64x60.h> +#include <asm/uaccess.h> +#include <asm/io.h> + +/* MV64x60 WDC (config) register access definitions */ +#define MV64x60_WDC_CTL1_MASK (3 << 24) +#define MV64x60_WDC_CTL1(val) ((val & 3) << 24) +#define MV64x60_WDC_CTL2_MASK (3 << 26) +#define MV64x60_WDC_CTL2(val) ((val & 3) << 26) + +/* Flags bits */ +#define MV64x60_WDOG_FLAG_OPENED 0 +#define MV64x60_WDOG_FLAG_ENABLED 1 + +static unsigned long wdt_flags; +static int wdt_status; +static void __iomem *mv64x60_regs; +static int mv64x60_wdt_timeout; + +static void mv64x60_wdt_reg_write(u32 val) +{ + /* Allow write only to CTL1 / CTL2 fields, retaining values in + * other fields. + */ + u32 data = readl(mv64x60_regs + MV64x60_WDT_WDC); + data &= ~(MV64x60_WDC_CTL1_MASK | MV64x60_WDC_CTL2_MASK); + data |= val; + writel(data, mv64x60_regs + MV64x60_WDT_WDC); +} + +static void mv64x60_wdt_service(void) +{ + /* Write 01 followed by 10 to CTL2 */ + mv64x60_wdt_reg_write(MV64x60_WDC_CTL2(0x01)); + mv64x60_wdt_reg_write(MV64x60_WDC_CTL2(0x02)); +} + +static void mv64x60_wdt_handler_disable(void) +{ + if (test_and_clear_bit(MV64x60_WDOG_FLAG_ENABLED, &wdt_flags)) { + /* Write 01 followed by 10 to CTL1 */ + mv64x60_wdt_reg_write(MV64x60_WDC_CTL1(0x01)); + mv64x60_wdt_reg_write(MV64x60_WDC_CTL1(0x02)); + printk(KERN_NOTICE "mv64x60_wdt: watchdog deactivated\n"); + } +} + +static void mv64x60_wdt_handler_enable(void) +{ + if (!test_and_set_bit(MV64x60_WDOG_FLAG_ENABLED, &wdt_flags)) { + /* Write 01 followed by 10 to CTL1 */ + mv64x60_wdt_reg_write(MV64x60_WDC_CTL1(0x01)); + mv64x60_wdt_reg_write(MV64x60_WDC_CTL1(0x02)); + printk(KERN_NOTICE "mv64x60_wdt: watchdog activated\n"); + } +} + +static int mv64x60_wdt_open(struct inode *inode, struct file *file) +{ + if (test_and_set_bit(MV64x60_WDOG_FLAG_OPENED, &wdt_flags)) + return -EBUSY; + + mv64x60_wdt_service(); + mv64x60_wdt_handler_enable(); + + return 0; +} + +static int mv64x60_wdt_release(struct inode *inode, struct file *file) +{ + mv64x60_wdt_service(); + +#if !defined(CONFIG_WATCHDOG_NOWAYOUT) + mv64x60_wdt_handler_disable(); +#endif + + clear_bit(MV64x60_WDOG_FLAG_OPENED, &wdt_flags); + + return 0; +} + +static ssize_t mv64x60_wdt_write(struct file *file, const char *data, + size_t len, loff_t * ppos) +{ + if (*ppos != file->f_pos) + return -ESPIPE; + + if (len) + mv64x60_wdt_service(); + + return len; +} + +static int mv64x60_wdt_ioctl(struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg) +{ + int timeout; + static struct watchdog_info info = { + .options = WDIOF_KEEPALIVEPING, + .firmware_version = 0, + .identity = "MV64x60 watchdog", + }; + + switch (cmd) { + case WDIOC_GETSUPPORT: + if (copy_to_user((void *)arg, &info, sizeof(info))) + return -EFAULT; + break; + + case WDIOC_GETSTATUS: + case WDIOC_GETBOOTSTATUS: + if (put_user(wdt_status, (int *)arg)) + return -EFAULT; + wdt_status &= ~WDIOF_KEEPALIVEPING; + break; + + case WDIOC_GETTEMP: + return -EOPNOTSUPP; + + case WDIOC_SETOPTIONS: + return -EOPNOTSUPP; + + case WDIOC_KEEPALIVE: + mv64x60_wdt_service(); + wdt_status |= WDIOF_KEEPALIVEPING; + break; + + case WDIOC_SETTIMEOUT: + return -EOPNOTSUPP; + + case WDIOC_GETTIMEOUT: + timeout = mv64x60_wdt_timeout * HZ; + if (put_user(timeout, (int *)arg)) + return -EFAULT; + break; + + default: + return -ENOIOCTLCMD; + } + + return 0; +} + +static struct file_operations mv64x60_wdt_fops = { + .owner = THIS_MODULE, + .llseek = no_llseek, + .write = mv64x60_wdt_write, + .ioctl = mv64x60_wdt_ioctl, + .open = mv64x60_wdt_open, + .release = mv64x60_wdt_release, +}; + +static struct miscdevice mv64x60_wdt_miscdev = { + .minor = WATCHDOG_MINOR, + .name = "watchdog", + .fops = &mv64x60_wdt_fops, +}; + +static int __devinit mv64x60_wdt_probe(struct device *dev) +{ + struct platform_device *pd = to_platform_device(dev); + struct mv64x60_wdt_pdata *pdata = pd->dev.platform_data; + int bus_clk = 133; + + mv64x60_wdt_timeout = 10; + if (pdata) { + mv64x60_wdt_timeout = pdata->timeout; + bus_clk = pdata->bus_clk; + } + + mv64x60_regs = mv64x60_get_bridge_vbase(); + + writel((mv64x60_wdt_timeout * (bus_clk * 1000000)) >> 8, + mv64x60_regs + MV64x60_WDT_WDC); + + return misc_register(&mv64x60_wdt_miscdev); +} + +static int __devexit mv64x60_wdt_remove(struct device *dev) +{ + misc_deregister(&mv64x60_wdt_miscdev); + + mv64x60_wdt_service(); + mv64x60_wdt_handler_disable(); + + return 0; +} + +static struct device_driver mv64x60_wdt_driver = { + .name = MV64x60_WDT_NAME, + .bus = &platform_bus_type, + .probe = mv64x60_wdt_probe, + .remove = __devexit_p(mv64x60_wdt_remove), +}; + +static struct platform_device *mv64x60_wdt_dev; + +static int __init mv64x60_wdt_init(void) +{ + int ret; + + printk(KERN_INFO "MV64x60 watchdog driver\n"); + + mv64x60_wdt_dev = platform_device_register_simple(MV64x60_WDT_NAME, + -1, NULL, 0); + if (IS_ERR(mv64x60_wdt_dev)) { + ret = PTR_ERR(mv64x60_wdt_dev); + goto out; + } + + ret = driver_register(&mv64x60_wdt_driver); + out: + return ret; +} + +static void __exit mv64x60_wdt_exit(void) +{ + driver_unregister(&mv64x60_wdt_driver); + platform_device_unregister(mv64x60_wdt_dev); +} + +module_init(mv64x60_wdt_init); +module_exit(mv64x60_wdt_exit); + +MODULE_AUTHOR("James Chapman <jchapman@katalix.com>"); +MODULE_DESCRIPTION("MV64x60 watchdog driver"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR); diff --git a/drivers/char/watchdog/pcwd_pci.c b/drivers/char/watchdog/pcwd_pci.c index 2b13afb..5a80adb 100644 --- a/drivers/char/watchdog/pcwd_pci.c +++ b/drivers/char/watchdog/pcwd_pci.c @@ -29,27 +29,29 @@ * Includes, defines, variables, module parameters, ... */ -#include <linux/config.h> -#include <linux/module.h> -#include <linux/moduleparam.h> -#include <linux/types.h> -#include <linux/delay.h> -#include <linux/miscdevice.h> -#include <linux/watchdog.h> -#include <linux/notifier.h> -#include <linux/reboot.h> -#include <linux/init.h> -#include <linux/fs.h> -#include <linux/pci.h> -#include <linux/ioport.h> -#include <linux/spinlock.h> - -#include <asm/uaccess.h> -#include <asm/io.h> +#include <linux/config.h> /* For CONFIG_WATCHDOG_NOWAYOUT/... */ +#include <linux/module.h> /* For module specific items */ +#include <linux/moduleparam.h> /* For new moduleparam's */ +#include <linux/types.h> /* For standard types (like size_t) */ +#include <linux/errno.h> /* For the -ENODEV/... values */ +#include <linux/kernel.h> /* For printk/panic/... */ +#include <linux/delay.h> /* For mdelay function */ +#include <linux/miscdevice.h> /* For MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR) */ +#include <linux/watchdog.h> /* For the watchdog specific items */ +#include <linux/notifier.h> /* For notifier support */ +#include <linux/reboot.h> /* For reboot_notifier stuff */ +#include <linux/init.h> /* For __init/__exit/... */ +#include <linux/fs.h> /* For file operations */ +#include <linux/pci.h> /* For pci functions */ +#include <linux/ioport.h> /* For io-port access */ +#include <linux/spinlock.h> /* For spin_lock/spin_unlock/... */ + +#include <asm/uaccess.h> /* For copy_to_user/put_user/... */ +#include <asm/io.h> /* For inb/outb/... */ /* Module and version information */ #define WATCHDOG_VERSION "1.01" -#define WATCHDOG_DATE "15 Mar 2005" +#define WATCHDOG_DATE "02 Sep 2005" #define WATCHDOG_DRIVER_NAME "PCI-PC Watchdog" #define WATCHDOG_NAME "pcwd_pci" #define PFX WATCHDOG_NAME ": " @@ -335,12 +337,14 @@ static int pcipcwd_ioctl(struct inode *inode, struct file *file, return -EFAULT; if (new_options & WDIOS_DISABLECARD) { - pcipcwd_stop(); + if (pcipcwd_stop()) + return -EIO; retval = 0; } if (new_options & WDIOS_ENABLECARD) { - pcipcwd_start(); + if (pcipcwd_start()) + return -EIO; retval = 0; } diff --git a/drivers/char/watchdog/s3c2410_wdt.c b/drivers/char/watchdog/s3c2410_wdt.c index 8b292bf..3625b26 100644 --- a/drivers/char/watchdog/s3c2410_wdt.c +++ b/drivers/char/watchdog/s3c2410_wdt.c @@ -464,7 +464,7 @@ static void s3c2410wdt_shutdown(struct device *dev) static unsigned long wtcon_save; static unsigned long wtdat_save; -static int s3c2410wdt_suspend(struct device *dev, u32 state, u32 level) +static int s3c2410wdt_suspend(struct device *dev, pm_message_t state, u32 level) { if (level == SUSPEND_POWER_DOWN) { /* Save watchdog state, and turn it off. */ diff --git a/drivers/char/watchdog/sbc8360.c b/drivers/char/watchdog/sbc8360.c new file mode 100644 index 0000000..c6cbf80 --- /dev/null +++ b/drivers/char/watchdog/sbc8360.c @@ -0,0 +1,414 @@ +/* + * SBC8360 Watchdog driver + * + * (c) Copyright 2005 Webcon, Inc. + * + * Based on ib700wdt.c, which is based on advantechwdt.c which is based + * on acquirewdt.c which is based on wdt.c. + * + * (c) Copyright 2001 Charles Howes <chowes@vsol.net> + * + * Based on advantechwdt.c which is based on acquirewdt.c which + * is based on wdt.c. + * + * (c) Copyright 2000-2001 Marek Michalkiewicz <marekm@linux.org.pl> + * + * Based on acquirewdt.c which is based on wdt.c. + * Original copyright messages: + * + * (c) Copyright 1996 Alan Cox <alan@redhat.com>, All Rights Reserved. + * http://www.redhat.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. + * + * Neither Alan Cox nor CymruNet Ltd. admit liability nor provide + * warranty for any of this software. This material is provided + * "AS-IS" and at no charge. + * + * (c) Copyright 1995 Alan Cox <alan@redhat.com> + * + * 14-Dec-2001 Matt Domsch <Matt_Domsch@dell.com> + * Added nowayout module option to override CONFIG_WATCHDOG_NOWAYOUT + * Added timeout module option to override default + * + */ + +#include <linux/config.h> +#include <linux/module.h> +#include <linux/types.h> +#include <linux/miscdevice.h> +#include <linux/watchdog.h> +#include <linux/ioport.h> +#include <linux/delay.h> +#include <linux/notifier.h> +#include <linux/fs.h> +#include <linux/reboot.h> +#include <linux/init.h> +#include <linux/spinlock.h> +#include <linux/moduleparam.h> + +#include <asm/io.h> +#include <asm/uaccess.h> +#include <asm/system.h> + +static unsigned long sbc8360_is_open; +static spinlock_t sbc8360_lock; +static char expect_close; + +#define PFX "sbc8360: " + +/* + * + * Watchdog Timer Configuration + * + * The function of the watchdog timer is to reset the system automatically + * and is defined at I/O port 0120H and 0121H. To enable the watchdog timer + * and allow the system to reset, write appropriate values from the table + * below to I/O port 0120H and 0121H. To disable the timer, write a zero + * value to I/O port 0121H for the system to stop the watchdog function. + * + * The following describes how the timer should be programmed (according to + * the vendor documentation) + * + * Enabling Watchdog: + * MOV AX,000AH (enable, phase I) + * MOV DX,0120H + * OUT DX,AX + * MOV AX,000BH (enable, phase II) + * MOV DX,0120H + * OUT DX,AX + * MOV AX,000nH (set multiplier n, from 1-4) + * MOV DX,0120H + * OUT DX,AX + * MOV AX,000mH (set base timer m, from 0-F) + * MOV DX,0121H + * OUT DX,AX + * + * Reset timer: + * MOV AX,000mH (same as set base timer, above) + * MOV DX,0121H + * OUT DX,AX + * + * Disabling Watchdog: + * MOV AX,0000H (a zero value) + * MOV DX,0120H + * OUT DX,AX + * + * Watchdog timeout configuration values: + * N + * M | 1 2 3 4 + * --|---------------------------------- + * 0 | 0.5s 5s 50s 100s + * 1 | 1s 10s 100s 200s + * 2 | 1.5s 15s 150s 300s + * 3 | 2s 20s 200s 400s + * 4 | 2.5s 25s 250s 500s + * 5 | 3s 30s 300s 600s + * 6 | 3.5s 35s 350s 700s + * 7 | 4s 40s 400s 800s + * 8 | 4.5s 45s 450s 900s + * 9 | 5s 50s 500s 1000s + * A | 5.5s 55s 550s 1100s + * B | 6s 60s 600s 1200s + * C | 6.5s 65s 650s 1300s + * D | 7s 70s 700s 1400s + * E | 7.5s 75s 750s 1500s + * F | 8s 80s 800s 1600s + * + * Another way to say the same things is: + * For N=1, Timeout = (M+1) * 0.5s + * For N=2, Timeout = (M+1) * 5s + * For N=3, Timeout = (M+1) * 50s + * For N=4, Timeout = (M+1) * 100s + * + */ + +static int wd_times[64][2] = { + {0, 1}, /* 0 = 0.5s */ + {1, 1}, /* 1 = 1s */ + {2, 1}, /* 2 = 1.5s */ + {3, 1}, /* 3 = 2s */ + {4, 1}, /* 4 = 2.5s */ + {5, 1}, /* 5 = 3s */ + {6, 1}, /* 6 = 3.5s */ + {7, 1}, /* 7 = 4s */ + {8, 1}, /* 8 = 4.5s */ + {9, 1}, /* 9 = 5s */ + {0xA, 1}, /* 10 = 5.5s */ + {0xB, 1}, /* 11 = 6s */ + {0xC, 1}, /* 12 = 6.5s */ + {0xD, 1}, /* 13 = 7s */ + {0xE, 1}, /* 14 = 7.5s */ + {0xF, 1}, /* 15 = 8s */ + {0, 2}, /* 16 = 5s */ + {1, 2}, /* 17 = 10s */ + {2, 2}, /* 18 = 15s */ + {3, 2}, /* 19 = 20s */ + {4, 2}, /* 20 = 25s */ + {5, 2}, /* 21 = 30s */ + {6, 2}, /* 22 = 35s */ + {7, 2}, /* 23 = 40s */ + {8, 2}, /* 24 = 45s */ + {9, 2}, /* 25 = 50s */ + {0xA, 2}, /* 26 = 55s */ + {0xB, 2}, /* 27 = 60s */ + {0xC, 2}, /* 28 = 65s */ + {0xD, 2}, /* 29 = 70s */ + {0xE, 2}, /* 30 = 75s */ + {0xF, 2}, /* 31 = 80s */ + {0, 3}, /* 32 = 50s */ + {1, 3}, /* 33 = 100s */ + {2, 3}, /* 34 = 150s */ + {3, 3}, /* 35 = 200s */ + {4, 3}, /* 36 = 250s */ + {5, 3}, /* 37 = 300s */ + {6, 3}, /* 38 = 350s */ + {7, 3}, /* 39 = 400s */ + {8, 3}, /* 40 = 450s */ + {9, 3}, /* 41 = 500s */ + {0xA, 3}, /* 42 = 550s */ + {0xB, 3}, /* 43 = 600s */ + {0xC, 3}, /* 44 = 650s */ + {0xD, 3}, /* 45 = 700s */ + {0xE, 3}, /* 46 = 750s */ + {0xF, 3}, /* 47 = 800s */ + {0, 4}, /* 48 = 100s */ + {1, 4}, /* 49 = 200s */ + {2, 4}, /* 50 = 300s */ + {3, 4}, /* 51 = 400s */ + {4, 4}, /* 52 = 500s */ + {5, 4}, /* 53 = 600s */ + {6, 4}, /* 54 = 700s */ + {7, 4}, /* 55 = 800s */ + {8, 4}, /* 56 = 900s */ + {9, 4}, /* 57 = 1000s */ + {0xA, 4}, /* 58 = 1100s */ + {0xB, 4}, /* 59 = 1200s */ + {0xC, 4}, /* 60 = 1300s */ + {0xD, 4}, /* 61 = 1400s */ + {0xE, 4}, /* 62 = 1500s */ + {0xF, 4} /* 63 = 1600s */ +}; + +#define SBC8360_ENABLE 0x120 +#define SBC8360_BASETIME 0x121 + +static int timeout = 27; +static int wd_margin = 0xB; +static int wd_multiplier = 2; +static int nowayout = WATCHDOG_NOWAYOUT; + +module_param(timeout, int, 27); +MODULE_PARM_DESC(timeout, "Index into timeout table (0-63) (default=27 (60s))"); +module_param(nowayout, int, 0); +MODULE_PARM_DESC(nowayout, + "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)"); + +/* + * Kernel methods. + */ + +/* Activate and pre-configure watchdog */ +static void sbc8360_activate(void) +{ + /* Enable the watchdog */ + outb(0x0A, SBC8360_ENABLE); + msleep_interruptible(100); + outb(0x0B, SBC8360_ENABLE); + msleep_interruptible(100); + /* Set timeout multiplier */ + outb(wd_multiplier, SBC8360_ENABLE); + msleep_interruptible(100); + /* Nothing happens until first sbc8360_ping() */ +} + +/* Kernel pings watchdog */ +static void sbc8360_ping(void) +{ + /* Write the base timer register */ + outb(wd_margin, SBC8360_BASETIME); +} + +/* Userspace pings kernel driver, or requests clean close */ +static ssize_t sbc8360_write(struct file *file, const char __user * buf, + size_t count, loff_t * ppos) +{ + if (count) { + if (!nowayout) { + size_t i; + + /* In case it was set long ago */ + expect_close = 0; + + for (i = 0; i != count; i++) { + char c; + if (get_user(c, buf + i)) + return -EFAULT; + if (c == 'V') + expect_close = 42; + } + } + sbc8360_ping(); + } + return count; +} + +static int sbc8360_open(struct inode *inode, struct file *file) +{ + spin_lock(&sbc8360_lock); + if (test_and_set_bit(0, &sbc8360_is_open)) { + spin_unlock(&sbc8360_lock); + return -EBUSY; + } + if (nowayout) + __module_get(THIS_MODULE); + + /* Activate and ping once to start the countdown */ + spin_unlock(&sbc8360_lock); + sbc8360_activate(); + sbc8360_ping(); + return nonseekable_open(inode, file); +} + +static int sbc8360_close(struct inode *inode, struct file *file) +{ + spin_lock(&sbc8360_lock); + if (expect_close == 42) + outb(0, SBC8360_ENABLE); + else + printk(KERN_CRIT PFX + "SBC8360 device closed unexpectedly. SBC8360 will not stop!\n"); + + clear_bit(0, &sbc8360_is_open); + expect_close = 0; + spin_unlock(&sbc8360_lock); + return 0; +} + +/* + * Notifier for system down + */ + +static int sbc8360_notify_sys(struct notifier_block *this, unsigned long code, + void *unused) +{ + if (code == SYS_DOWN || code == SYS_HALT) { + /* Disable the SBC8360 Watchdog */ + outb(0, SBC8360_ENABLE); + } + return NOTIFY_DONE; +} + +/* + * Kernel Interfaces + */ + +static struct file_operations sbc8360_fops = { + .owner = THIS_MODULE, + .llseek = no_llseek, + .write = sbc8360_write, + .open = sbc8360_open, + .release = sbc8360_close, +}; + +static struct miscdevice sbc8360_miscdev = { + .minor = WATCHDOG_MINOR, + .name = "watchdog", + .fops = &sbc8360_fops, +}; + +/* + * The SBC8360 needs to learn about soft shutdowns in order to + * turn the timebomb registers off. + */ + +static struct notifier_block sbc8360_notifier = { + .notifier_call = sbc8360_notify_sys, +}; + +static int __init sbc8360_init(void) +{ + int res; + unsigned long int mseconds = 60000; + + spin_lock_init(&sbc8360_lock); + res = misc_register(&sbc8360_miscdev); + if (res) { + printk(KERN_ERR PFX "failed to register misc device\n"); + goto out_nomisc; + } + + if (!request_region(SBC8360_ENABLE, 1, "SBC8360")) { + printk(KERN_ERR PFX "ENABLE method I/O %X is not available.\n", + SBC8360_ENABLE); + res = -EIO; + goto out_noenablereg; + } + if (!request_region(SBC8360_BASETIME, 1, "SBC8360")) { + printk(KERN_ERR PFX + "BASETIME method I/O %X is not available.\n", + SBC8360_BASETIME); + res = -EIO; + goto out_nobasetimereg; + } + + res = register_reboot_notifier(&sbc8360_notifier); + if (res) { + printk(KERN_ERR PFX "Failed to register reboot notifier.\n"); + goto out_noreboot; + } + + if (timeout < 0 || timeout > 63) { + printk(KERN_ERR PFX "Invalid timeout index (must be 0-63).\n"); + res = -EINVAL; + goto out_noreboot; + } + + wd_margin = wd_times[timeout][0]; + wd_multiplier = wd_times[timeout][1]; + + if (wd_multiplier == 1) + mseconds = (wd_margin + 1) * 500; + else if (wd_multiplier == 2) + mseconds = (wd_margin + 1) * 5000; + else if (wd_multiplier == 3) + mseconds = (wd_margin + 1) * 50000; + else if (wd_multiplier == 4) + mseconds = (wd_margin + 1) * 100000; + + /* My kingdom for the ability to print "0.5 seconds" in the kernel! */ + printk(KERN_INFO PFX "Timeout set at %ld ms.\n", mseconds); + + return 0; + + out_noreboot: + release_region(SBC8360_ENABLE, 1); + release_region(SBC8360_BASETIME, 1); + out_noenablereg: + out_nobasetimereg: + misc_deregister(&sbc8360_miscdev); + out_nomisc: + return res; +} + +static void __exit sbc8360_exit(void) +{ + misc_deregister(&sbc8360_miscdev); + unregister_reboot_notifier(&sbc8360_notifier); + release_region(SBC8360_ENABLE, 1); + release_region(SBC8360_BASETIME, 1); +} + +module_init(sbc8360_init); +module_exit(sbc8360_exit); + +MODULE_AUTHOR("Ian E. Morgan <imorgan@webcon.ca>"); +MODULE_DESCRIPTION("SBC8360 watchdog driver"); +MODULE_LICENSE("GPL"); +MODULE_VERSION("1.0"); +MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR); + +/* end of sbc8360.c */ diff --git a/drivers/char/watchdog/w83977f_wdt.c b/drivers/char/watchdog/w83977f_wdt.c new file mode 100644 index 0000000..a7ff64c --- /dev/null +++ b/drivers/char/watchdog/w83977f_wdt.c @@ -0,0 +1,543 @@ +/* + * W83977F Watchdog Timer Driver for Winbond W83977F I/O Chip + * + * (c) Copyright 2005 Jose Goncalves <jose.goncalves@inov.pt> + * + * Based on w83877f_wdt.c by Scott Jennings, + * and wdt977.c by Woody Suwalski + * + * ----------------------- + * + * This 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 <linux/module.h> +#include <linux/moduleparam.h> +#include <linux/config.h> +#include <linux/types.h> +#include <linux/kernel.h> +#include <linux/fs.h> +#include <linux/miscdevice.h> +#include <linux/init.h> +#include <linux/ioport.h> +#include <linux/watchdog.h> +#include <linux/notifier.h> +#include <linux/reboot.h> + +#include <asm/io.h> +#include <asm/system.h> +#include <asm/uaccess.h> + +#define WATCHDOG_VERSION "1.00" +#define WATCHDOG_NAME "W83977F WDT" +#define PFX WATCHDOG_NAME ": " +#define DRIVER_VERSION WATCHDOG_NAME " driver, v" WATCHDOG_VERSION "\n" + +#define IO_INDEX_PORT 0x3F0 +#define IO_DATA_PORT (IO_INDEX_PORT+1) + +#define UNLOCK_DATA 0x87 +#define LOCK_DATA 0xAA +#define DEVICE_REGISTER 0x07 + +#define DEFAULT_TIMEOUT 45 /* default timeout in seconds */ + +static int timeout = DEFAULT_TIMEOUT; +static int timeoutW; /* timeout in watchdog counter units */ +static unsigned long timer_alive; +static int testmode; +static char expect_close; +static spinlock_t spinlock; + +module_param(timeout, int, 0); +MODULE_PARM_DESC(timeout,"Watchdog timeout in seconds (15..7635), default=" __MODULE_STRING(DEFAULT_TIMEOUT) ")"); +module_param(testmode, int, 0); +MODULE_PARM_DESC(testmode,"Watchdog testmode (1 = no reboot), default=0"); + +static int nowayout = WATCHDOG_NOWAYOUT; +module_param(nowayout, int, 0); +MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)"); + +/* + * Start the watchdog + */ + +static int wdt_start(void) +{ + unsigned long flags; + + spin_lock_irqsave(&spinlock, flags); + + /* Unlock the SuperIO chip */ + outb_p(UNLOCK_DATA,IO_INDEX_PORT); + outb_p(UNLOCK_DATA,IO_INDEX_PORT); + + /* + * Select device Aux2 (device=8) to set watchdog regs F2, F3 and F4. + * F2 has the timeout in watchdog counter units. + * F3 is set to enable watchdog LED blink at timeout. + * F4 is used to just clear the TIMEOUT'ed state (bit 0). + */ + outb_p(DEVICE_REGISTER,IO_INDEX_PORT); + outb_p(0x08,IO_DATA_PORT); + outb_p(0xF2,IO_INDEX_PORT); + outb_p(timeoutW,IO_DATA_PORT); + outb_p(0xF3,IO_INDEX_PORT); + outb_p(0x08,IO_DATA_PORT); + outb_p(0xF4,IO_INDEX_PORT); + outb_p(0x00,IO_DATA_PORT); + + /* Set device Aux2 active */ + outb_p(0x30,IO_INDEX_PORT); + outb_p(0x01,IO_DATA_PORT); + + /* + * Select device Aux1 (dev=7) to set GP16 as the watchdog output + * (in reg E6) and GP13 as the watchdog LED output (in reg E3). + * Map GP16 at pin 119. + * In test mode watch the bit 0 on F4 to indicate "triggered" or + * check watchdog LED on SBC. + */ + outb_p(DEVICE_REGISTER,IO_INDEX_PORT); + outb_p(0x07,IO_DATA_PORT); + if (!testmode) + { + unsigned pin_map; + + outb_p(0xE6,IO_INDEX_PORT); + outb_p(0x0A,IO_DATA_PORT); + outb_p(0x2C,IO_INDEX_PORT); + pin_map = inb_p(IO_DATA_PORT); + pin_map |= 0x10; + pin_map &= ~(0x20); + outb_p(0x2C,IO_INDEX_PORT); + outb_p(pin_map,IO_DATA_PORT); + } + outb_p(0xE3,IO_INDEX_PORT); + outb_p(0x08,IO_DATA_PORT); + + /* Set device Aux1 active */ + outb_p(0x30,IO_INDEX_PORT); + outb_p(0x01,IO_DATA_PORT); + + /* Lock the SuperIO chip */ + outb_p(LOCK_DATA,IO_INDEX_PORT); + + spin_unlock_irqrestore(&spinlock, flags); + + printk(KERN_INFO PFX "activated.\n"); + + return 0; +} + +/* + * Stop the watchdog + */ + +static int wdt_stop(void) +{ + unsigned long flags; + + spin_lock_irqsave(&spinlock, flags); + + /* Unlock the SuperIO chip */ + outb_p(UNLOCK_DATA,IO_INDEX_PORT); + outb_p(UNLOCK_DATA,IO_INDEX_PORT); + + /* + * Select device Aux2 (device=8) to set watchdog regs F2, F3 and F4. + * F2 is reset to its default value (watchdog timer disabled). + * F3 is reset to its default state. + * F4 clears the TIMEOUT'ed state (bit 0) - back to default. + */ + outb_p(DEVICE_REGISTER,IO_INDEX_PORT); + outb_p(0x08,IO_DATA_PORT); + outb_p(0xF2,IO_INDEX_PORT); + outb_p(0xFF,IO_DATA_PORT); + outb_p(0xF3,IO_INDEX_PORT); + outb_p(0x00,IO_DATA_PORT); + outb_p(0xF4,IO_INDEX_PORT); + outb_p(0x00,IO_DATA_PORT); + outb_p(0xF2,IO_INDEX_PORT); + outb_p(0x00,IO_DATA_PORT); + + /* + * Select device Aux1 (dev=7) to set GP16 (in reg E6) and + * Gp13 (in reg E3) as inputs. + */ + outb_p(DEVICE_REGISTER,IO_INDEX_PORT); + outb_p(0x07,IO_DATA_PORT); + if (!testmode) + { + outb_p(0xE6,IO_INDEX_PORT); + outb_p(0x01,IO_DATA_PORT); + } + outb_p(0xE3,IO_INDEX_PORT); + outb_p(0x01,IO_DATA_PORT); + + /* Lock the SuperIO chip */ + outb_p(LOCK_DATA,IO_INDEX_PORT); + + spin_unlock_irqrestore(&spinlock, flags); + + printk(KERN_INFO PFX "shutdown.\n"); + + return 0; +} + +/* + * Send a keepalive ping to the watchdog + * This is done by simply re-writing the timeout to reg. 0xF2 + */ + +static int wdt_keepalive(void) +{ + unsigned long flags; + + spin_lock_irqsave(&spinlock, flags); + + /* Unlock the SuperIO chip */ + outb_p(UNLOCK_DATA,IO_INDEX_PORT); + outb_p(UNLOCK_DATA,IO_INDEX_PORT); + + /* Select device Aux2 (device=8) to kick watchdog reg F2 */ + outb_p(DEVICE_REGISTER,IO_INDEX_PORT); + outb_p(0x08,IO_DATA_PORT); + outb_p(0xF2,IO_INDEX_PORT); + outb_p(timeoutW,IO_DATA_PORT); + + /* Lock the SuperIO chip */ + outb_p(LOCK_DATA,IO_INDEX_PORT); + + spin_unlock_irqrestore(&spinlock, flags); + + return 0; +} + +/* + * Set the watchdog timeout value + */ + +static int wdt_set_timeout(int t) +{ + int tmrval; + + /* + * Convert seconds to watchdog counter time units, rounding up. + * On PCM-5335 watchdog units are 30 seconds/step with 15 sec startup + * value. This information is supplied in the PCM-5335 manual and was + * checked by me on a real board. This is a bit strange because W83977f + * datasheet says counter unit is in minutes! + */ + if (t < 15) + return -EINVAL; + + tmrval = ((t + 15) + 29) / 30; + + if (tmrval > 255) + return -EINVAL; + + /* + * timeout is the timeout in seconds, + * timeoutW is the timeout in watchdog counter units. + */ + timeoutW = tmrval; + timeout = (timeoutW * 30) - 15; + return 0; +} + +/* + * Get the watchdog status + */ + +static int wdt_get_status(int *status) +{ + int new_status; + unsigned long flags; + + spin_lock_irqsave(&spinlock, flags); + + /* Unlock the SuperIO chip */ + outb_p(UNLOCK_DATA,IO_INDEX_PORT); + outb_p(UNLOCK_DATA,IO_INDEX_PORT); + + /* Select device Aux2 (device=8) to read watchdog reg F4 */ + outb_p(DEVICE_REGISTER,IO_INDEX_PORT); + outb_p(0x08,IO_DATA_PORT); + outb_p(0xF4,IO_INDEX_PORT); + new_status = inb_p(IO_DATA_PORT); + + /* Lock the SuperIO chip */ + outb_p(LOCK_DATA,IO_INDEX_PORT); + + spin_unlock_irqrestore(&spinlock, flags); + + *status = 0; + if (new_status & 1) + *status |= WDIOF_CARDRESET; + + return 0; +} + + +/* + * /dev/watchdog handling + */ + +static int wdt_open(struct inode *inode, struct file *file) +{ + /* If the watchdog is alive we don't need to start it again */ + if( test_and_set_bit(0, &timer_alive) ) + return -EBUSY; + + if (nowayout) + __module_get(THIS_MODULE); + + wdt_start(); + return nonseekable_open(inode, file); +} + +static int wdt_release(struct inode *inode, struct file *file) +{ + /* + * Shut off the timer. + * Lock it in if it's a module and we set nowayout + */ + if (expect_close == 42) + { + wdt_stop(); + clear_bit(0, &timer_alive); + } else { + wdt_keepalive(); + printk(KERN_CRIT PFX "unexpected close, not stopping watchdog!\n"); + } + expect_close = 0; + return 0; +} + +/* + * wdt_write: + * @file: file handle to the watchdog + * @buf: buffer to write (unused as data does not matter here + * @count: count of bytes + * @ppos: pointer to the position to write. No seeks allowed + * + * A write to a watchdog device is defined as a keepalive signal. Any + * write of data will do, as we we don't define content meaning. + */ + +static ssize_t wdt_write(struct file *file, const char __user *buf, + size_t count, loff_t *ppos) +{ + /* See if we got the magic character 'V' and reload the timer */ + if(count) + { + if (!nowayout) + { + size_t ofs; + + /* note: just in case someone wrote the magic character long ago */ + expect_close = 0; + + /* scan to see whether or not we got the magic character */ + for(ofs = 0; ofs != count; ofs++) + { + char c; + if (get_user(c, buf + ofs)) + return -EFAULT; + if (c == 'V') { + expect_close = 42; + } + } + } + + /* someone wrote to us, we should restart timer */ + wdt_keepalive(); + } + return count; +} + +/* + * wdt_ioctl: + * @inode: inode of the device + * @file: file handle to the device + * @cmd: watchdog command + * @arg: argument pointer + * + * The watchdog API defines a common set of functions for all watchdogs + * according to their available features. + */ + +static struct watchdog_info ident = { + .options = WDIOF_SETTIMEOUT | WDIOF_MAGICCLOSE | WDIOF_KEEPALIVEPING, + .firmware_version = 1, + .identity = WATCHDOG_NAME, +}; + +static int wdt_ioctl(struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg) +{ + int status; + int new_options, retval = -EINVAL; + int new_timeout; + union { + struct watchdog_info __user *ident; + int __user *i; + } uarg; + + uarg.i = (int __user *)arg; + + switch(cmd) + { + default: + return -ENOIOCTLCMD; + + case WDIOC_GETSUPPORT: + return copy_to_user(uarg.ident, &ident, sizeof(ident)) ? -EFAULT : 0; + + case WDIOC_GETSTATUS: + wdt_get_status(&status); + return put_user(status, uarg.i); + + case WDIOC_GETBOOTSTATUS: + return put_user(0, uarg.i); + + case WDIOC_KEEPALIVE: + wdt_keepalive(); + return 0; + + case WDIOC_SETOPTIONS: + if (get_user (new_options, uarg.i)) + return -EFAULT; + + if (new_options & WDIOS_DISABLECARD) { + wdt_stop(); + retval = 0; + } + + if (new_options & WDIOS_ENABLECARD) { + wdt_start(); + retval = 0; + } + + return retval; + + case WDIOC_SETTIMEOUT: + if (get_user(new_timeout, uarg.i)) + return -EFAULT; + + if (wdt_set_timeout(new_timeout)) + return -EINVAL; + + wdt_keepalive(); + /* Fall */ + + case WDIOC_GETTIMEOUT: + return put_user(timeout, uarg.i); + + } +} + +static int wdt_notify_sys(struct notifier_block *this, unsigned long code, + void *unused) +{ + if (code==SYS_DOWN || code==SYS_HALT) + wdt_stop(); + return NOTIFY_DONE; +} + +static struct file_operations wdt_fops= +{ + .owner = THIS_MODULE, + .llseek = no_llseek, + .write = wdt_write, + .ioctl = wdt_ioctl, + .open = wdt_open, + .release = wdt_release, +}; + +static struct miscdevice wdt_miscdev= +{ + .minor = WATCHDOG_MINOR, + .name = "watchdog", + .fops = &wdt_fops, +}; + +static struct notifier_block wdt_notifier = { + .notifier_call = wdt_notify_sys, +}; + +static int __init w83977f_wdt_init(void) +{ + int rc; + + printk(KERN_INFO PFX DRIVER_VERSION); + + spin_lock_init(&spinlock); + + /* + * Check that the timeout value is within it's range ; + * if not reset to the default + */ + if (wdt_set_timeout(timeout)) { + wdt_set_timeout(DEFAULT_TIMEOUT); + printk(KERN_INFO PFX "timeout value must be 15<=timeout<=7635, using %d\n", + DEFAULT_TIMEOUT); + } + + if (!request_region(IO_INDEX_PORT, 2, WATCHDOG_NAME)) + { + printk(KERN_ERR PFX "I/O address 0x%04x already in use\n", + IO_INDEX_PORT); + rc = -EIO; + goto err_out; + } + + rc = misc_register(&wdt_miscdev); + if (rc) + { + printk(KERN_ERR PFX "cannot register miscdev on minor=%d (err=%d)\n", + wdt_miscdev.minor, rc); + goto err_out_region; + } + + rc = register_reboot_notifier(&wdt_notifier); + if (rc) + { + printk(KERN_ERR PFX "cannot register reboot notifier (err=%d)\n", + rc); + goto err_out_miscdev; + } + + printk(KERN_INFO PFX "initialized. timeout=%d sec (nowayout=%d testmode=%d)\n", + timeout, nowayout, testmode); + + return 0; + +err_out_miscdev: + misc_deregister(&wdt_miscdev); +err_out_region: + release_region(IO_INDEX_PORT,2); +err_out: + return rc; +} + +static void __exit w83977f_wdt_exit(void) +{ + wdt_stop(); + misc_deregister(&wdt_miscdev); + unregister_reboot_notifier(&wdt_notifier); + release_region(IO_INDEX_PORT,2); +} + +module_init(w83977f_wdt_init); +module_exit(w83977f_wdt_exit); + +MODULE_AUTHOR("Jose Goncalves <jose.goncalves@inov.pt>"); +MODULE_DESCRIPTION("Driver for watchdog timer in W83977F I/O chip"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR); diff --git a/drivers/firmware/dell_rbu.c b/drivers/firmware/dell_rbu.c index 3b865f3..b667823 100644 --- a/drivers/firmware/dell_rbu.c +++ b/drivers/firmware/dell_rbu.c @@ -50,7 +50,7 @@ MODULE_AUTHOR("Abhay Salunke <abhay_salunke@dell.com>"); MODULE_DESCRIPTION("Driver for updating BIOS image on DELL systems"); MODULE_LICENSE("GPL"); -MODULE_VERSION("1.0"); +MODULE_VERSION("2.0"); #define BIOS_SCAN_LIMIT 0xffffffff #define MAX_IMAGE_LENGTH 16 @@ -65,10 +65,11 @@ static struct _rbu_data { unsigned long packet_write_count; unsigned long num_packets; unsigned long packetsize; + int entry_created; } rbu_data; -static char image_type[MAX_IMAGE_LENGTH] = "mono"; -module_param_string(image_type, image_type, sizeof(image_type), 0); +static char image_type[MAX_IMAGE_LENGTH + 1] = "mono"; +module_param_string(image_type, image_type, sizeof (image_type), 0); MODULE_PARM_DESC(image_type, "BIOS image type. choose- mono or packet"); struct packet_data { @@ -114,7 +115,7 @@ static int fill_last_packet(void *data, size_t length) if ((rbu_data.packet_write_count + length) > rbu_data.packetsize) { pr_debug("dell_rbu:%s: packet size data " - "overrun\n", __FUNCTION__); + "overrun\n", __FUNCTION__); return -EINVAL; } @@ -146,12 +147,14 @@ static int create_packet(size_t length) pr_debug("create_packet: packetsize not specified\n"); return -EINVAL; } + spin_unlock(&rbu_data.lock); + newpacket = kmalloc(sizeof (struct packet_data), GFP_KERNEL); + spin_lock(&rbu_data.lock); - newpacket = kmalloc(sizeof(struct packet_data), GFP_KERNEL); if (!newpacket) { printk(KERN_WARNING - "dell_rbu:%s: failed to allocate new " - "packet\n", __FUNCTION__); + "dell_rbu:%s: failed to allocate new " + "packet\n", __FUNCTION__); return -ENOMEM; } @@ -160,15 +163,17 @@ static int create_packet(size_t length) * there is no upper limit on memory * address for packetized mechanism */ - newpacket->data = (unsigned char *)__get_free_pages(GFP_KERNEL, - ordernum); + spin_unlock(&rbu_data.lock); + newpacket->data = (unsigned char *) __get_free_pages(GFP_KERNEL, + ordernum); + spin_lock(&rbu_data.lock); pr_debug("create_packet: newpacket %p\n", newpacket->data); if (!newpacket->data) { printk(KERN_WARNING - "dell_rbu:%s: failed to allocate new " - "packet\n", __FUNCTION__); + "dell_rbu:%s: failed to allocate new " + "packet\n", __FUNCTION__); kfree(newpacket); return -ENOMEM; } @@ -204,9 +209,8 @@ static int packetize_data(void *data, size_t length) return rc; } -static int -do_packet_read(char *data, struct list_head *ptemp_list, - int length, int bytes_read, int *list_read_count) +static int do_packet_read(char *data, struct list_head *ptemp_list, + int length, int bytes_read, int *list_read_count) { void *ptemp_buf; struct packet_data *newpacket = NULL; @@ -239,7 +243,7 @@ do_packet_read(char *data, struct list_head *ptemp_list, return bytes_copied; } -static int packet_read_list(char *data, size_t * pread_length) +static int packet_read_list(char *data, size_t *pread_length) { struct list_head *ptemp_list; int temp_count = 0; @@ -258,8 +262,7 @@ static int packet_read_list(char *data, size_t * pread_length) ptemp_list = (&packet_data_head.list)->next; while (!list_empty(ptemp_list)) { bytes_copied = do_packet_read(pdest, ptemp_list, - remaining_bytes, bytes_read, - &temp_count); + remaining_bytes, bytes_read, &temp_count); remaining_bytes -= bytes_copied; bytes_read += bytes_copied; pdest += bytes_copied; @@ -287,7 +290,7 @@ static void packet_empty_list(void) ptemp_list = (&packet_data_head.list)->next; while (!list_empty(ptemp_list)) { newpacket = - list_entry(ptemp_list, struct packet_data, list); + list_entry(ptemp_list, struct packet_data, list); pnext_list = ptemp_list->next; list_del(ptemp_list); ptemp_list = pnext_list; @@ -296,8 +299,8 @@ static void packet_empty_list(void) * to make sure there are no stale RBU packets left in memory */ memset(newpacket->data, 0, rbu_data.packetsize); - free_pages((unsigned long)newpacket->data, - newpacket->ordernum); + free_pages((unsigned long) newpacket->data, + newpacket->ordernum); kfree(newpacket); } rbu_data.packet_write_count = 0; @@ -319,14 +322,13 @@ static void img_update_free(void) * BIOS image copied in memory. */ memset(rbu_data.image_update_buffer, 0, - rbu_data.image_update_buffer_size); + rbu_data.image_update_buffer_size); if (rbu_data.dma_alloc == 1) dma_free_coherent(NULL, rbu_data.bios_image_size, - rbu_data.image_update_buffer, - dell_rbu_dmaaddr); + rbu_data.image_update_buffer, dell_rbu_dmaaddr); else - free_pages((unsigned long)rbu_data.image_update_buffer, - rbu_data.image_update_ordernum); + free_pages((unsigned long) rbu_data.image_update_buffer, + rbu_data.image_update_ordernum); /* * Re-initialize the rbu_data variables after a free @@ -366,7 +368,7 @@ static int img_update_realloc(unsigned long size) */ if ((size != 0) && (rbu_data.image_update_buffer == NULL)) { printk(KERN_ERR "dell_rbu:%s: corruption " - "check failed\n", __FUNCTION__); + "check failed\n", __FUNCTION__); return -EINVAL; } /* @@ -385,17 +387,16 @@ static int img_update_realloc(unsigned long size) ordernum = get_order(size); image_update_buffer = - (unsigned char *)__get_free_pages(GFP_KERNEL, ordernum); + (unsigned char *) __get_free_pages(GFP_KERNEL, ordernum); img_buf_phys_addr = - (unsigned long)virt_to_phys(image_update_buffer); + (unsigned long) virt_to_phys(image_update_buffer); if (img_buf_phys_addr > BIOS_SCAN_LIMIT) { - free_pages((unsigned long)image_update_buffer, ordernum); + free_pages((unsigned long) image_update_buffer, ordernum); ordernum = -1; image_update_buffer = dma_alloc_coherent(NULL, size, - &dell_rbu_dmaaddr, - GFP_KERNEL); + &dell_rbu_dmaaddr, GFP_KERNEL); dma_alloc = 1; } @@ -405,13 +406,13 @@ static int img_update_realloc(unsigned long size) rbu_data.image_update_buffer = image_update_buffer; rbu_data.image_update_buffer_size = size; rbu_data.bios_image_size = - rbu_data.image_update_buffer_size; + rbu_data.image_update_buffer_size; rbu_data.image_update_ordernum = ordernum; rbu_data.dma_alloc = dma_alloc; rc = 0; } else { pr_debug("Not enough memory for image update:" - "size = %ld\n", size); + "size = %ld\n", size); rc = -ENOMEM; } @@ -438,7 +439,7 @@ static ssize_t read_packet_data(char *buffer, loff_t pos, size_t count) if (pos > imagesize) { retval = 0; printk(KERN_WARNING "dell_rbu:read_packet_data: " - "data underrun\n"); + "data underrun\n"); goto read_rbu_data_exit; } @@ -468,11 +469,11 @@ static ssize_t read_rbu_mono_data(char *buffer, loff_t pos, size_t count) /* check to see if we have something to return */ if ((rbu_data.image_update_buffer == NULL) || - (rbu_data.bios_image_size == 0)) { + (rbu_data.bios_image_size == 0)) { pr_debug("read_rbu_data_mono: image_update_buffer %p ," - "bios_image_size %lu\n", - rbu_data.image_update_buffer, - rbu_data.bios_image_size); + "bios_image_size %lu\n", + rbu_data.image_update_buffer, + rbu_data.bios_image_size); ret_count = -ENOMEM; goto read_rbu_data_exit; } @@ -497,8 +498,8 @@ static ssize_t read_rbu_mono_data(char *buffer, loff_t pos, size_t count) return ret_count; } -static ssize_t -read_rbu_data(struct kobject *kobj, char *buffer, loff_t pos, size_t count) +static ssize_t read_rbu_data(struct kobject *kobj, char *buffer, + loff_t pos, size_t count) { ssize_t ret_count = 0; @@ -515,62 +516,20 @@ read_rbu_data(struct kobject *kobj, char *buffer, loff_t pos, size_t count) return ret_count; } -static ssize_t -read_rbu_image_type(struct kobject *kobj, char *buffer, loff_t pos, - size_t count) -{ - int size = 0; - if (!pos) - size = sprintf(buffer, "%s\n", image_type); - return size; -} - -static ssize_t -write_rbu_image_type(struct kobject *kobj, char *buffer, loff_t pos, - size_t count) -{ - int rc = count; - spin_lock(&rbu_data.lock); - - if (strlen(buffer) < MAX_IMAGE_LENGTH) - sscanf(buffer, "%s", image_type); - else - printk(KERN_WARNING "dell_rbu: image_type is invalid" - "max chars = %d, \n incoming str--%s-- \n", - MAX_IMAGE_LENGTH, buffer); - - /* we must free all previous allocations */ - packet_empty_list(); - img_update_free(); - - spin_unlock(&rbu_data.lock); - return rc; - -} - -static struct bin_attribute rbu_data_attr = { - .attr = {.name = "data",.owner = THIS_MODULE,.mode = 0444}, - .read = read_rbu_data, -}; - -static struct bin_attribute rbu_image_type_attr = { - .attr = {.name = "image_type",.owner = THIS_MODULE,.mode = 0644}, - .read = read_rbu_image_type, - .write = write_rbu_image_type, -}; - static void callbackfn_rbu(const struct firmware *fw, void *context) { int rc = 0; - if (!fw || !fw->size) + if (!fw || !fw->size) { + rbu_data.entry_created = 0; return; + } spin_lock(&rbu_data.lock); if (!strcmp(image_type, "mono")) { if (!img_update_realloc(fw->size)) memcpy(rbu_data.image_update_buffer, - fw->data, fw->size); + fw->data, fw->size); } else if (!strcmp(image_type, "packet")) { if (!rbu_data.packetsize) rbu_data.packetsize = fw->size; @@ -584,14 +543,103 @@ static void callbackfn_rbu(const struct firmware *fw, void *context) spin_unlock(&rbu_data.lock); rc = request_firmware_nowait(THIS_MODULE, FW_ACTION_NOHOTPLUG, - "dell_rbu", &rbu_device->dev, - &context, callbackfn_rbu); + "dell_rbu", &rbu_device->dev, &context, callbackfn_rbu); if (rc) printk(KERN_ERR - "dell_rbu:%s request_firmware_nowait failed" - " %d\n", __FUNCTION__, rc); + "dell_rbu:%s request_firmware_nowait failed" + " %d\n", __FUNCTION__, rc); + else + rbu_data.entry_created = 1; +} + +static ssize_t read_rbu_image_type(struct kobject *kobj, char *buffer, + loff_t pos, size_t count) +{ + int size = 0; + if (!pos) + size = sprintf(buffer, "%s\n", image_type); + return size; +} + +static ssize_t write_rbu_image_type(struct kobject *kobj, char *buffer, + loff_t pos, size_t count) +{ + int rc = count; + int req_firm_rc = 0; + int i; + spin_lock(&rbu_data.lock); + /* + * Find the first newline or space + */ + for (i = 0; i < count; ++i) + if (buffer[i] == '\n' || buffer[i] == ' ') { + buffer[i] = '\0'; + break; + } + if (i == count) + buffer[count] = '\0'; + + if (strstr(buffer, "mono")) + strcpy(image_type, "mono"); + else if (strstr(buffer, "packet")) + strcpy(image_type, "packet"); + else if (strstr(buffer, "init")) { + /* + * If due to the user error the driver gets in a bad + * state where even though it is loaded , the + * /sys/class/firmware/dell_rbu entries are missing. + * to cover this situation the user can recreate entries + * by writing init to image_type. + */ + if (!rbu_data.entry_created) { + spin_unlock(&rbu_data.lock); + req_firm_rc = request_firmware_nowait(THIS_MODULE, + FW_ACTION_NOHOTPLUG, "dell_rbu", + &rbu_device->dev, &context, + callbackfn_rbu); + if (req_firm_rc) { + printk(KERN_ERR + "dell_rbu:%s request_firmware_nowait" + " failed %d\n", __FUNCTION__, rc); + rc = -EIO; + } else + rbu_data.entry_created = 1; + + spin_lock(&rbu_data.lock); + } + } else { + printk(KERN_WARNING "dell_rbu: image_type is invalid\n"); + spin_unlock(&rbu_data.lock); + return -EINVAL; + } + + /* we must free all previous allocations */ + packet_empty_list(); + img_update_free(); + spin_unlock(&rbu_data.lock); + + return rc; } +static struct bin_attribute rbu_data_attr = { + .attr = { + .name = "data", + .owner = THIS_MODULE, + .mode = 0444, + }, + .read = read_rbu_data, +}; + +static struct bin_attribute rbu_image_type_attr = { + .attr = { + .name = "image_type", + .owner = THIS_MODULE, + .mode = 0644, + }, + .read = read_rbu_image_type, + .write = write_rbu_image_type, +}; + static int __init dcdrbu_init(void) { int rc = 0; @@ -599,11 +647,11 @@ static int __init dcdrbu_init(void) init_packet_head(); rbu_device = - platform_device_register_simple("dell_rbu", -1, NULL, 0); + platform_device_register_simple("dell_rbu", -1, NULL, 0); if (!rbu_device) { printk(KERN_ERR - "dell_rbu:%s:platform_device_register_simple " - "failed\n", __FUNCTION__); + "dell_rbu:%s:platform_device_register_simple " + "failed\n", __FUNCTION__); return -EIO; } @@ -611,11 +659,12 @@ static int __init dcdrbu_init(void) sysfs_create_bin_file(&rbu_device->dev.kobj, &rbu_image_type_attr); rc = request_firmware_nowait(THIS_MODULE, FW_ACTION_NOHOTPLUG, - "dell_rbu", &rbu_device->dev, - &context, callbackfn_rbu); + "dell_rbu", &rbu_device->dev, &context, callbackfn_rbu); if (rc) printk(KERN_ERR "dell_rbu:%s:request_firmware_nowait" - " failed %d\n", __FUNCTION__, rc); + " failed %d\n", __FUNCTION__, rc); + else + rbu_data.entry_created = 1; return rc; diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig index 7e72e92..db358cf 100644 --- a/drivers/hwmon/Kconfig +++ b/drivers/hwmon/Kconfig @@ -418,12 +418,11 @@ config SENSORS_HDAPS help This driver provides support for the IBM Hard Drive Active Protection System (hdaps), which provides an accelerometer and other misc. data. - Supported laptops include the IBM ThinkPad T41, T42, T43, and R51. - The accelerometer data is readable via sysfs. + ThinkPads starting with the R50, T41, and X40 are supported. The + accelerometer data is readable via sysfs. - This driver also provides an input class device, allowing the - laptop to act as a pinball machine-esque mouse. This is off by - default but enabled via sysfs or the module parameter "mousedev". + This driver also provides an absolute input class device, allowing + the laptop to act as a pinball machine-esque joystick. Say Y here if you have an applicable laptop and want to experience the awesome power of hdaps. diff --git a/drivers/hwmon/hdaps.c b/drivers/hwmon/hdaps.c index eaebfc1..7f01076 100644 --- a/drivers/hwmon/hdaps.c +++ b/drivers/hwmon/hdaps.c @@ -4,11 +4,11 @@ * Copyright (C) 2005 Robert Love <rml@novell.com> * Copyright (C) 2005 Jesper Juhl <jesper.juhl@gmail.com> * - * The HardDisk Active Protection System (hdaps) is present in the IBM ThinkPad - * T41, T42, T43, R51, and X40, at least. It provides a basic two-axis + * The HardDisk Active Protection System (hdaps) is present in IBM ThinkPads + * starting with the R40, T41, and X40. It provides a basic two-axis * accelerometer and other data, such as the device's temperature. * - * Based on the document by Mark A. Smith available at + * This driver is based on the document by Mark A. Smith available at * http://www.almaden.ibm.com/cs/people/marksmith/tpaps.html and a lot of trial * and error. * @@ -36,12 +36,7 @@ #include <asm/io.h> #define HDAPS_LOW_PORT 0x1600 /* first port used by hdaps */ -#define HDAPS_NR_PORTS 0x30 /* 0x1600 - 0x162f */ - -#define STATE_FRESH 0x50 /* accelerometer data is fresh */ - -#define REFRESH_ASYNC 0x00 /* do asynchronous refresh */ -#define REFRESH_SYNC 0x01 /* do synchronous refresh */ +#define HDAPS_NR_PORTS 0x30 /* number of ports: 0x1600 - 0x162f */ #define HDAPS_PORT_STATE 0x1611 /* device state */ #define HDAPS_PORT_YPOS 0x1612 /* y-axis position */ @@ -53,7 +48,7 @@ #define HDAPS_PORT_UNKNOWN 0x161c /* what is this? */ #define HDAPS_PORT_KMACT 0x161d /* keyboard or mouse activity */ -#define HDAPS_READ_MASK 0xff /* some reads have the low 8 bits set */ +#define STATE_FRESH 0x50 /* accelerometer data is fresh */ #define KEYBD_MASK 0x20 /* set if keyboard activity */ #define MOUSE_MASK 0x40 /* set if mouse activity */ @@ -63,12 +58,11 @@ #define INIT_TIMEOUT_MSECS 4000 /* wait up to 4s for device init ... */ #define INIT_WAIT_MSECS 200 /* ... in 200ms increments */ -static struct platform_device *pdev; -static struct input_dev hdaps_idev; +#define HDAPS_POLL_PERIOD (HZ/20) /* poll for input every 1/20s */ +#define HDAPS_INPUT_FUZZ 4 /* input event threshold */ + static struct timer_list hdaps_timer; -static unsigned int hdaps_mousedev_threshold = 4; -static unsigned long hdaps_poll_ms = 50; -static unsigned int hdaps_mousedev; +static struct platform_device *pdev; static unsigned int hdaps_invert; static u8 km_activity; static int rest_x; @@ -81,14 +75,14 @@ static DECLARE_MUTEX(hdaps_sem); */ static inline u8 __get_latch(u16 port) { - return inb(port) & HDAPS_READ_MASK; + return inb(port) & 0xff; } /* - * __check_latch - Check a port latch for a given value. Callers must hold - * hdaps_sem. Returns zero if the port contains the given value. + * __check_latch - Check a port latch for a given value. Returns zero if the + * port contains the given value. Callers must hold hdaps_sem. */ -static inline unsigned int __check_latch(u16 port, u8 val) +static inline int __check_latch(u16 port, u8 val) { if (__get_latch(port) == val) return 0; @@ -99,7 +93,7 @@ static inline unsigned int __check_latch(u16 port, u8 val) * __wait_latch - Wait up to 100us for a port latch to get a certain value, * returning zero if the value is obtained. Callers must hold hdaps_sem. */ -static unsigned int __wait_latch(u16 port, u8 val) +static int __wait_latch(u16 port, u8 val) { unsigned int i; @@ -109,59 +103,42 @@ static unsigned int __wait_latch(u16 port, u8 val) udelay(5); } - return -EINVAL; + return -EIO; } /* - * __device_refresh - Request a refresh from the accelerometer. - * - * If sync is REFRESH_SYNC, we perform a synchronous refresh and will wait. - * Returns zero if successful and nonzero on error. - * - * If sync is REFRESH_ASYNC, we merely kick off a new refresh if the device is - * not up-to-date. Always returns zero. - * - * Callers must hold hdaps_sem. + * __device_refresh - request a refresh from the accelerometer. Does not wait + * for refresh to complete. Callers must hold hdaps_sem. */ -static int __device_refresh(unsigned int sync) +static void __device_refresh(void) { - u8 state; - - udelay(100); - - state = inb(0x1604); - if (state == STATE_FRESH) - return 0; - - outb(0x11, 0x1610); - outb(0x01, 0x161f); - if (sync == REFRESH_ASYNC) - return 0; + udelay(200); + if (inb(0x1604) != STATE_FRESH) { + outb(0x11, 0x1610); + outb(0x01, 0x161f); + } +} +/* + * __device_refresh_sync - request a synchronous refresh from the + * accelerometer. We wait for the refresh to complete. Returns zero if + * successful and nonzero on error. Callers must hold hdaps_sem. + */ +static int __device_refresh_sync(void) +{ + __device_refresh(); return __wait_latch(0x1604, STATE_FRESH); } /* - * __device_complete - Indicate to the accelerometer that we are done reading + * __device_complete - indicate to the accelerometer that we are done reading * data, and then initiate an async refresh. Callers must hold hdaps_sem. */ static inline void __device_complete(void) { inb(0x161f); inb(0x1604); - __device_refresh(REFRESH_ASYNC); -} - -static int __hdaps_readb_one(unsigned int port, u8 *val) -{ - /* do a sync refresh -- we need to be sure that we read fresh data */ - if (__device_refresh(REFRESH_SYNC)) - return -EIO; - - *val = inb(port); - __device_complete(); - - return 0; + __device_refresh(); } /* @@ -174,17 +151,26 @@ static int hdaps_readb_one(unsigned int port, u8 *val) int ret; down(&hdaps_sem); - ret = __hdaps_readb_one(port, val); - up(&hdaps_sem); + /* do a sync refresh -- we need to be sure that we read fresh data */ + ret = __device_refresh_sync(); + if (ret) + goto out; + + *val = inb(port); + __device_complete(); + +out: + up(&hdaps_sem); return ret; } +/* __hdaps_read_pair - internal lockless helper for hdaps_read_pair(). */ static int __hdaps_read_pair(unsigned int port1, unsigned int port2, int *x, int *y) { /* do a sync refresh -- we need to be sure that we read fresh data */ - if (__device_refresh(REFRESH_SYNC)) + if (__device_refresh_sync()) return -EIO; *y = inw(port2); @@ -217,11 +203,13 @@ static int hdaps_read_pair(unsigned int port1, unsigned int port2, return ret; } -/* initialize the accelerometer */ +/* + * hdaps_device_init - initialize the accelerometer. Returns zero on success + * and negative error code on failure. Can sleep. + */ static int hdaps_device_init(void) { - unsigned int total_msecs = INIT_TIMEOUT_MSECS; - int ret = -ENXIO; + int total, ret = -ENXIO; down(&hdaps_sem); @@ -231,8 +219,10 @@ static int hdaps_device_init(void) goto out; /* - * The 0x03 value appears to only work on some thinkpads, such as the - * T42p. Others return 0x01. + * Most ThinkPads return 0x01. + * + * Others--namely the R50p, T41p, and T42p--return 0x03. These laptops + * have "inverted" axises. * * The 0x02 value occurs when the chip has been previously initialized. */ @@ -267,24 +257,23 @@ static int hdaps_device_init(void) outb(0x01, 0x161f); if (__wait_latch(0x161f, 0x00)) goto out; - if (__device_refresh(REFRESH_SYNC)) + if (__device_refresh_sync()) goto out; if (__wait_latch(0x1611, 0x00)) goto out; /* we have done our dance, now let's wait for the applause */ - while (total_msecs > 0) { - u8 ignored; + for (total = INIT_TIMEOUT_MSECS; total > 0; total -= INIT_WAIT_MSECS) { + int x, y; /* a read of the device helps push it into action */ - __hdaps_readb_one(HDAPS_PORT_UNKNOWN, &ignored); + __hdaps_read_pair(HDAPS_PORT_XPOS, HDAPS_PORT_YPOS, &x, &y); if (!__wait_latch(0x1611, 0x02)) { ret = 0; break; } msleep(INIT_WAIT_MSECS); - total_msecs -= INIT_WAIT_MSECS; } out: @@ -293,96 +282,6 @@ out: } -/* Input class stuff */ - -/* - * hdaps_calibrate - Zero out our "resting" values. Callers must hold hdaps_sem. - */ -static void hdaps_calibrate(void) -{ - int x, y; - - if (__hdaps_read_pair(HDAPS_PORT_XPOS, HDAPS_PORT_YPOS, &x, &y)) - return; - - rest_x = x; - rest_y = y; -} - -static void hdaps_mousedev_poll(unsigned long unused) -{ - int x, y; - - /* Cannot sleep. Try nonblockingly. If we fail, try again later. */ - if (down_trylock(&hdaps_sem)) { - mod_timer(&hdaps_timer,jiffies+msecs_to_jiffies(hdaps_poll_ms)); - return; - } - - if (__hdaps_read_pair(HDAPS_PORT_XPOS, HDAPS_PORT_YPOS, &x, &y)) - goto out; - - x -= rest_x; - y -= rest_y; - if (abs(x) > hdaps_mousedev_threshold) - input_report_rel(&hdaps_idev, REL_X, x); - if (abs(y) > hdaps_mousedev_threshold) - input_report_rel(&hdaps_idev, REL_Y, y); - input_sync(&hdaps_idev); - - mod_timer(&hdaps_timer, jiffies + msecs_to_jiffies(hdaps_poll_ms)); - -out: - up(&hdaps_sem); -} - -/* - * hdaps_mousedev_enable - enable the input class device. Can sleep. - */ -static void hdaps_mousedev_enable(void) -{ - down(&hdaps_sem); - - /* calibrate the device before enabling */ - hdaps_calibrate(); - - /* initialize the input class */ - init_input_dev(&hdaps_idev); - hdaps_idev.dev = &pdev->dev; - hdaps_idev.evbit[0] = BIT(EV_KEY) | BIT(EV_REL); - hdaps_idev.relbit[0] = BIT(REL_X) | BIT(REL_Y); - hdaps_idev.keybit[LONG(BTN_LEFT)] = BIT(BTN_LEFT); - input_register_device(&hdaps_idev); - - /* start up our timer */ - init_timer(&hdaps_timer); - hdaps_timer.function = hdaps_mousedev_poll; - hdaps_timer.expires = jiffies + msecs_to_jiffies(hdaps_poll_ms); - add_timer(&hdaps_timer); - - hdaps_mousedev = 1; - - up(&hdaps_sem); - - printk(KERN_INFO "hdaps: input device enabled.\n"); -} - -/* - * hdaps_mousedev_disable - disable the input class device. Caller must hold - * hdaps_sem. - */ -static void hdaps_mousedev_disable(void) -{ - down(&hdaps_sem); - if (hdaps_mousedev) { - hdaps_mousedev = 0; - del_timer_sync(&hdaps_timer); - input_unregister_device(&hdaps_idev); - } - up(&hdaps_sem); -} - - /* Device model stuff */ static int hdaps_probe(struct device *dev) @@ -412,6 +311,49 @@ static struct device_driver hdaps_driver = { .resume = hdaps_resume }; +/* Input class stuff */ + +static struct input_dev hdaps_idev = { + .name = "hdaps", + .evbit = { BIT(EV_ABS) }, + .absbit = { BIT(ABS_X) | BIT(ABS_Y) }, + .absmin = { [ABS_X] = -256, [ABS_Y] = -256 }, + .absmax = { [ABS_X] = 256, [ABS_Y] = 256 }, + .absfuzz = { [ABS_X] = HDAPS_INPUT_FUZZ, [ABS_Y] = HDAPS_INPUT_FUZZ }, + .absflat = { [ABS_X] = HDAPS_INPUT_FUZZ, [ABS_Y] = HDAPS_INPUT_FUZZ }, +}; + +/* + * hdaps_calibrate - Set our "resting" values. Callers must hold hdaps_sem. + */ +static void hdaps_calibrate(void) +{ + __hdaps_read_pair(HDAPS_PORT_XPOS, HDAPS_PORT_YPOS, &rest_x, &rest_y); +} + +static void hdaps_mousedev_poll(unsigned long unused) +{ + int x, y; + + /* Cannot sleep. Try nonblockingly. If we fail, try again later. */ + if (down_trylock(&hdaps_sem)) { + mod_timer(&hdaps_timer,jiffies + HDAPS_POLL_PERIOD); + return; + } + + if (__hdaps_read_pair(HDAPS_PORT_XPOS, HDAPS_PORT_YPOS, &x, &y)) + goto out; + + input_report_abs(&hdaps_idev, ABS_X, x - rest_x); + input_report_abs(&hdaps_idev, ABS_Y, y - rest_y); + input_sync(&hdaps_idev); + + mod_timer(&hdaps_timer, jiffies + HDAPS_POLL_PERIOD); + +out: + up(&hdaps_sem); +} + /* Sysfs Files */ @@ -517,69 +459,6 @@ static ssize_t hdaps_invert_store(struct device *dev, return count; } -static ssize_t hdaps_mousedev_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - return sprintf(buf, "%d\n", hdaps_mousedev); -} - -static ssize_t hdaps_mousedev_store(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t count) -{ - int enable; - - if (sscanf(buf, "%d", &enable) != 1) - return -EINVAL; - - if (enable == 1) - hdaps_mousedev_enable(); - else if (enable == 0) - hdaps_mousedev_disable(); - else - return -EINVAL; - - return count; -} - -static ssize_t hdaps_poll_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - return sprintf(buf, "%lu\n", hdaps_poll_ms); -} - -static ssize_t hdaps_poll_store(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t count) -{ - unsigned int poll; - - if (sscanf(buf, "%u", &poll) != 1 || poll == 0) - return -EINVAL; - hdaps_poll_ms = poll; - - return count; -} - -static ssize_t hdaps_threshold_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - return sprintf(buf, "%u\n", hdaps_mousedev_threshold); -} - -static ssize_t hdaps_threshold_store(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t count) -{ - unsigned int threshold; - - if (sscanf(buf, "%u", &threshold) != 1 || threshold == 0) - return -EINVAL; - hdaps_mousedev_threshold = threshold; - - return count; -} - static DEVICE_ATTR(position, 0444, hdaps_position_show, NULL); static DEVICE_ATTR(variance, 0444, hdaps_variance_show, NULL); static DEVICE_ATTR(temp1, 0444, hdaps_temp1_show, NULL); @@ -588,10 +467,6 @@ static DEVICE_ATTR(keyboard_activity, 0444, hdaps_keyboard_activity_show, NULL); static DEVICE_ATTR(mouse_activity, 0444, hdaps_mouse_activity_show, NULL); static DEVICE_ATTR(calibrate, 0644, hdaps_calibrate_show,hdaps_calibrate_store); static DEVICE_ATTR(invert, 0644, hdaps_invert_show, hdaps_invert_store); -static DEVICE_ATTR(mousedev, 0644, hdaps_mousedev_show, hdaps_mousedev_store); -static DEVICE_ATTR(mousedev_poll_ms, 0644, hdaps_poll_show, hdaps_poll_store); -static DEVICE_ATTR(mousedev_threshold, 0644, hdaps_threshold_show, - hdaps_threshold_store); static struct attribute *hdaps_attributes[] = { &dev_attr_position.attr, @@ -601,9 +476,6 @@ static struct attribute *hdaps_attributes[] = { &dev_attr_keyboard_activity.attr, &dev_attr_mouse_activity.attr, &dev_attr_calibrate.attr, - &dev_attr_mousedev.attr, - &dev_attr_mousedev_threshold.attr, - &dev_attr_mousedev_poll_ms.attr, &dev_attr_invert.attr, NULL, }; @@ -615,24 +487,19 @@ static struct attribute_group hdaps_attribute_group = { /* Module stuff */ -/* - * XXX: We should be able to return nonzero and halt the detection process. - * But there is a bug in dmi_check_system() where a nonzero return from the - * first match will result in a return of failure from dmi_check_system(). - * I fixed this; the patch is in 2.6-mm. Once in Linus's tree we can make - * hdaps_dmi_match_invert() return hdaps_dmi_match(), which in turn returns 1. - */ +/* hdaps_dmi_match - found a match. return one, short-circuiting the hunt. */ static int hdaps_dmi_match(struct dmi_system_id *id) { printk(KERN_INFO "hdaps: %s detected.\n", id->ident); - return 0; + return 1; } +/* hdaps_dmi_match_invert - found an inverted match. */ static int hdaps_dmi_match_invert(struct dmi_system_id *id) { hdaps_invert = 1; printk(KERN_INFO "hdaps: inverting axis readings.\n"); - return 0; + return hdaps_dmi_match(id); } #define HDAPS_DMI_MATCH_NORMAL(model) { \ @@ -662,12 +529,15 @@ static int __init hdaps_init(void) HDAPS_DMI_MATCH_INVERT("ThinkPad R50p"), HDAPS_DMI_MATCH_NORMAL("ThinkPad R50"), HDAPS_DMI_MATCH_NORMAL("ThinkPad R51"), + HDAPS_DMI_MATCH_NORMAL("ThinkPad R52"), HDAPS_DMI_MATCH_INVERT("ThinkPad T41p"), HDAPS_DMI_MATCH_NORMAL("ThinkPad T41"), HDAPS_DMI_MATCH_INVERT("ThinkPad T42p"), HDAPS_DMI_MATCH_NORMAL("ThinkPad T42"), HDAPS_DMI_MATCH_NORMAL("ThinkPad T43"), HDAPS_DMI_MATCH_NORMAL("ThinkPad X40"), + HDAPS_DMI_MATCH_NORMAL("ThinkPad X41 Tablet"), + HDAPS_DMI_MATCH_NORMAL("ThinkPad X41"), { .ident = NULL } }; @@ -696,8 +566,18 @@ static int __init hdaps_init(void) if (ret) goto out_device; - if (hdaps_mousedev) - hdaps_mousedev_enable(); + /* initial calibrate for the input device */ + hdaps_calibrate(); + + /* initialize the input class */ + hdaps_idev.dev = &pdev->dev; + input_register_device(&hdaps_idev); + + /* start up our timer for the input device */ + init_timer(&hdaps_timer); + hdaps_timer.function = hdaps_mousedev_poll; + hdaps_timer.expires = jiffies + HDAPS_POLL_PERIOD; + add_timer(&hdaps_timer); printk(KERN_INFO "hdaps: driver successfully loaded.\n"); return 0; @@ -715,8 +595,8 @@ out: static void __exit hdaps_exit(void) { - hdaps_mousedev_disable(); - + del_timer_sync(&hdaps_timer); + input_unregister_device(&hdaps_idev); sysfs_remove_group(&pdev->dev.kobj, &hdaps_attribute_group); platform_device_unregister(pdev); driver_unregister(&hdaps_driver); @@ -728,9 +608,6 @@ static void __exit hdaps_exit(void) module_init(hdaps_init); module_exit(hdaps_exit); -module_param_named(mousedev, hdaps_mousedev, bool, 0); -MODULE_PARM_DESC(mousedev, "enable the input class device"); - module_param_named(invert, hdaps_invert, bool, 0); MODULE_PARM_DESC(invert, "invert data along each axis"); diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig index 8334496..3badfec 100644 --- a/drivers/i2c/busses/Kconfig +++ b/drivers/i2c/busses/Kconfig @@ -245,6 +245,18 @@ config I2C_KEYWEST This support is also available as a module. If so, the module will be called i2c-keywest. +config I2C_PMAC_SMU + tristate "Powermac SMU I2C interface" + depends on I2C && PMAC_SMU + help + This supports the use of the I2C interface in the SMU + chip on recent Apple machines like the iMac G5. It is used + among others by the thermal control driver for those machines. + Say Y if you have such a machine. + + This support is also available as a module. If so, the module + will be called i2c-pmac-smu. + config I2C_MPC tristate "MPC107/824x/85xx/52xx" depends on I2C && PPC32 diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile index 980b3e9..f1df00f 100644 --- a/drivers/i2c/busses/Makefile +++ b/drivers/i2c/busses/Makefile @@ -20,6 +20,7 @@ obj-$(CONFIG_I2C_ITE) += i2c-ite.o obj-$(CONFIG_I2C_IXP2000) += i2c-ixp2000.o obj-$(CONFIG_I2C_IXP4XX) += i2c-ixp4xx.o obj-$(CONFIG_I2C_KEYWEST) += i2c-keywest.o +obj-$(CONFIG_I2C_PMAC_SMU) += i2c-pmac-smu.o obj-$(CONFIG_I2C_MPC) += i2c-mpc.o obj-$(CONFIG_I2C_MV64XXX) += i2c-mv64xxx.o obj-$(CONFIG_I2C_NFORCE2) += i2c-nforce2.o diff --git a/drivers/i2c/busses/i2c-keywest.c b/drivers/i2c/busses/i2c-keywest.c index 37b49c2..eff5896 100644 --- a/drivers/i2c/busses/i2c-keywest.c +++ b/drivers/i2c/busses/i2c-keywest.c @@ -611,7 +611,6 @@ create_iface(struct device_node *np, struct device *dev) for (i=0; i<nchan; i++) { struct keywest_chan* chan = &iface->channels[i]; - u8 addr; sprintf(chan->adapter.name, "%s %d", np->parent->name, i); chan->iface = iface; diff --git a/drivers/i2c/busses/i2c-pmac-smu.c b/drivers/i2c/busses/i2c-pmac-smu.c new file mode 100644 index 0000000..8a9f564 --- /dev/null +++ b/drivers/i2c/busses/i2c-pmac-smu.c @@ -0,0 +1,316 @@ +/* + i2c Support for Apple SMU Controller + + Copyright (c) 2005 Benjamin Herrenschmidt, IBM Corp. + <benh@kernel.crashing.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; 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 <linux/config.h> +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/types.h> +#include <linux/i2c.h> +#include <linux/init.h> +#include <linux/completion.h> +#include <linux/device.h> +#include <asm/prom.h> +#include <asm/of_device.h> +#include <asm/smu.h> + +static int probe; + +MODULE_AUTHOR("Benjamin Herrenschmidt <benh@kernel.crashing.org>"); +MODULE_DESCRIPTION("I2C driver for Apple's SMU"); +MODULE_LICENSE("GPL"); +module_param(probe, bool, 0); + + +/* Physical interface */ +struct smu_iface +{ + struct i2c_adapter adapter; + struct completion complete; + u32 busid; +}; + +static void smu_i2c_done(struct smu_i2c_cmd *cmd, void *misc) +{ + struct smu_iface *iface = misc; + complete(&iface->complete); +} + +/* + * SMBUS-type transfer entrypoint + */ +static s32 smu_smbus_xfer( struct i2c_adapter* adap, + u16 addr, + unsigned short flags, + char read_write, + u8 command, + int size, + union i2c_smbus_data* data) +{ + struct smu_iface *iface = i2c_get_adapdata(adap); + struct smu_i2c_cmd cmd; + int rc = 0; + int read = (read_write == I2C_SMBUS_READ); + + cmd.info.bus = iface->busid; + cmd.info.devaddr = (addr << 1) | (read ? 0x01 : 0x00); + + /* Prepare datas & select mode */ + switch (size) { + case I2C_SMBUS_QUICK: + cmd.info.type = SMU_I2C_TRANSFER_SIMPLE; + cmd.info.datalen = 0; + break; + case I2C_SMBUS_BYTE: + cmd.info.type = SMU_I2C_TRANSFER_SIMPLE; + cmd.info.datalen = 1; + if (!read) + cmd.info.data[0] = data->byte; + break; + case I2C_SMBUS_BYTE_DATA: + cmd.info.type = SMU_I2C_TRANSFER_STDSUB; + cmd.info.datalen = 1; + cmd.info.sublen = 1; + cmd.info.subaddr[0] = command; + cmd.info.subaddr[1] = 0; + cmd.info.subaddr[2] = 0; + if (!read) + cmd.info.data[0] = data->byte; + break; + case I2C_SMBUS_WORD_DATA: + cmd.info.type = SMU_I2C_TRANSFER_STDSUB; + cmd.info.datalen = 2; + cmd.info.sublen = 1; + cmd.info.subaddr[0] = command; + cmd.info.subaddr[1] = 0; + cmd.info.subaddr[2] = 0; + if (!read) { + cmd.info.data[0] = data->byte & 0xff; + cmd.info.data[1] = (data->byte >> 8) & 0xff; + } + break; + /* Note that these are broken vs. the expected smbus API where + * on reads, the lenght is actually returned from the function, + * but I think the current API makes no sense and I don't want + * any driver that I haven't verified for correctness to go + * anywhere near a pmac i2c bus anyway ... + */ + case I2C_SMBUS_BLOCK_DATA: + cmd.info.type = SMU_I2C_TRANSFER_STDSUB; + cmd.info.datalen = data->block[0] + 1; + if (cmd.info.datalen > 6) + return -EINVAL; + if (!read) + memcpy(cmd.info.data, data->block, cmd.info.datalen); + cmd.info.sublen = 1; + cmd.info.subaddr[0] = command; + cmd.info.subaddr[1] = 0; + cmd.info.subaddr[2] = 0; + break; + case I2C_SMBUS_I2C_BLOCK_DATA: + cmd.info.type = SMU_I2C_TRANSFER_STDSUB; + cmd.info.datalen = data->block[0]; + if (cmd.info.datalen > 7) + return -EINVAL; + if (!read) + memcpy(cmd.info.data, &data->block[1], + cmd.info.datalen); + cmd.info.sublen = 1; + cmd.info.subaddr[0] = command; + cmd.info.subaddr[1] = 0; + cmd.info.subaddr[2] = 0; + break; + + default: + return -EINVAL; + } + + /* Turn a standardsub read into a combined mode access */ + if (read_write == I2C_SMBUS_READ && + cmd.info.type == SMU_I2C_TRANSFER_STDSUB) + cmd.info.type = SMU_I2C_TRANSFER_COMBINED; + + /* Finish filling command and submit it */ + cmd.done = smu_i2c_done; + cmd.misc = iface; + rc = smu_queue_i2c(&cmd); + if (rc < 0) + return rc; + wait_for_completion(&iface->complete); + rc = cmd.status; + + if (!read || rc < 0) + return rc; + + switch (size) { + case I2C_SMBUS_BYTE: + case I2C_SMBUS_BYTE_DATA: + data->byte = cmd.info.data[0]; + break; + case I2C_SMBUS_WORD_DATA: + data->word = ((u16)cmd.info.data[1]) << 8; + data->word |= cmd.info.data[0]; + break; + /* Note that these are broken vs. the expected smbus API where + * on reads, the lenght is actually returned from the function, + * but I think the current API makes no sense and I don't want + * any driver that I haven't verified for correctness to go + * anywhere near a pmac i2c bus anyway ... + */ + case I2C_SMBUS_BLOCK_DATA: + case I2C_SMBUS_I2C_BLOCK_DATA: + memcpy(&data->block[0], cmd.info.data, cmd.info.datalen); + break; + } + + return rc; +} + +static u32 +smu_smbus_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; +} + +/* For now, we only handle combined mode (smbus) */ +static struct i2c_algorithm smu_algorithm = { + .smbus_xfer = smu_smbus_xfer, + .functionality = smu_smbus_func, +}; + +static int create_iface(struct device_node *np, struct device *dev) +{ + struct smu_iface* iface; + u32 *reg, busid; + int rc; + + reg = (u32 *)get_property(np, "reg", NULL); + if (reg == NULL) { + printk(KERN_ERR "i2c-pmac-smu: can't find bus number !\n"); + return -ENXIO; + } + busid = *reg; + + iface = kmalloc(sizeof(struct smu_iface), GFP_KERNEL); + if (iface == NULL) { + printk(KERN_ERR "i2c-pmac-smu: can't allocate inteface !\n"); + return -ENOMEM; + } + memset(iface, 0, sizeof(struct smu_iface)); + init_completion(&iface->complete); + iface->busid = busid; + + dev_set_drvdata(dev, iface); + + sprintf(iface->adapter.name, "smu-i2c-%02x", busid); + iface->adapter.algo = &smu_algorithm; + iface->adapter.algo_data = NULL; + iface->adapter.client_register = NULL; + iface->adapter.client_unregister = NULL; + i2c_set_adapdata(&iface->adapter, iface); + iface->adapter.dev.parent = dev; + + rc = i2c_add_adapter(&iface->adapter); + if (rc) { + printk(KERN_ERR "i2c-pamc-smu.c: Adapter %s registration " + "failed\n", iface->adapter.name); + i2c_set_adapdata(&iface->adapter, NULL); + } + + if (probe) { + unsigned char addr; + printk("Probe: "); + for (addr = 0x00; addr <= 0x7f; addr++) { + if (i2c_smbus_xfer(&iface->adapter,addr, + 0,0,0,I2C_SMBUS_QUICK,NULL) >= 0) + printk("%02x ", addr); + } + printk("\n"); + } + + printk(KERN_INFO "SMU i2c bus %x registered\n", busid); + + return 0; +} + +static int dispose_iface(struct device *dev) +{ + struct smu_iface *iface = dev_get_drvdata(dev); + int rc; + + rc = i2c_del_adapter(&iface->adapter); + i2c_set_adapdata(&iface->adapter, NULL); + /* We aren't that prepared to deal with this... */ + if (rc) + printk("i2c-pmac-smu.c: Failed to remove bus %s !\n", + iface->adapter.name); + dev_set_drvdata(dev, NULL); + kfree(iface); + + return 0; +} + + +static int create_iface_of_platform(struct of_device* dev, + const struct of_device_id *match) +{ + return create_iface(dev->node, &dev->dev); +} + + +static int dispose_iface_of_platform(struct of_device* dev) +{ + return dispose_iface(&dev->dev); +} + + +static struct of_device_id i2c_smu_match[] = +{ + { + .compatible = "smu-i2c", + }, + {}, +}; +static struct of_platform_driver i2c_smu_of_platform_driver = +{ + .name = "i2c-smu", + .match_table = i2c_smu_match, + .probe = create_iface_of_platform, + .remove = dispose_iface_of_platform +}; + + +static int __init i2c_pmac_smu_init(void) +{ + of_register_driver(&i2c_smu_of_platform_driver); + return 0; +} + + +static void __exit i2c_pmac_smu_cleanup(void) +{ + of_unregister_driver(&i2c_smu_of_platform_driver); +} + +module_init(i2c_pmac_smu_init); +module_exit(i2c_pmac_smu_cleanup); diff --git a/drivers/i2c/busses/i2c-pxa.c b/drivers/i2c/busses/i2c-pxa.c index fdf53ce..44b595d 100644 --- a/drivers/i2c/busses/i2c-pxa.c +++ b/drivers/i2c/busses/i2c-pxa.c @@ -914,19 +914,23 @@ static int i2c_pxa_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num return ret; } +static u32 i2c_pxa_functionality(struct i2c_adapter *adap) +{ + return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL; +} + static struct i2c_algorithm i2c_pxa_algorithm = { - .name = "PXA-I2C-Algorithm", - .id = I2C_ALGO_PXA, .master_xfer = i2c_pxa_xfer, + .functionality = i2c_pxa_functionality, }; static struct pxa_i2c i2c_pxa = { .lock = SPIN_LOCK_UNLOCKED, .wait = __WAIT_QUEUE_HEAD_INITIALIZER(i2c_pxa.wait), .adap = { - .name = "pxa2xx-i2c", - .id = I2C_ALGO_PXA, + .owner = THIS_MODULE, .algo = &i2c_pxa_algorithm, + .name = "pxa2xx-i2c", .retries = 5, }, }; diff --git a/drivers/ide/ide-iops.c b/drivers/ide/ide-iops.c index b443b04..0b0aa4f 100644 --- a/drivers/ide/ide-iops.c +++ b/drivers/ide/ide-iops.c @@ -601,44 +601,15 @@ EXPORT_SYMBOL(ide_wait_stat); */ u8 eighty_ninty_three (ide_drive_t *drive) { -#if 0 - if (!HWIF(drive)->udma_four) + if(HWIF(drive)->udma_four == 0) + return 0; + if (!(drive->id->hw_config & 0x6000)) return 0; - - if (drive->id->major_rev_num) { - int hssbd = 0; - int i; - /* - * Determine highest Supported SPEC - */ - for (i=1; i<=15; i++) - if (drive->id->major_rev_num & (1<<i)) - hssbd++; - - switch (hssbd) { - case 7: - case 6: - case 5: - /* ATA-4 and older do not support above Ultra 33 */ - default: - return 0; - } - } - - return ((u8) ( -#ifndef CONFIG_IDEDMA_IVB - (drive->id->hw_config & 0x4000) && -#endif /* CONFIG_IDEDMA_IVB */ - (drive->id->hw_config & 0x6000)) ? 1 : 0); - -#else - - return ((u8) ((HWIF(drive)->udma_four) && #ifndef CONFIG_IDEDMA_IVB - (drive->id->hw_config & 0x4000) && + if(!(drive->id->hw_config & 0x4000)) + return 0; #endif /* CONFIG_IDEDMA_IVB */ - (drive->id->hw_config & 0x6000)) ? 1 : 0); -#endif + return 1; } EXPORT_SYMBOL(eighty_ninty_three); diff --git a/drivers/ide/ide-taskfile.c b/drivers/ide/ide-taskfile.c index d04f62a..ace8eda 100644 --- a/drivers/ide/ide-taskfile.c +++ b/drivers/ide/ide-taskfile.c @@ -500,6 +500,7 @@ static int ide_diag_taskfile(ide_drive_t *drive, ide_task_t *args, unsigned long } rq.special = args; + args->rq = &rq; return ide_do_drive_cmd(drive, &rq, ide_wait); } diff --git a/drivers/ide/pci/cmd64x.c b/drivers/ide/pci/cmd64x.c index 3de9ab8..3d9c7af 100644 --- a/drivers/ide/pci/cmd64x.c +++ b/drivers/ide/pci/cmd64x.c @@ -608,7 +608,7 @@ static unsigned int __devinit init_chipset_cmd64x(struct pci_dev *dev, const cha #ifdef __i386__ if (dev->resource[PCI_ROM_RESOURCE].start) { - pci_write_config_byte(dev, PCI_ROM_ADDRESS, dev->resource[PCI_ROM_RESOURCE].start | PCI_ROM_ADDRESS_ENABLE); + pci_write_config_dword(dev, PCI_ROM_ADDRESS, dev->resource[PCI_ROM_RESOURCE].start | PCI_ROM_ADDRESS_ENABLE); printk(KERN_INFO "%s: ROM enabled at 0x%08lx\n", name, dev->resource[PCI_ROM_RESOURCE].start); } #endif diff --git a/drivers/ide/pci/hpt34x.c b/drivers/ide/pci/hpt34x.c index bbde462..be334da 100644 --- a/drivers/ide/pci/hpt34x.c +++ b/drivers/ide/pci/hpt34x.c @@ -173,7 +173,7 @@ static unsigned int __devinit init_chipset_hpt34x(struct pci_dev *dev, const cha if (cmd & PCI_COMMAND_MEMORY) { if (pci_resource_start(dev, PCI_ROM_RESOURCE)) { - pci_write_config_byte(dev, PCI_ROM_ADDRESS, + pci_write_config_dword(dev, PCI_ROM_ADDRESS, dev->resource[PCI_ROM_RESOURCE].start | PCI_ROM_ADDRESS_ENABLE); printk(KERN_INFO "HPT345: ROM enabled at 0x%08lx\n", dev->resource[PCI_ROM_RESOURCE].start); diff --git a/drivers/infiniband/core/mad_rmpp.c b/drivers/infiniband/core/mad_rmpp.c index 2bd8b1c..e23836d 100644 --- a/drivers/infiniband/core/mad_rmpp.c +++ b/drivers/infiniband/core/mad_rmpp.c @@ -412,8 +412,8 @@ static inline int get_mad_len(struct mad_rmpp_recv *rmpp_recv) hdr_size = data_offset(rmpp_mad->mad_hdr.mgmt_class); data_size = sizeof(struct ib_rmpp_mad) - hdr_size; - pad = data_size - be32_to_cpu(rmpp_mad->rmpp_hdr.paylen_newwin); - if (pad > data_size || pad < 0) + pad = IB_MGMT_RMPP_DATA - be32_to_cpu(rmpp_mad->rmpp_hdr.paylen_newwin); + if (pad > IB_MGMT_RMPP_DATA || pad < 0) pad = 0; return hdr_size + rmpp_recv->seg_num * data_size - pad; @@ -583,6 +583,7 @@ static int send_next_seg(struct ib_mad_send_wr_private *mad_send_wr) { struct ib_rmpp_mad *rmpp_mad; int timeout; + u32 paylen; rmpp_mad = (struct ib_rmpp_mad *)mad_send_wr->send_wr.wr.ud.mad_hdr; ib_set_rmpp_flags(&rmpp_mad->rmpp_hdr, IB_MGMT_RMPP_FLAG_ACTIVE); @@ -590,11 +591,9 @@ static int send_next_seg(struct ib_mad_send_wr_private *mad_send_wr) if (mad_send_wr->seg_num == 1) { rmpp_mad->rmpp_hdr.rmpp_rtime_flags |= IB_MGMT_RMPP_FLAG_FIRST; - rmpp_mad->rmpp_hdr.paylen_newwin = - cpu_to_be32(mad_send_wr->total_seg * - (sizeof(struct ib_rmpp_mad) - - offsetof(struct ib_rmpp_mad, data)) - - mad_send_wr->pad); + paylen = mad_send_wr->total_seg * IB_MGMT_RMPP_DATA - + mad_send_wr->pad; + rmpp_mad->rmpp_hdr.paylen_newwin = cpu_to_be32(paylen); mad_send_wr->sg_list[0].length = sizeof(struct ib_rmpp_mad); } else { mad_send_wr->send_wr.num_sge = 2; @@ -608,10 +607,8 @@ static int send_next_seg(struct ib_mad_send_wr_private *mad_send_wr) if (mad_send_wr->seg_num == mad_send_wr->total_seg) { rmpp_mad->rmpp_hdr.rmpp_rtime_flags |= IB_MGMT_RMPP_FLAG_LAST; - rmpp_mad->rmpp_hdr.paylen_newwin = - cpu_to_be32(sizeof(struct ib_rmpp_mad) - - offsetof(struct ib_rmpp_mad, data) - - mad_send_wr->pad); + paylen = IB_MGMT_RMPP_DATA - mad_send_wr->pad; + rmpp_mad->rmpp_hdr.paylen_newwin = cpu_to_be32(paylen); } /* 2 seconds for an ACK until we can find the packet lifetime */ diff --git a/drivers/infiniband/core/user_mad.c b/drivers/infiniband/core/user_mad.c index 7c2f030..a64d6b4 100644 --- a/drivers/infiniband/core/user_mad.c +++ b/drivers/infiniband/core/user_mad.c @@ -334,10 +334,11 @@ static ssize_t ib_umad_write(struct file *filp, const char __user *buf, ret = -EINVAL; goto err_ah; } - /* Validate that management class can support RMPP */ + + /* Validate that the management class can support RMPP */ if (rmpp_mad->mad_hdr.mgmt_class == IB_MGMT_CLASS_SUBN_ADM) { hdr_len = offsetof(struct ib_sa_mad, data); - data_len = length; + data_len = length - hdr_len; } else if ((rmpp_mad->mad_hdr.mgmt_class >= IB_MGMT_CLASS_VENDOR_RANGE2_START) && (rmpp_mad->mad_hdr.mgmt_class <= IB_MGMT_CLASS_VENDOR_RANGE2_END)) { hdr_len = offsetof(struct ib_vendor_mad, data); diff --git a/drivers/infiniband/hw/mthca/mthca_eq.c b/drivers/infiniband/hw/mthca/mthca_eq.c index 18f0981..78152a8 100644 --- a/drivers/infiniband/hw/mthca/mthca_eq.c +++ b/drivers/infiniband/hw/mthca/mthca_eq.c @@ -476,12 +476,8 @@ static int __devinit mthca_create_eq(struct mthca_dev *dev, int i; u8 status; - /* Make sure EQ size is aligned to a power of 2 size. */ - for (i = 1; i < nent; i <<= 1) - ; /* nothing */ - nent = i; - - eq->dev = dev; + eq->dev = dev; + eq->nent = roundup_pow_of_two(max(nent, 2)); eq->page_list = kmalloc(npages * sizeof *eq->page_list, GFP_KERNEL); @@ -512,7 +508,7 @@ static int __devinit mthca_create_eq(struct mthca_dev *dev, memset(eq->page_list[i].buf, 0, PAGE_SIZE); } - for (i = 0; i < nent; ++i) + for (i = 0; i < eq->nent; ++i) set_eqe_hw(get_eqe(eq, i)); eq->eqn = mthca_alloc(&dev->eq_table.alloc); @@ -528,8 +524,6 @@ static int __devinit mthca_create_eq(struct mthca_dev *dev, if (err) goto err_out_free_eq; - eq->nent = nent; - memset(eq_context, 0, sizeof *eq_context); eq_context->flags = cpu_to_be32(MTHCA_EQ_STATUS_OK | MTHCA_EQ_OWNER_HW | @@ -538,7 +532,7 @@ static int __devinit mthca_create_eq(struct mthca_dev *dev, if (mthca_is_memfree(dev)) eq_context->flags |= cpu_to_be32(MTHCA_EQ_STATE_ARBEL); - eq_context->logsize_usrpage = cpu_to_be32((ffs(nent) - 1) << 24); + eq_context->logsize_usrpage = cpu_to_be32((ffs(eq->nent) - 1) << 24); if (mthca_is_memfree(dev)) { eq_context->arbel_pd = cpu_to_be32(dev->driver_pd.pd_num); } else { @@ -569,7 +563,7 @@ static int __devinit mthca_create_eq(struct mthca_dev *dev, dev->eq_table.arm_mask |= eq->eqn_mask; mthca_dbg(dev, "Allocated EQ %d with %d entries\n", - eq->eqn, nent); + eq->eqn, eq->nent); return err; diff --git a/drivers/infiniband/hw/mthca/mthca_qp.c b/drivers/infiniband/hw/mthca/mthca_qp.c index bcef06b..5fa0066 100644 --- a/drivers/infiniband/hw/mthca/mthca_qp.c +++ b/drivers/infiniband/hw/mthca/mthca_qp.c @@ -227,7 +227,6 @@ static void mthca_wq_init(struct mthca_wq *wq) wq->last_comp = wq->max - 1; wq->head = 0; wq->tail = 0; - wq->last = NULL; } void mthca_qp_event(struct mthca_dev *dev, u32 qpn, @@ -687,7 +686,7 @@ int mthca_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, int attr_mask) } if (attr_mask & IB_QP_TIMEOUT) { - qp_context->pri_path.ackto = attr->timeout; + qp_context->pri_path.ackto = attr->timeout << 3; qp_param->opt_param_mask |= cpu_to_be32(MTHCA_QP_OPTPAR_ACK_TIMEOUT); } @@ -1103,6 +1102,9 @@ static int mthca_alloc_qp_common(struct mthca_dev *dev, } } + qp->sq.last = get_send_wqe(qp, qp->sq.max - 1); + qp->rq.last = get_recv_wqe(qp, qp->rq.max - 1); + return 0; } @@ -1583,15 +1585,13 @@ int mthca_tavor_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr, goto out; } - if (prev_wqe) { - ((struct mthca_next_seg *) prev_wqe)->nda_op = - cpu_to_be32(((ind << qp->sq.wqe_shift) + - qp->send_wqe_offset) | - mthca_opcode[wr->opcode]); - wmb(); - ((struct mthca_next_seg *) prev_wqe)->ee_nds = - cpu_to_be32((size0 ? 0 : MTHCA_NEXT_DBD) | size); - } + ((struct mthca_next_seg *) prev_wqe)->nda_op = + cpu_to_be32(((ind << qp->sq.wqe_shift) + + qp->send_wqe_offset) | + mthca_opcode[wr->opcode]); + wmb(); + ((struct mthca_next_seg *) prev_wqe)->ee_nds = + cpu_to_be32((size0 ? 0 : MTHCA_NEXT_DBD) | size); if (!size0) { size0 = size; @@ -1688,13 +1688,11 @@ int mthca_tavor_post_receive(struct ib_qp *ibqp, struct ib_recv_wr *wr, qp->wrid[ind] = wr->wr_id; - if (likely(prev_wqe)) { - ((struct mthca_next_seg *) prev_wqe)->nda_op = - cpu_to_be32((ind << qp->rq.wqe_shift) | 1); - wmb(); - ((struct mthca_next_seg *) prev_wqe)->ee_nds = - cpu_to_be32(MTHCA_NEXT_DBD | size); - } + ((struct mthca_next_seg *) prev_wqe)->nda_op = + cpu_to_be32((ind << qp->rq.wqe_shift) | 1); + wmb(); + ((struct mthca_next_seg *) prev_wqe)->ee_nds = + cpu_to_be32(MTHCA_NEXT_DBD | size); if (!size0) size0 = size; @@ -1905,15 +1903,13 @@ int mthca_arbel_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr, goto out; } - if (likely(prev_wqe)) { - ((struct mthca_next_seg *) prev_wqe)->nda_op = - cpu_to_be32(((ind << qp->sq.wqe_shift) + - qp->send_wqe_offset) | - mthca_opcode[wr->opcode]); - wmb(); - ((struct mthca_next_seg *) prev_wqe)->ee_nds = - cpu_to_be32(MTHCA_NEXT_DBD | size); - } + ((struct mthca_next_seg *) prev_wqe)->nda_op = + cpu_to_be32(((ind << qp->sq.wqe_shift) + + qp->send_wqe_offset) | + mthca_opcode[wr->opcode]); + wmb(); + ((struct mthca_next_seg *) prev_wqe)->ee_nds = + cpu_to_be32(MTHCA_NEXT_DBD | size); if (!size0) { size0 = size; @@ -2127,5 +2123,6 @@ void __devexit mthca_cleanup_qp_table(struct mthca_dev *dev) for (i = 0; i < 2; ++i) mthca_CONF_SPECIAL_QP(dev, i, 0, &status); + mthca_array_cleanup(&dev->qp_table.qp, dev->limits.num_qps); mthca_alloc_cleanup(&dev->qp_table.alloc); } diff --git a/drivers/infiniband/hw/mthca/mthca_srq.c b/drivers/infiniband/hw/mthca/mthca_srq.c index 75cd2d8..18998d4 100644 --- a/drivers/infiniband/hw/mthca/mthca_srq.c +++ b/drivers/infiniband/hw/mthca/mthca_srq.c @@ -172,6 +172,8 @@ static int mthca_alloc_srq_buf(struct mthca_dev *dev, struct mthca_pd *pd, scatter->lkey = cpu_to_be32(MTHCA_INVAL_LKEY); } + srq->last = get_wqe(srq, srq->max - 1); + return 0; } @@ -189,7 +191,6 @@ int mthca_alloc_srq(struct mthca_dev *dev, struct mthca_pd *pd, srq->max = attr->max_wr; srq->max_gs = attr->max_sge; - srq->last = NULL; srq->counter = 0; if (mthca_is_memfree(dev)) @@ -409,7 +410,7 @@ int mthca_tavor_post_srq_recv(struct ib_srq *ibsrq, struct ib_recv_wr *wr, mthca_err(dev, "SRQ %06x full\n", srq->srqn); err = -ENOMEM; *bad_wr = wr; - return nreq; + break; } wqe = get_wqe(srq, ind); @@ -427,7 +428,7 @@ int mthca_tavor_post_srq_recv(struct ib_srq *ibsrq, struct ib_recv_wr *wr, err = -EINVAL; *bad_wr = wr; srq->last = prev_wqe; - return nreq; + break; } for (i = 0; i < wr->num_sge; ++i) { @@ -446,20 +447,16 @@ int mthca_tavor_post_srq_recv(struct ib_srq *ibsrq, struct ib_recv_wr *wr, ((struct mthca_data_seg *) wqe)->addr = 0; } - if (likely(prev_wqe)) { - ((struct mthca_next_seg *) prev_wqe)->nda_op = - cpu_to_be32((ind << srq->wqe_shift) | 1); - wmb(); - ((struct mthca_next_seg *) prev_wqe)->ee_nds = - cpu_to_be32(MTHCA_NEXT_DBD); - } + ((struct mthca_next_seg *) prev_wqe)->nda_op = + cpu_to_be32((ind << srq->wqe_shift) | 1); + wmb(); + ((struct mthca_next_seg *) prev_wqe)->ee_nds = + cpu_to_be32(MTHCA_NEXT_DBD); srq->wrid[ind] = wr->wr_id; srq->first_free = next_ind; } - return nreq; - if (likely(nreq)) { __be32 doorbell[2]; @@ -503,7 +500,7 @@ int mthca_arbel_post_srq_recv(struct ib_srq *ibsrq, struct ib_recv_wr *wr, mthca_err(dev, "SRQ %06x full\n", srq->srqn); err = -ENOMEM; *bad_wr = wr; - return nreq; + break; } wqe = get_wqe(srq, ind); @@ -519,7 +516,7 @@ int mthca_arbel_post_srq_recv(struct ib_srq *ibsrq, struct ib_recv_wr *wr, if (unlikely(wr->num_sge > srq->max_gs)) { err = -EINVAL; *bad_wr = wr; - return nreq; + break; } for (i = 0; i < wr->num_sge; ++i) { diff --git a/drivers/infiniband/ulp/ipoib/ipoib.h b/drivers/infiniband/ulp/ipoib/ipoib.h index bea960b..4ea1c1c 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib.h +++ b/drivers/infiniband/ulp/ipoib/ipoib.h @@ -257,7 +257,7 @@ void ipoib_mcast_send(struct net_device *dev, union ib_gid *mgid, void ipoib_mcast_restart_task(void *dev_ptr); int ipoib_mcast_start_thread(struct net_device *dev); -int ipoib_mcast_stop_thread(struct net_device *dev); +int ipoib_mcast_stop_thread(struct net_device *dev, int flush); void ipoib_mcast_dev_down(struct net_device *dev); void ipoib_mcast_dev_flush(struct net_device *dev); diff --git a/drivers/infiniband/ulp/ipoib/ipoib_ib.c b/drivers/infiniband/ulp/ipoib/ipoib_ib.c index ef0e389..f744009 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib_ib.c +++ b/drivers/infiniband/ulp/ipoib/ipoib_ib.c @@ -432,7 +432,7 @@ int ipoib_ib_dev_down(struct net_device *dev) flush_workqueue(ipoib_workqueue); } - ipoib_mcast_stop_thread(dev); + ipoib_mcast_stop_thread(dev, 1); /* * Flush the multicast groups first so we stop any multicast joins. The @@ -599,7 +599,7 @@ void ipoib_ib_dev_cleanup(struct net_device *dev) ipoib_dbg(priv, "cleaning up ib_dev\n"); - ipoib_mcast_stop_thread(dev); + ipoib_mcast_stop_thread(dev, 1); /* Delete the broadcast address and the local address */ ipoib_mcast_dev_down(dev); diff --git a/drivers/infiniband/ulp/ipoib/ipoib_main.c b/drivers/infiniband/ulp/ipoib/ipoib_main.c index 49d120d..704f48e 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib_main.c +++ b/drivers/infiniband/ulp/ipoib/ipoib_main.c @@ -1005,6 +1005,7 @@ debug_failed: register_failed: ib_unregister_event_handler(&priv->event_handler); + flush_scheduled_work(); event_failed: ipoib_dev_cleanup(priv->dev); @@ -1057,6 +1058,7 @@ static void ipoib_remove_one(struct ib_device *device) list_for_each_entry_safe(priv, tmp, dev_list, list) { ib_unregister_event_handler(&priv->event_handler); + flush_scheduled_work(); unregister_netdev(priv->dev); ipoib_dev_cleanup(priv->dev); diff --git a/drivers/infiniband/ulp/ipoib/ipoib_multicast.c b/drivers/infiniband/ulp/ipoib/ipoib_multicast.c index aca7aea..36ce298 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib_multicast.c +++ b/drivers/infiniband/ulp/ipoib/ipoib_multicast.c @@ -145,7 +145,7 @@ static struct ipoib_mcast *ipoib_mcast_alloc(struct net_device *dev, mcast->dev = dev; mcast->created = jiffies; - mcast->backoff = HZ; + mcast->backoff = 1; mcast->logcount = 0; INIT_LIST_HEAD(&mcast->list); @@ -396,7 +396,7 @@ static void ipoib_mcast_join_complete(int status, IPOIB_GID_ARG(mcast->mcmember.mgid), status); if (!status && !ipoib_mcast_join_finish(mcast, mcmember)) { - mcast->backoff = HZ; + mcast->backoff = 1; down(&mcast_mutex); if (test_bit(IPOIB_MCAST_RUN, &priv->flags)) queue_work(ipoib_workqueue, &priv->mcast_task); @@ -496,7 +496,7 @@ static void ipoib_mcast_join(struct net_device *dev, struct ipoib_mcast *mcast, if (test_bit(IPOIB_MCAST_RUN, &priv->flags)) queue_delayed_work(ipoib_workqueue, &priv->mcast_task, - mcast->backoff); + mcast->backoff * HZ); up(&mcast_mutex); } else mcast->query_id = ret; @@ -598,7 +598,7 @@ int ipoib_mcast_start_thread(struct net_device *dev) return 0; } -int ipoib_mcast_stop_thread(struct net_device *dev) +int ipoib_mcast_stop_thread(struct net_device *dev, int flush) { struct ipoib_dev_priv *priv = netdev_priv(dev); struct ipoib_mcast *mcast; @@ -610,7 +610,8 @@ int ipoib_mcast_stop_thread(struct net_device *dev) cancel_delayed_work(&priv->mcast_task); up(&mcast_mutex); - flush_workqueue(ipoib_workqueue); + if (flush) + flush_workqueue(ipoib_workqueue); if (priv->broadcast && priv->broadcast->query) { ib_sa_cancel_query(priv->broadcast->query_id, priv->broadcast->query); @@ -832,7 +833,7 @@ void ipoib_mcast_restart_task(void *dev_ptr) ipoib_dbg_mcast(priv, "restarting multicast task\n"); - ipoib_mcast_stop_thread(dev); + ipoib_mcast_stop_thread(dev, 0); spin_lock_irqsave(&priv->lock, flags); diff --git a/drivers/input/keyboard/Kconfig b/drivers/input/keyboard/Kconfig index e55dee3..444f775 100644 --- a/drivers/input/keyboard/Kconfig +++ b/drivers/input/keyboard/Kconfig @@ -132,6 +132,17 @@ config KEYBOARD_CORGI To compile this driver as a module, choose M here: the module will be called corgikbd. +config KEYBOARD_SPITZ + tristate "Spitz keyboard" + depends on PXA_SHARPSL + default y + help + Say Y here to enable the keyboard on the Sharp Zaurus SL-C1000, + SL-C3000 and Sl-C3100 series of PDAs. + + To compile this driver as a module, choose M here: the + module will be called spitzkbd. + config KEYBOARD_MAPLE tristate "Maple bus keyboard" depends on SH_DREAMCAST && MAPLE diff --git a/drivers/input/keyboard/Makefile b/drivers/input/keyboard/Makefile index b02eece..9ce0b87 100644 --- a/drivers/input/keyboard/Makefile +++ b/drivers/input/keyboard/Makefile @@ -14,6 +14,7 @@ obj-$(CONFIG_KEYBOARD_LOCOMO) += locomokbd.o obj-$(CONFIG_KEYBOARD_NEWTON) += newtonkbd.o obj-$(CONFIG_KEYBOARD_98KBD) += 98kbd.o obj-$(CONFIG_KEYBOARD_CORGI) += corgikbd.o +obj-$(CONFIG_KEYBOARD_SPITZ) += spitzkbd.o obj-$(CONFIG_KEYBOARD_HIL) += hil_kbd.o obj-$(CONFIG_KEYBOARD_HIL_OLD) += hilkbd.o diff --git a/drivers/input/keyboard/spitzkbd.c b/drivers/input/keyboard/spitzkbd.c new file mode 100644 index 0000000..1714045 --- /dev/null +++ b/drivers/input/keyboard/spitzkbd.c @@ -0,0 +1,478 @@ +/* + * Keyboard driver for Sharp Spitz, Borzoi and Akita (SL-Cxx00 series) + * + * Copyright (c) 2005 Richard Purdie + * + * Based on corgikbd.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. + * + */ + +#include <linux/delay.h> +#include <linux/device.h> +#include <linux/init.h> +#include <linux/input.h> +#include <linux/interrupt.h> +#include <linux/jiffies.h> +#include <linux/module.h> +#include <linux/slab.h> +#include <asm/irq.h> + +#include <asm/arch/spitz.h> +#include <asm/arch/hardware.h> +#include <asm/arch/pxa-regs.h> + +#define KB_ROWS 7 +#define KB_COLS 11 +#define KB_ROWMASK(r) (1 << (r)) +#define SCANCODE(r,c) (((r)<<4) + (c) + 1) +#define NR_SCANCODES ((KB_ROWS<<4) + 1) + +#define HINGE_SCAN_INTERVAL (150) /* ms */ + +#define SPITZ_KEY_CALENDER KEY_F1 +#define SPITZ_KEY_ADDRESS KEY_F2 +#define SPITZ_KEY_FN KEY_F3 +#define SPITZ_KEY_CANCEL KEY_F4 +#define SPITZ_KEY_EXOK KEY_F5 +#define SPITZ_KEY_EXCANCEL KEY_F6 +#define SPITZ_KEY_EXJOGDOWN KEY_F7 +#define SPITZ_KEY_EXJOGUP KEY_F8 +#define SPITZ_KEY_JAP1 KEY_LEFTALT +#define SPITZ_KEY_JAP2 KEY_RIGHTCTRL +#define SPITZ_KEY_SYNC KEY_F9 +#define SPITZ_KEY_MAIL KEY_F10 +#define SPITZ_KEY_OK KEY_F11 +#define SPITZ_KEY_MENU KEY_F12 + +static unsigned char spitzkbd_keycode[NR_SCANCODES] = { + 0, /* 0 */ + KEY_LEFTCTRL, KEY_1, KEY_3, KEY_5, KEY_6, KEY_7, KEY_9, KEY_0, KEY_BACKSPACE, SPITZ_KEY_EXOK, SPITZ_KEY_EXCANCEL, 0, 0, 0, 0, 0, /* 1-16 */ + 0, KEY_2, KEY_4, KEY_R, KEY_Y, KEY_8, KEY_I, KEY_O, KEY_P, SPITZ_KEY_EXJOGDOWN, SPITZ_KEY_EXJOGUP, 0, 0, 0, 0, 0, /* 17-32 */ + KEY_TAB, KEY_Q, KEY_E, KEY_T, KEY_G, KEY_U, KEY_J, KEY_K, 0, 0, 0, 0, 0, 0, 0, 0, /* 33-48 */ + SPITZ_KEY_CALENDER, KEY_W, KEY_S, KEY_F, KEY_V, KEY_H, KEY_M, KEY_L, 0, 0, KEY_RIGHTSHIFT, 0, 0, 0, 0, 0, /* 49-64 */ + SPITZ_KEY_ADDRESS, KEY_A, KEY_D, KEY_C, KEY_B, KEY_N, KEY_DOT, 0, KEY_ENTER, KEY_LEFTSHIFT, 0, 0, 0, 0, 0, 0, /* 65-80 */ + SPITZ_KEY_MAIL, KEY_Z, KEY_X, KEY_MINUS, KEY_SPACE, KEY_COMMA, 0, KEY_UP, 0, 0, SPITZ_KEY_FN, 0, 0, 0, 0, 0, /* 81-96 */ + KEY_SYSRQ, SPITZ_KEY_JAP1, SPITZ_KEY_JAP2, SPITZ_KEY_CANCEL, SPITZ_KEY_OK, SPITZ_KEY_MENU, KEY_LEFT, KEY_DOWN, KEY_RIGHT, 0, 0, 0, 0, 0, 0, 0 /* 97-112 */ +}; + +static int spitz_strobes[] = { + SPITZ_GPIO_KEY_STROBE0, + SPITZ_GPIO_KEY_STROBE1, + SPITZ_GPIO_KEY_STROBE2, + SPITZ_GPIO_KEY_STROBE3, + SPITZ_GPIO_KEY_STROBE4, + SPITZ_GPIO_KEY_STROBE5, + SPITZ_GPIO_KEY_STROBE6, + SPITZ_GPIO_KEY_STROBE7, + SPITZ_GPIO_KEY_STROBE8, + SPITZ_GPIO_KEY_STROBE9, + SPITZ_GPIO_KEY_STROBE10, +}; + +static int spitz_senses[] = { + SPITZ_GPIO_KEY_SENSE0, + SPITZ_GPIO_KEY_SENSE1, + SPITZ_GPIO_KEY_SENSE2, + SPITZ_GPIO_KEY_SENSE3, + SPITZ_GPIO_KEY_SENSE4, + SPITZ_GPIO_KEY_SENSE5, + SPITZ_GPIO_KEY_SENSE6, +}; + +struct spitzkbd { + unsigned char keycode[ARRAY_SIZE(spitzkbd_keycode)]; + struct input_dev input; + char phys[32]; + + spinlock_t lock; + struct timer_list timer; + struct timer_list htimer; + + unsigned int suspended; + unsigned long suspend_jiffies; +}; + +#define KB_DISCHARGE_DELAY 10 +#define KB_ACTIVATE_DELAY 10 + +/* Helper functions for reading the keyboard matrix + * Note: We should really be using pxa_gpio_mode to alter GPDR but it + * requires a function call per GPIO bit which is excessive + * when we need to access 11 bits at once, multiple times. + * These functions must be called within local_irq_save()/local_irq_restore() + * or similar. + */ +static inline void spitzkbd_discharge_all(void) +{ + /* STROBE All HiZ */ + GPCR0 = SPITZ_GPIO_G0_STROBE_BIT; + GPDR0 &= ~SPITZ_GPIO_G0_STROBE_BIT; + GPCR1 = SPITZ_GPIO_G1_STROBE_BIT; + GPDR1 &= ~SPITZ_GPIO_G1_STROBE_BIT; + GPCR2 = SPITZ_GPIO_G2_STROBE_BIT; + GPDR2 &= ~SPITZ_GPIO_G2_STROBE_BIT; + GPCR3 = SPITZ_GPIO_G3_STROBE_BIT; + GPDR3 &= ~SPITZ_GPIO_G3_STROBE_BIT; +} + +static inline void spitzkbd_activate_all(void) +{ + /* STROBE ALL -> High */ + GPSR0 = SPITZ_GPIO_G0_STROBE_BIT; + GPDR0 |= SPITZ_GPIO_G0_STROBE_BIT; + GPSR1 = SPITZ_GPIO_G1_STROBE_BIT; + GPDR1 |= SPITZ_GPIO_G1_STROBE_BIT; + GPSR2 = SPITZ_GPIO_G2_STROBE_BIT; + GPDR2 |= SPITZ_GPIO_G2_STROBE_BIT; + GPSR3 = SPITZ_GPIO_G3_STROBE_BIT; + GPDR3 |= SPITZ_GPIO_G3_STROBE_BIT; + + udelay(KB_DISCHARGE_DELAY); + + /* Clear any interrupts we may have triggered when altering the GPIO lines */ + GEDR0 = SPITZ_GPIO_G0_SENSE_BIT; + GEDR1 = SPITZ_GPIO_G1_SENSE_BIT; + GEDR2 = SPITZ_GPIO_G2_SENSE_BIT; + GEDR3 = SPITZ_GPIO_G3_SENSE_BIT; +} + +static inline void spitzkbd_activate_col(int col) +{ + int gpio = spitz_strobes[col]; + GPDR0 &= ~SPITZ_GPIO_G0_STROBE_BIT; + GPDR1 &= ~SPITZ_GPIO_G1_STROBE_BIT; + GPDR2 &= ~SPITZ_GPIO_G2_STROBE_BIT; + GPDR3 &= ~SPITZ_GPIO_G3_STROBE_BIT; + GPSR(gpio) = GPIO_bit(gpio); + GPDR(gpio) |= GPIO_bit(gpio); +} + +static inline void spitzkbd_reset_col(int col) +{ + int gpio = spitz_strobes[col]; + GPDR0 &= ~SPITZ_GPIO_G0_STROBE_BIT; + GPDR1 &= ~SPITZ_GPIO_G1_STROBE_BIT; + GPDR2 &= ~SPITZ_GPIO_G2_STROBE_BIT; + GPDR3 &= ~SPITZ_GPIO_G3_STROBE_BIT; + GPCR(gpio) = GPIO_bit(gpio); + GPDR(gpio) |= GPIO_bit(gpio); +} + +static inline int spitzkbd_get_row_status(int col) +{ + return ((GPLR0 >> 12) & 0x01) | ((GPLR0 >> 16) & 0x02) + | ((GPLR2 >> 25) & 0x04) | ((GPLR1 << 1) & 0x08) + | ((GPLR1 >> 0) & 0x10) | ((GPLR1 >> 1) & 0x60); +} + +/* + * The spitz keyboard only generates interrupts when a key is pressed. + * When a key is pressed, we enable a timer which then scans the + * keyboard to detect when the key is released. + */ + +/* Scan the hardware keyboard and push any changes up through the input layer */ +static void spitzkbd_scankeyboard(struct spitzkbd *spitzkbd_data, struct pt_regs *regs) +{ + unsigned int row, col, rowd; + unsigned long flags; + unsigned int num_pressed, pwrkey = ((GPLR(SPITZ_GPIO_ON_KEY) & GPIO_bit(SPITZ_GPIO_ON_KEY)) != 0); + + if (spitzkbd_data->suspended) + return; + + spin_lock_irqsave(&spitzkbd_data->lock, flags); + + if (regs) + input_regs(&spitzkbd_data->input, regs); + + num_pressed = 0; + for (col = 0; col < KB_COLS; col++) { + /* + * Discharge the output driver capacitatance + * in the keyboard matrix. (Yes it is significant..) + */ + + spitzkbd_discharge_all(); + udelay(KB_DISCHARGE_DELAY); + + spitzkbd_activate_col(col); + udelay(KB_ACTIVATE_DELAY); + + rowd = spitzkbd_get_row_status(col); + for (row = 0; row < KB_ROWS; row++) { + unsigned int scancode, pressed; + + scancode = SCANCODE(row, col); + pressed = rowd & KB_ROWMASK(row); + + input_report_key(&spitzkbd_data->input, spitzkbd_data->keycode[scancode], pressed); + + if (pressed) + num_pressed++; + } + spitzkbd_reset_col(col); + } + + spitzkbd_activate_all(); + + input_report_key(&spitzkbd_data->input, SPITZ_KEY_SYNC, (GPLR(SPITZ_GPIO_SYNC) & GPIO_bit(SPITZ_GPIO_SYNC)) != 0 ); + input_report_key(&spitzkbd_data->input, KEY_SUSPEND, pwrkey); + + if (pwrkey && time_after(jiffies, spitzkbd_data->suspend_jiffies + msecs_to_jiffies(1000))) { + input_event(&spitzkbd_data->input, EV_PWR, KEY_SUSPEND, 1); + spitzkbd_data->suspend_jiffies = jiffies; + } + + input_sync(&spitzkbd_data->input); + + /* if any keys are pressed, enable the timer */ + if (num_pressed) + mod_timer(&spitzkbd_data->timer, jiffies + msecs_to_jiffies(100)); + + spin_unlock_irqrestore(&spitzkbd_data->lock, flags); +} + +/* + * spitz keyboard interrupt handler. + */ +static irqreturn_t spitzkbd_interrupt(int irq, void *dev_id, struct pt_regs *regs) +{ + struct spitzkbd *spitzkbd_data = dev_id; + + if (!timer_pending(&spitzkbd_data->timer)) { + /** wait chattering delay **/ + udelay(20); + spitzkbd_scankeyboard(spitzkbd_data, regs); + } + + return IRQ_HANDLED; +} + +/* + * spitz timer checking for released keys + */ +static void spitzkbd_timer_callback(unsigned long data) +{ + struct spitzkbd *spitzkbd_data = (struct spitzkbd *) data; + spitzkbd_scankeyboard(spitzkbd_data, NULL); +} + +/* + * The hinge switches generate an interrupt. + * We debounce the switches and pass them to the input system. + */ + +static irqreturn_t spitzkbd_hinge_isr(int irq, void *dev_id, struct pt_regs *regs) +{ + struct spitzkbd *spitzkbd_data = dev_id; + + if (!timer_pending(&spitzkbd_data->htimer)) + mod_timer(&spitzkbd_data->htimer, jiffies + msecs_to_jiffies(HINGE_SCAN_INTERVAL)); + + return IRQ_HANDLED; +} + +#define HINGE_STABLE_COUNT 2 +static int sharpsl_hinge_state; +static int hinge_count; + +static void spitzkbd_hinge_timer(unsigned long data) +{ + struct spitzkbd *spitzkbd_data = (struct spitzkbd *) data; + unsigned long state; + unsigned long flags; + + state = GPLR(SPITZ_GPIO_SWA) & (GPIO_bit(SPITZ_GPIO_SWA)|GPIO_bit(SPITZ_GPIO_SWB)); + if (state != sharpsl_hinge_state) { + hinge_count = 0; + sharpsl_hinge_state = state; + } else if (hinge_count < HINGE_STABLE_COUNT) { + hinge_count++; + } + + if (hinge_count >= HINGE_STABLE_COUNT) { + spin_lock_irqsave(&spitzkbd_data->lock, flags); + + input_report_switch(&spitzkbd_data->input, SW_0, ((GPLR(SPITZ_GPIO_SWA) & GPIO_bit(SPITZ_GPIO_SWA)) != 0)); + input_report_switch(&spitzkbd_data->input, SW_1, ((GPLR(SPITZ_GPIO_SWB) & GPIO_bit(SPITZ_GPIO_SWB)) != 0)); + input_sync(&spitzkbd_data->input); + + spin_unlock_irqrestore(&spitzkbd_data->lock, flags); + } else { + mod_timer(&spitzkbd_data->htimer, jiffies + msecs_to_jiffies(HINGE_SCAN_INTERVAL)); + } +} + +#ifdef CONFIG_PM +static int spitzkbd_suspend(struct device *dev, pm_message_t state, uint32_t level) +{ + if (level == SUSPEND_POWER_DOWN) { + int i; + struct spitzkbd *spitzkbd = dev_get_drvdata(dev); + spitzkbd->suspended = 1; + + /* Set Strobe lines as inputs - *except* strobe line 0 leave this + enabled so we can detect a power button press for resume */ + for (i = 1; i < SPITZ_KEY_STROBE_NUM; i++) + pxa_gpio_mode(spitz_strobes[i] | GPIO_IN); + } + return 0; +} + +static int spitzkbd_resume(struct device *dev, uint32_t level) +{ + if (level == RESUME_POWER_ON) { + int i; + struct spitzkbd *spitzkbd = dev_get_drvdata(dev); + + for (i = 0; i < SPITZ_KEY_STROBE_NUM; i++) + pxa_gpio_mode(spitz_strobes[i] | GPIO_OUT | GPIO_DFLT_HIGH); + + /* Upon resume, ignore the suspend key for a short while */ + spitzkbd->suspend_jiffies = jiffies; + spitzkbd->suspended = 0; + } + return 0; +} +#else +#define spitzkbd_suspend NULL +#define spitzkbd_resume NULL +#endif + +static int __init spitzkbd_probe(struct device *dev) +{ + int i; + struct spitzkbd *spitzkbd; + + spitzkbd = kzalloc(sizeof(struct spitzkbd), GFP_KERNEL); + if (!spitzkbd) + return -ENOMEM; + + dev_set_drvdata(dev,spitzkbd); + strcpy(spitzkbd->phys, "spitzkbd/input0"); + + spin_lock_init(&spitzkbd->lock); + + /* Init Keyboard rescan timer */ + init_timer(&spitzkbd->timer); + spitzkbd->timer.function = spitzkbd_timer_callback; + spitzkbd->timer.data = (unsigned long) spitzkbd; + + /* Init Hinge Timer */ + init_timer(&spitzkbd->htimer); + spitzkbd->htimer.function = spitzkbd_hinge_timer; + spitzkbd->htimer.data = (unsigned long) spitzkbd; + + spitzkbd->suspend_jiffies=jiffies; + + init_input_dev(&spitzkbd->input); + spitzkbd->input.private = spitzkbd; + spitzkbd->input.name = "Spitz Keyboard"; + spitzkbd->input.dev = dev; + spitzkbd->input.phys = spitzkbd->phys; + spitzkbd->input.id.bustype = BUS_HOST; + spitzkbd->input.id.vendor = 0x0001; + spitzkbd->input.id.product = 0x0001; + spitzkbd->input.id.version = 0x0100; + spitzkbd->input.evbit[0] = BIT(EV_KEY) | BIT(EV_REP) | BIT(EV_PWR) | BIT(EV_SW); + spitzkbd->input.keycode = spitzkbd->keycode; + spitzkbd->input.keycodesize = sizeof(unsigned char); + spitzkbd->input.keycodemax = ARRAY_SIZE(spitzkbd_keycode); + + memcpy(spitzkbd->keycode, spitzkbd_keycode, sizeof(spitzkbd->keycode)); + for (i = 0; i < ARRAY_SIZE(spitzkbd_keycode); i++) + set_bit(spitzkbd->keycode[i], spitzkbd->input.keybit); + clear_bit(0, spitzkbd->input.keybit); + set_bit(SW_0, spitzkbd->input.swbit); + set_bit(SW_1, spitzkbd->input.swbit); + + input_register_device(&spitzkbd->input); + mod_timer(&spitzkbd->htimer, jiffies + msecs_to_jiffies(HINGE_SCAN_INTERVAL)); + + /* Setup sense interrupts - RisingEdge Detect, sense lines as inputs */ + for (i = 0; i < SPITZ_KEY_SENSE_NUM; i++) { + pxa_gpio_mode(spitz_senses[i] | GPIO_IN); + if (request_irq(IRQ_GPIO(spitz_senses[i]), spitzkbd_interrupt, + SA_INTERRUPT, "Spitzkbd Sense", spitzkbd)) + printk(KERN_WARNING "spitzkbd: Can't get Sense IRQ: %d!\n", i); + else + set_irq_type(IRQ_GPIO(spitz_senses[i]),IRQT_RISING); + } + + /* Set Strobe lines as outputs - set high */ + for (i = 0; i < SPITZ_KEY_STROBE_NUM; i++) + pxa_gpio_mode(spitz_strobes[i] | GPIO_OUT | GPIO_DFLT_HIGH); + + pxa_gpio_mode(SPITZ_GPIO_SYNC | GPIO_IN); + pxa_gpio_mode(SPITZ_GPIO_ON_KEY | GPIO_IN); + pxa_gpio_mode(SPITZ_GPIO_SWA | GPIO_IN); + pxa_gpio_mode(SPITZ_GPIO_SWB | GPIO_IN); + + request_irq(SPITZ_IRQ_GPIO_SYNC, spitzkbd_interrupt, SA_INTERRUPT, "Spitzkbd Sync", spitzkbd); + request_irq(SPITZ_IRQ_GPIO_ON_KEY, spitzkbd_interrupt, SA_INTERRUPT, "Spitzkbd PwrOn", spitzkbd); + request_irq(SPITZ_IRQ_GPIO_SWA, spitzkbd_hinge_isr, SA_INTERRUPT, "Spitzkbd SWA", spitzkbd); + request_irq(SPITZ_IRQ_GPIO_SWB, spitzkbd_hinge_isr, SA_INTERRUPT, "Spitzkbd SWB", spitzkbd); + + set_irq_type(SPITZ_IRQ_GPIO_SYNC, IRQT_BOTHEDGE); + set_irq_type(SPITZ_IRQ_GPIO_ON_KEY, IRQT_BOTHEDGE); + set_irq_type(SPITZ_IRQ_GPIO_SWA, IRQT_BOTHEDGE); + set_irq_type(SPITZ_IRQ_GPIO_SWB, IRQT_BOTHEDGE); + + printk(KERN_INFO "input: Spitz Keyboard Registered\n"); + + return 0; +} + +static int spitzkbd_remove(struct device *dev) +{ + int i; + struct spitzkbd *spitzkbd = dev_get_drvdata(dev); + + for (i = 0; i < SPITZ_KEY_SENSE_NUM; i++) + free_irq(IRQ_GPIO(spitz_senses[i]), spitzkbd); + + free_irq(SPITZ_IRQ_GPIO_SYNC, spitzkbd); + free_irq(SPITZ_IRQ_GPIO_ON_KEY, spitzkbd); + free_irq(SPITZ_IRQ_GPIO_SWA, spitzkbd); + free_irq(SPITZ_IRQ_GPIO_SWB, spitzkbd); + + del_timer_sync(&spitzkbd->htimer); + del_timer_sync(&spitzkbd->timer); + + input_unregister_device(&spitzkbd->input); + + kfree(spitzkbd); + + return 0; +} + +static struct device_driver spitzkbd_driver = { + .name = "spitz-keyboard", + .bus = &platform_bus_type, + .probe = spitzkbd_probe, + .remove = spitzkbd_remove, + .suspend = spitzkbd_suspend, + .resume = spitzkbd_resume, +}; + +static int __devinit spitzkbd_init(void) +{ + return driver_register(&spitzkbd_driver); +} + +static void __exit spitzkbd_exit(void) +{ + driver_unregister(&spitzkbd_driver); +} + +module_init(spitzkbd_init); +module_exit(spitzkbd_exit); + +MODULE_AUTHOR("Richard Purdie <rpurdie@rpsys.net>"); +MODULE_DESCRIPTION("Spitz Keyboard Driver"); +MODULE_LICENSE("GPLv2"); diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig index 0489af5..21d55ed 100644 --- a/drivers/input/touchscreen/Kconfig +++ b/drivers/input/touchscreen/Kconfig @@ -24,17 +24,17 @@ config TOUCHSCREEN_BITSY module will be called h3600_ts_input. config TOUCHSCREEN_CORGI - tristate "Corgi touchscreen (for Sharp SL-C7xx)" + tristate "SharpSL (Corgi and Spitz series) touchscreen driver" depends on PXA_SHARPSL default y help Say Y here to enable the driver for the touchscreen on the - Sharp SL-C7xx series of PDAs. + Sharp SL-C7xx and SL-Cxx00 series of PDAs. If unsure, say N. To compile this driver as a module, choose M here: the - module will be called ads7846_ts. + module will be called corgi_ts. config TOUCHSCREEN_GUNZE tristate "Gunze AHL-51S touchscreen" diff --git a/drivers/input/touchscreen/corgi_ts.c b/drivers/input/touchscreen/corgi_ts.c index 5d19261..4c7fbe5 100644 --- a/drivers/input/touchscreen/corgi_ts.c +++ b/drivers/input/touchscreen/corgi_ts.c @@ -1,5 +1,5 @@ /* - * Touchscreen driver for Sharp Corgi models (SL-C7xx) + * Touchscreen driver for Sharp SL-C7xx and SL-Cxx00 models * * Copyright (c) 2004-2005 Richard Purdie * @@ -19,7 +19,7 @@ #include <linux/slab.h> #include <asm/irq.h> -#include <asm/arch/corgi.h> +#include <asm/arch/sharpsl.h> #include <asm/arch/hardware.h> #include <asm/arch/pxa-regs.h> @@ -47,15 +47,20 @@ struct corgi_ts { struct ts_event tc; int pendown; int power_mode; + int irq_gpio; + struct corgits_machinfo *machinfo; }; -#define STATUS_HSYNC (GPLR(CORGI_GPIO_HSYNC) & GPIO_bit(CORGI_GPIO_HSYNC)) - -#define SyncHS() while((STATUS_HSYNC) == 0); while((STATUS_HSYNC) != 0); +#ifdef CONFIG_PXA25x #define CCNT(a) asm volatile ("mrc p14, 0, %0, C1, C0, 0" : "=r"(a)) #define PMNC_GET(x) asm volatile ("mrc p14, 0, %0, C0, C0, 0" : "=r"(x)) #define PMNC_SET(x) asm volatile ("mcr p14, 0, %0, C0, C0, 0" : : "r"(x)) - +#endif +#ifdef CONFIG_PXA27x +#define CCNT(a) asm volatile ("mrc p14, 0, %0, C1, C1, 0" : "=r"(a)) +#define PMNC_GET(x) asm volatile ("mrc p14, 0, %0, C0, C1, 0" : "=r"(x)) +#define PMNC_SET(x) asm volatile ("mcr p14, 0, %0, C0, C1, 0" : : "r"(x)) +#endif /* ADS7846 Touch Screen Controller bit definitions */ #define ADSCTRL_PD0 (1u << 0) /* PD0 */ @@ -66,12 +71,11 @@ struct corgi_ts { #define ADSCTRL_STS (1u << 7) /* Start Bit */ /* External Functions */ -extern unsigned long w100fb_get_hsynclen(struct device *dev); extern unsigned int get_clk_frequency_khz(int info); -static unsigned long calc_waittime(void) +static unsigned long calc_waittime(struct corgi_ts *corgi_ts) { - unsigned long hsync_len = w100fb_get_hsynclen(&corgifb_device.dev); + unsigned long hsync_len = corgi_ts->machinfo->get_hsync_len(); if (hsync_len) return get_clk_frequency_khz(0)*1000/hsync_len; @@ -79,7 +83,8 @@ static unsigned long calc_waittime(void) return 0; } -static int sync_receive_data_send_cmd(int doRecive, int doSend, unsigned int address, unsigned long wait_time) +static int sync_receive_data_send_cmd(struct corgi_ts *corgi_ts, int doRecive, int doSend, + unsigned int address, unsigned long wait_time) { unsigned long timer1 = 0, timer2, pmnc = 0; int pos = 0; @@ -90,7 +95,7 @@ static int sync_receive_data_send_cmd(int doRecive, int doSend, unsigned int add PMNC_SET(0x01); /* polling HSync */ - SyncHS(); + corgi_ts->machinfo->wait_hsync(); /* get CCNT */ CCNT(timer1); } @@ -109,7 +114,7 @@ static int sync_receive_data_send_cmd(int doRecive, int doSend, unsigned int add CCNT(timer2); if (timer2-timer1 > wait_time) { /* too slow - timeout, try again */ - SyncHS(); + corgi_ts->machinfo->wait_hsync(); /* get OSCR */ CCNT(timer1); /* Wait after HSync */ @@ -133,23 +138,23 @@ static int read_xydata(struct corgi_ts *corgi_ts) /* critical section */ local_irq_save(flags); corgi_ssp_ads7846_lock(); - wait_time=calc_waittime(); + wait_time = calc_waittime(corgi_ts); /* Y-axis */ - sync_receive_data_send_cmd(0, 1, 1u, wait_time); + sync_receive_data_send_cmd(corgi_ts, 0, 1, 1u, wait_time); /* Y-axis */ - sync_receive_data_send_cmd(1, 1, 1u, wait_time); + sync_receive_data_send_cmd(corgi_ts, 1, 1, 1u, wait_time); /* X-axis */ - y = sync_receive_data_send_cmd(1, 1, 5u, wait_time); + y = sync_receive_data_send_cmd(corgi_ts, 1, 1, 5u, wait_time); /* Z1 */ - x = sync_receive_data_send_cmd(1, 1, 3u, wait_time); + x = sync_receive_data_send_cmd(corgi_ts, 1, 1, 3u, wait_time); /* Z2 */ - z1 = sync_receive_data_send_cmd(1, 1, 4u, wait_time); - z2 = sync_receive_data_send_cmd(1, 0, 4u, wait_time); + z1 = sync_receive_data_send_cmd(corgi_ts, 1, 1, 4u, wait_time); + z2 = sync_receive_data_send_cmd(corgi_ts, 1, 0, 4u, wait_time); /* Power-Down Enable */ corgi_ssp_ads7846_put((1u << ADSCTRL_ADR_SH) | ADSCTRL_STS); @@ -189,9 +194,9 @@ static void new_data(struct corgi_ts *corgi_ts, struct pt_regs *regs) static void ts_interrupt_main(struct corgi_ts *corgi_ts, int isTimer, struct pt_regs *regs) { - if ((GPLR(CORGI_GPIO_TP_INT) & GPIO_bit(CORGI_GPIO_TP_INT)) == 0) { + if ((GPLR(IRQ_TO_GPIO(corgi_ts->irq_gpio)) & GPIO_bit(IRQ_TO_GPIO(corgi_ts->irq_gpio))) == 0) { /* Disable Interrupt */ - set_irq_type(CORGI_IRQ_GPIO_TP_INT, IRQT_NOEDGE); + set_irq_type(corgi_ts->irq_gpio, IRQT_NOEDGE); if (read_xydata(corgi_ts)) { corgi_ts->pendown = 1; new_data(corgi_ts, regs); @@ -210,7 +215,7 @@ static void ts_interrupt_main(struct corgi_ts *corgi_ts, int isTimer, struct pt_ } /* Enable Falling Edge */ - set_irq_type(CORGI_IRQ_GPIO_TP_INT, IRQT_FALLING); + set_irq_type(corgi_ts->irq_gpio, IRQT_FALLING); corgi_ts->pendown = 0; } } @@ -254,7 +259,7 @@ static int corgits_resume(struct device *dev, uint32_t level) corgi_ssp_ads7846_putget((4u << ADSCTRL_ADR_SH) | ADSCTRL_STS); /* Enable Falling Edge */ - set_irq_type(CORGI_IRQ_GPIO_TP_INT, IRQT_FALLING); + set_irq_type(corgi_ts->irq_gpio, IRQT_FALLING); corgi_ts->power_mode = PWR_MODE_ACTIVE; } return 0; @@ -267,6 +272,7 @@ static int corgits_resume(struct device *dev, uint32_t level) static int __init corgits_probe(struct device *dev) { struct corgi_ts *corgi_ts; + struct platform_device *pdev = to_platform_device(dev); if (!(corgi_ts = kmalloc(sizeof(struct corgi_ts), GFP_KERNEL))) return -ENOMEM; @@ -275,6 +281,14 @@ static int __init corgits_probe(struct device *dev) memset(corgi_ts, 0, sizeof(struct corgi_ts)); + corgi_ts->machinfo = dev->platform_data; + corgi_ts->irq_gpio = platform_get_irq(pdev, 0); + + if (corgi_ts->irq_gpio < 0) { + kfree(corgi_ts); + return -ENODEV; + } + init_input_dev(&corgi_ts->input); corgi_ts->input.evbit[0] = BIT(EV_KEY) | BIT(EV_ABS); corgi_ts->input.keybit[LONG(BTN_TOUCH)] = BIT(BTN_TOUCH); @@ -293,8 +307,7 @@ static int __init corgits_probe(struct device *dev) corgi_ts->input.id.product = 0x0002; corgi_ts->input.id.version = 0x0100; - pxa_gpio_mode(CORGI_GPIO_TP_INT | GPIO_IN); - pxa_gpio_mode(CORGI_GPIO_HSYNC | GPIO_IN); + pxa_gpio_mode(IRQ_TO_GPIO(corgi_ts->irq_gpio) | GPIO_IN); /* Initiaize ADS7846 Difference Reference mode */ corgi_ssp_ads7846_putget((1u << ADSCTRL_ADR_SH) | ADSCTRL_STS); @@ -313,14 +326,14 @@ static int __init corgits_probe(struct device *dev) input_register_device(&corgi_ts->input); corgi_ts->power_mode = PWR_MODE_ACTIVE; - if (request_irq(CORGI_IRQ_GPIO_TP_INT, ts_interrupt, SA_INTERRUPT, "ts", corgi_ts)) { + if (request_irq(corgi_ts->irq_gpio, ts_interrupt, SA_INTERRUPT, "ts", corgi_ts)) { input_unregister_device(&corgi_ts->input); kfree(corgi_ts); return -EBUSY; } /* Enable Falling Edge */ - set_irq_type(CORGI_IRQ_GPIO_TP_INT, IRQT_FALLING); + set_irq_type(corgi_ts->irq_gpio, IRQT_FALLING); printk(KERN_INFO "input: Corgi Touchscreen Registered\n"); @@ -331,8 +344,9 @@ static int corgits_remove(struct device *dev) { struct corgi_ts *corgi_ts = dev_get_drvdata(dev); - free_irq(CORGI_IRQ_GPIO_TP_INT, NULL); + free_irq(corgi_ts->irq_gpio, NULL); del_timer_sync(&corgi_ts->timer); + corgi_ts->machinfo->put_hsync(); input_unregister_device(&corgi_ts->input); kfree(corgi_ts); return 0; diff --git a/drivers/isdn/hisax/hfc_pci.c b/drivers/isdn/hisax/hfc_pci.c index 8337b0f..4866fc3 100644 --- a/drivers/isdn/hisax/hfc_pci.c +++ b/drivers/isdn/hisax/hfc_pci.c @@ -61,6 +61,7 @@ static const PCI_ENTRY id_list[] = {PCI_VENDOR_ID_DIGI, PCI_DEVICE_ID_DIGI_DF_M_E,"Digi International", "Digi DataFire Micro V (Europe)"}, {PCI_VENDOR_ID_DIGI, PCI_DEVICE_ID_DIGI_DF_M_IOM2_A,"Digi International", "Digi DataFire Micro V IOM2 (North America)"}, {PCI_VENDOR_ID_DIGI, PCI_DEVICE_ID_DIGI_DF_M_A,"Digi International", "Digi DataFire Micro V (North America)"}, + {PCI_VENDOR_ID_SITECOM, PCI_DEVICE_ID_SITECOM_DC105V2, "Sitecom Europe", "DC-105 ISDN PCI"}, {0, 0, NULL, NULL}, }; diff --git a/drivers/isdn/hisax/sedlbauer_cs.c b/drivers/isdn/hisax/sedlbauer_cs.c index c6b5bf7..dc334aa 100644 --- a/drivers/isdn/hisax/sedlbauer_cs.c +++ b/drivers/isdn/hisax/sedlbauer_cs.c @@ -611,7 +611,7 @@ static int sedlbauer_event(event_t event, int priority, } /* sedlbauer_event */ static struct pcmcia_device_id sedlbauer_ids[] = { - PCMCIA_DEVICE_PROD_ID1234("SEDLBAUER", "speed star II", "V 3.1", "(c) 93 - 98 cb ", 0x81fb79f5, 0xf3612e1d, 0x6b95c78a, 0x50d4149c), + PCMCIA_DEVICE_PROD_ID123("SEDLBAUER", "speed star II", "V 3.1", 0x81fb79f5, 0xf3612e1d, 0x6b95c78a), PCMCIA_DEVICE_PROD_ID123("SEDLBAUER", "ISDN-Adapter", "4D67", 0x81fb79f5, 0xe4e9bc12, 0x397b7e90), PCMCIA_DEVICE_PROD_ID123("SEDLBAUER", "ISDN-Adapter", "4D98", 0x81fb79f5, 0xe4e9bc12, 0x2e5c7fce), PCMCIA_DEVICE_PROD_ID123("SEDLBAUER", "ISDN-Adapter", " (C) 93-94 VK", 0x81fb79f5, 0xe4e9bc12, 0x8db143fe), diff --git a/drivers/isdn/hisax/st5481.h b/drivers/isdn/hisax/st5481.h index 0fda5c8..9ffaae7 100644 --- a/drivers/isdn/hisax/st5481.h +++ b/drivers/isdn/hisax/st5481.h @@ -466,10 +466,10 @@ void st5481_stop(struct st5481_adapter *adapter); #define __debug_variable st5481_debug #include "hisax_debug.h" -#ifdef CONFIG_HISAX_DEBUG - extern int st5481_debug; +#ifdef CONFIG_HISAX_DEBUG + #define DBG_ISO_PACKET(level,urb) \ if (level & __debug_variable) dump_iso_packet(__FUNCTION__,urb) diff --git a/drivers/isdn/hisax/st5481_b.c b/drivers/isdn/hisax/st5481_b.c index 2fcd093..657817a 100644 --- a/drivers/isdn/hisax/st5481_b.c +++ b/drivers/isdn/hisax/st5481_b.c @@ -172,14 +172,18 @@ static void usb_b_out_complete(struct urb *urb, struct pt_regs *regs) test_and_clear_bit(buf_nr, &b_out->busy); if (unlikely(urb->status < 0)) { - if (urb->status != -ENOENT && urb->status != -ESHUTDOWN) { - WARN("urb status %d",urb->status); - if (b_out->busy == 0) { - st5481_usb_pipe_reset(adapter, (bcs->channel+1)*2 | USB_DIR_OUT, NULL, NULL); - } - } else { - DBG(1,"urb killed"); - return; // Give up + switch (urb->status) { + case -ENOENT: + case -ESHUTDOWN: + case -ECONNRESET: + DBG(4,"urb killed status %d", urb->status); + return; // Give up + default: + WARN("urb status %d",urb->status); + if (b_out->busy == 0) { + st5481_usb_pipe_reset(adapter, (bcs->channel+1)*2 | USB_DIR_OUT, NULL, NULL); + } + break; } } diff --git a/drivers/isdn/hisax/st5481_d.c b/drivers/isdn/hisax/st5481_d.c index 071b1d3..941f702 100644 --- a/drivers/isdn/hisax/st5481_d.c +++ b/drivers/isdn/hisax/st5481_d.c @@ -382,16 +382,20 @@ static void usb_d_out_complete(struct urb *urb, struct pt_regs *regs) test_and_clear_bit(buf_nr, &d_out->busy); if (unlikely(urb->status < 0)) { - if (urb->status != -ENOENT && urb->status != -ESHUTDOWN) { - WARN("urb status %d",urb->status); - if (d_out->busy == 0) { - st5481_usb_pipe_reset(adapter, EP_D_OUT | USB_DIR_OUT, fifo_reseted, adapter); - } - return; - } else { - DBG(1,"urb killed"); - return; // Give up + switch (urb->status) { + case -ENOENT: + case -ESHUTDOWN: + case -ECONNRESET: + DBG(1,"urb killed status %d", urb->status); + break; + default: + WARN("urb status %d",urb->status); + if (d_out->busy == 0) { + st5481_usb_pipe_reset(adapter, EP_D_OUT | USB_DIR_OUT, fifo_reseted, adapter); + } + break; } + return; // Give up } FsmEvent(&adapter->d_out.fsm, EV_DOUT_COMPLETE, (void *) buf_nr); @@ -709,14 +713,14 @@ int st5481_setup_d(struct st5481_adapter *adapter) adapter->l1m.fsm = &l1fsm; adapter->l1m.state = ST_L1_F3; - adapter->l1m.debug = 1; + adapter->l1m.debug = st5481_debug & 0x100; adapter->l1m.userdata = adapter; adapter->l1m.printdebug = l1m_debug; FsmInitTimer(&adapter->l1m, &adapter->timer); adapter->d_out.fsm.fsm = &dout_fsm; adapter->d_out.fsm.state = ST_DOUT_NONE; - adapter->d_out.fsm.debug = 1; + adapter->d_out.fsm.debug = st5481_debug & 0x100; adapter->d_out.fsm.userdata = adapter; adapter->d_out.fsm.printdebug = dout_debug; diff --git a/drivers/isdn/hisax/st5481_init.c b/drivers/isdn/hisax/st5481_init.c index 7aa810d..2cf5d1a 100644 --- a/drivers/isdn/hisax/st5481_init.c +++ b/drivers/isdn/hisax/st5481_init.c @@ -43,10 +43,10 @@ static int number_of_leds = 2; /* 2 LEDs on the adpater default */ module_param(number_of_leds, int, 0); #ifdef CONFIG_HISAX_DEBUG -static int debug = 0x1; +static int debug = 0; module_param(debug, int, 0); -int st5481_debug; #endif +int st5481_debug; static LIST_HEAD(adapter_list); diff --git a/drivers/isdn/hisax/st5481_usb.c b/drivers/isdn/hisax/st5481_usb.c index ab62223..89fbeb5 100644 --- a/drivers/isdn/hisax/st5481_usb.c +++ b/drivers/isdn/hisax/st5481_usb.c @@ -132,11 +132,15 @@ static void usb_ctrl_complete(struct urb *urb, struct pt_regs *regs) struct ctrl_msg *ctrl_msg; if (unlikely(urb->status < 0)) { - if (urb->status != -ENOENT && urb->status != -ESHUTDOWN) { - WARN("urb status %d",urb->status); - } else { - DBG(1,"urb killed"); - return; // Give up + switch (urb->status) { + case -ENOENT: + case -ESHUTDOWN: + case -ECONNRESET: + DBG(1,"urb killed status %d", urb->status); + return; // Give up + default: + WARN("urb status %d",urb->status); + break; } } @@ -184,22 +188,22 @@ static void usb_int_complete(struct urb *urb, struct pt_regs *regs) int status; switch (urb->status) { - case 0: - /* success */ - break; - case -ECONNRESET: - case -ENOENT: - case -ESHUTDOWN: - /* this urb is terminated, clean up */ - DBG(1, "urb shutting down with status: %d", urb->status); - return; - default: - WARN("nonzero urb status received: %d", urb->status); - goto exit; + case 0: + /* success */ + break; + case -ECONNRESET: + case -ENOENT: + case -ESHUTDOWN: + /* this urb is terminated, clean up */ + DBG(2, "urb shutting down with status: %d", urb->status); + return; + default: + WARN("nonzero urb status received: %d", urb->status); + goto exit; } - DBG_PACKET(1, data, INT_PKT_SIZE); + DBG_PACKET(2, data, INT_PKT_SIZE); if (urb->actual_length == 0) { goto exit; @@ -250,7 +254,7 @@ int st5481_setup_usb(struct st5481_adapter *adapter) struct urb *urb; u8 *buf; - DBG(1,""); + DBG(2,""); if ((status = usb_reset_configuration (dev)) < 0) { WARN("reset_configuration failed,status=%d",status); @@ -330,15 +334,17 @@ void st5481_release_usb(struct st5481_adapter *adapter) DBG(1,""); // Stop and free Control and Interrupt URBs - usb_unlink_urb(ctrl->urb); + usb_kill_urb(ctrl->urb); if (ctrl->urb->transfer_buffer) kfree(ctrl->urb->transfer_buffer); usb_free_urb(ctrl->urb); + ctrl->urb = NULL; - usb_unlink_urb(intr->urb); + usb_kill_urb(intr->urb); if (intr->urb->transfer_buffer) kfree(intr->urb->transfer_buffer); usb_free_urb(intr->urb); + ctrl->urb = NULL; } /* @@ -406,6 +412,7 @@ fill_isoc_urb(struct urb *urb, struct usb_device *dev, spin_lock_init(&urb->lock); urb->dev=dev; urb->pipe=pipe; + urb->interval = 1; urb->transfer_buffer=buf; urb->number_of_packets = num_packets; urb->transfer_buffer_length=num_packets*packet_size; @@ -452,7 +459,9 @@ st5481_setup_isocpipes(struct urb* urb[2], struct usb_device *dev, if (urb[j]) { if (urb[j]->transfer_buffer) kfree(urb[j]->transfer_buffer); + urb[j]->transfer_buffer = NULL; usb_free_urb(urb[j]); + urb[j] = NULL; } } return retval; @@ -463,10 +472,11 @@ void st5481_release_isocpipes(struct urb* urb[2]) int j; for (j = 0; j < 2; j++) { - usb_unlink_urb(urb[j]); + usb_kill_urb(urb[j]); if (urb[j]->transfer_buffer) kfree(urb[j]->transfer_buffer); usb_free_urb(urb[j]); + urb[j] = NULL; } } @@ -485,11 +495,15 @@ static void usb_in_complete(struct urb *urb, struct pt_regs *regs) int len, count, status; if (unlikely(urb->status < 0)) { - if (urb->status != -ENOENT && urb->status != -ESHUTDOWN) { - WARN("urb status %d",urb->status); - } else { - DBG(1,"urb killed"); - return; // Give up + switch (urb->status) { + case -ENOENT: + case -ESHUTDOWN: + case -ECONNRESET: + DBG(1,"urb killed status %d", urb->status); + return; // Give up + default: + WARN("urb status %d",urb->status); + break; } } diff --git a/drivers/isdn/sc/init.c b/drivers/isdn/sc/init.c index 40b0df0..1ebed04 100644 --- a/drivers/isdn/sc/init.c +++ b/drivers/isdn/sc/init.c @@ -87,7 +87,7 @@ static int __init sc_init(void) */ for (i = 0 ; i < MAX_IO_REGS - 1 ; i++) { if(!request_region(io[b] + i * 0x400, 1, "sc test")) { - pr_debug("check_region for 0x%x failed\n", io[b] + i * 0x400); + pr_debug("request_region for 0x%x failed\n", io[b] + i * 0x400); io[b] = 0; break; } else @@ -181,7 +181,7 @@ static int __init sc_init(void) for (i = SRAM_MIN ; i < SRAM_MAX ; i += SRAM_PAGESIZE) { pr_debug("Checking RAM address 0x%x...\n", i); if(request_region(i, SRAM_PAGESIZE, "sc test")) { - pr_debug(" check_region succeeded\n"); + pr_debug(" request_region succeeded\n"); model = identify_board(i, io[b]); release_region(i, SRAM_PAGESIZE); if (model >= 0) { diff --git a/drivers/macintosh/smu.c b/drivers/macintosh/smu.c index fb53573..a85ac18 100644 --- a/drivers/macintosh/smu.c +++ b/drivers/macintosh/smu.c @@ -8,21 +8,15 @@ */ /* - * For now, this driver includes: - * - RTC get & set - * - reboot & shutdown commands - * all synchronous with IRQ disabled (ugh) - * * TODO: - * rework in a way the PMU driver works, that is asynchronous - * with a queue of commands. I'll do that as soon as I have an - * SMU based machine at hand. Some more cleanup is needed too, - * like maybe fitting it into a platform device, etc... - * Also check what's up with cache coherency, and if we really - * can't do better than flushing the cache, maybe build a table - * of command len/reply len like the PMU driver to only flush - * what is actually necessary. - * --BenH. + * - maybe add timeout to commands ? + * - blocking version of time functions + * - polling version of i2c commands (including timer that works with + * interrutps off) + * - maybe avoid some data copies with i2c by directly using the smu cmd + * buffer and a lower level internal interface + * - understand SMU -> CPU events and implement reception of them via + * the userland interface */ #include <linux/config.h> @@ -36,6 +30,11 @@ #include <linux/jiffies.h> #include <linux/interrupt.h> #include <linux/rtc.h> +#include <linux/completion.h> +#include <linux/miscdevice.h> +#include <linux/delay.h> +#include <linux/sysdev.h> +#include <linux/poll.h> #include <asm/byteorder.h> #include <asm/io.h> @@ -45,8 +44,13 @@ #include <asm/smu.h> #include <asm/sections.h> #include <asm/abs_addr.h> +#include <asm/uaccess.h> +#include <asm/of_device.h> + +#define VERSION "0.6" +#define AUTHOR "(c) 2005 Benjamin Herrenschmidt, IBM Corp." -#define DEBUG_SMU 1 +#undef DEBUG_SMU #ifdef DEBUG_SMU #define DPRINTK(fmt, args...) do { printk(KERN_DEBUG fmt , ##args); } while (0) @@ -57,20 +61,30 @@ /* * This is the command buffer passed to the SMU hardware */ +#define SMU_MAX_DATA 254 + struct smu_cmd_buf { u8 cmd; u8 length; - u8 data[0x0FFE]; + u8 data[SMU_MAX_DATA]; }; struct smu_device { spinlock_t lock; struct device_node *of_node; - int db_ack; /* doorbell ack GPIO */ - int db_req; /* doorbell req GPIO */ + struct of_device *of_dev; + int doorbell; /* doorbell gpio */ u32 __iomem *db_buf; /* doorbell buffer */ + int db_irq; + int msg; + int msg_irq; struct smu_cmd_buf *cmd_buf; /* command buffer virtual */ u32 cmd_buf_abs; /* command buffer absolute */ + struct list_head cmd_list; + struct smu_cmd *cmd_cur; /* pending command */ + struct list_head cmd_i2c_list; + struct smu_i2c_cmd *cmd_i2c_cur; /* pending i2c command */ + struct timer_list i2c_timer; }; /* @@ -79,113 +93,243 @@ struct smu_device { */ static struct smu_device *smu; + /* - * SMU low level communication stuff + * SMU driver low level stuff */ -static inline int smu_cmd_stat(struct smu_cmd_buf *cmd_buf, u8 cmd_ack) -{ - rmb(); - return cmd_buf->cmd == cmd_ack && cmd_buf->length != 0; -} -static inline u8 smu_save_ack_cmd(struct smu_cmd_buf *cmd_buf) +static void smu_start_cmd(void) { - return (~cmd_buf->cmd) & 0xff; -} + unsigned long faddr, fend; + struct smu_cmd *cmd; -static void smu_send_cmd(struct smu_device *dev) -{ - /* SMU command buf is currently cacheable, we need a physical - * address. This isn't exactly a DMA mapping here, I suspect + if (list_empty(&smu->cmd_list)) + return; + + /* Fetch first command in queue */ + cmd = list_entry(smu->cmd_list.next, struct smu_cmd, link); + smu->cmd_cur = cmd; + list_del(&cmd->link); + + DPRINTK("SMU: starting cmd %x, %d bytes data\n", cmd->cmd, + cmd->data_len); + DPRINTK("SMU: data buffer: %02x %02x %02x %02x ...\n", + ((u8 *)cmd->data_buf)[0], ((u8 *)cmd->data_buf)[1], + ((u8 *)cmd->data_buf)[2], ((u8 *)cmd->data_buf)[3]); + + /* Fill the SMU command buffer */ + smu->cmd_buf->cmd = cmd->cmd; + smu->cmd_buf->length = cmd->data_len; + memcpy(smu->cmd_buf->data, cmd->data_buf, cmd->data_len); + + /* Flush command and data to RAM */ + faddr = (unsigned long)smu->cmd_buf; + fend = faddr + smu->cmd_buf->length + 2; + flush_inval_dcache_range(faddr, fend); + + /* This isn't exactly a DMA mapping here, I suspect * the SMU is actually communicating with us via i2c to the * northbridge or the CPU to access RAM. */ - writel(dev->cmd_buf_abs, dev->db_buf); + writel(smu->cmd_buf_abs, smu->db_buf); /* Ring the SMU doorbell */ - pmac_do_feature_call(PMAC_FTR_WRITE_GPIO, NULL, dev->db_req, 4); - pmac_do_feature_call(PMAC_FTR_READ_GPIO, NULL, dev->db_req, 4); + pmac_do_feature_call(PMAC_FTR_WRITE_GPIO, NULL, smu->doorbell, 4); } -static int smu_cmd_done(struct smu_device *dev) + +static irqreturn_t smu_db_intr(int irq, void *arg, struct pt_regs *regs) { - unsigned long wait = 0; - int gpio; + unsigned long flags; + struct smu_cmd *cmd; + void (*done)(struct smu_cmd *cmd, void *misc) = NULL; + void *misc = NULL; + u8 gpio; + int rc = 0; - /* Check the SMU doorbell */ - do { - gpio = pmac_do_feature_call(PMAC_FTR_READ_GPIO, - NULL, dev->db_ack); - if ((gpio & 7) == 7) - return 0; - udelay(100); - } while(++wait < 10000); + /* SMU completed the command, well, we hope, let's make sure + * of it + */ + spin_lock_irqsave(&smu->lock, flags); - printk(KERN_ERR "SMU timeout !\n"); - return -ENXIO; + gpio = pmac_do_feature_call(PMAC_FTR_READ_GPIO, NULL, smu->doorbell); + if ((gpio & 7) != 7) + return IRQ_HANDLED; + + cmd = smu->cmd_cur; + smu->cmd_cur = NULL; + if (cmd == NULL) + goto bail; + + if (rc == 0) { + unsigned long faddr; + int reply_len; + u8 ack; + + /* CPU might have brought back the cache line, so we need + * to flush again before peeking at the SMU response. We + * flush the entire buffer for now as we haven't read the + * reply lenght (it's only 2 cache lines anyway) + */ + faddr = (unsigned long)smu->cmd_buf; + flush_inval_dcache_range(faddr, faddr + 256); + + /* Now check ack */ + ack = (~cmd->cmd) & 0xff; + if (ack != smu->cmd_buf->cmd) { + DPRINTK("SMU: incorrect ack, want %x got %x\n", + ack, smu->cmd_buf->cmd); + rc = -EIO; + } + reply_len = rc == 0 ? smu->cmd_buf->length : 0; + DPRINTK("SMU: reply len: %d\n", reply_len); + if (reply_len > cmd->reply_len) { + printk(KERN_WARNING "SMU: reply buffer too small," + "got %d bytes for a %d bytes buffer\n", + reply_len, cmd->reply_len); + reply_len = cmd->reply_len; + } + cmd->reply_len = reply_len; + if (cmd->reply_buf && reply_len) + memcpy(cmd->reply_buf, smu->cmd_buf->data, reply_len); + } + + /* Now complete the command. Write status last in order as we lost + * ownership of the command structure as soon as it's no longer -1 + */ + done = cmd->done; + misc = cmd->misc; + mb(); + cmd->status = rc; + bail: + /* Start next command if any */ + smu_start_cmd(); + spin_unlock_irqrestore(&smu->lock, flags); + + /* Call command completion handler if any */ + if (done) + done(cmd, misc); + + /* It's an edge interrupt, nothing to do */ + return IRQ_HANDLED; } -static int smu_do_cmd(struct smu_device *dev) + +static irqreturn_t smu_msg_intr(int irq, void *arg, struct pt_regs *regs) { - int rc; - u8 cmd_ack; + /* I don't quite know what to do with this one, we seem to never + * receive it, so I suspect we have to arm it someway in the SMU + * to start getting events that way. + */ + + printk(KERN_INFO "SMU: message interrupt !\n"); - DPRINTK("SMU do_cmd %02x len=%d %02x\n", - dev->cmd_buf->cmd, dev->cmd_buf->length, - dev->cmd_buf->data[0]); + /* It's an edge interrupt, nothing to do */ + return IRQ_HANDLED; +} - cmd_ack = smu_save_ack_cmd(dev->cmd_buf); - /* Clear cmd_buf cache lines */ - flush_inval_dcache_range((unsigned long)dev->cmd_buf, - ((unsigned long)dev->cmd_buf) + - sizeof(struct smu_cmd_buf)); - smu_send_cmd(dev); - rc = smu_cmd_done(dev); - if (rc == 0) - rc = smu_cmd_stat(dev->cmd_buf, cmd_ack) ? 0 : -1; +/* + * Queued command management. + * + */ - DPRINTK("SMU do_cmd %02x len=%d %02x => %d (%02x)\n", - dev->cmd_buf->cmd, dev->cmd_buf->length, - dev->cmd_buf->data[0], rc, cmd_ack); +int smu_queue_cmd(struct smu_cmd *cmd) +{ + unsigned long flags; - return rc; + if (smu == NULL) + return -ENODEV; + if (cmd->data_len > SMU_MAX_DATA || + cmd->reply_len > SMU_MAX_DATA) + return -EINVAL; + + cmd->status = 1; + spin_lock_irqsave(&smu->lock, flags); + list_add_tail(&cmd->link, &smu->cmd_list); + if (smu->cmd_cur == NULL) + smu_start_cmd(); + spin_unlock_irqrestore(&smu->lock, flags); + + return 0; } +EXPORT_SYMBOL(smu_queue_cmd); -/* RTC low level commands */ -static inline int bcd2hex (int n) + +int smu_queue_simple(struct smu_simple_cmd *scmd, u8 command, + unsigned int data_len, + void (*done)(struct smu_cmd *cmd, void *misc), + void *misc, ...) { - return (((n & 0xf0) >> 4) * 10) + (n & 0xf); + struct smu_cmd *cmd = &scmd->cmd; + va_list list; + int i; + + if (data_len > sizeof(scmd->buffer)) + return -EINVAL; + + memset(scmd, 0, sizeof(*scmd)); + cmd->cmd = command; + cmd->data_len = data_len; + cmd->data_buf = scmd->buffer; + cmd->reply_len = sizeof(scmd->buffer); + cmd->reply_buf = scmd->buffer; + cmd->done = done; + cmd->misc = misc; + + va_start(list, misc); + for (i = 0; i < data_len; ++i) + scmd->buffer[i] = (u8)va_arg(list, int); + va_end(list); + + return smu_queue_cmd(cmd); } +EXPORT_SYMBOL(smu_queue_simple); -static inline int hex2bcd (int n) + +void smu_poll(void) { - return ((n / 10) << 4) + (n % 10); + u8 gpio; + + if (smu == NULL) + return; + + gpio = pmac_do_feature_call(PMAC_FTR_READ_GPIO, NULL, smu->doorbell); + if ((gpio & 7) == 7) + smu_db_intr(smu->db_irq, smu, NULL); } +EXPORT_SYMBOL(smu_poll); + -#if 0 -static inline void smu_fill_set_pwrup_timer_cmd(struct smu_cmd_buf *cmd_buf) +void smu_done_complete(struct smu_cmd *cmd, void *misc) { - cmd_buf->cmd = 0x8e; - cmd_buf->length = 8; - cmd_buf->data[0] = 0x00; - memset(cmd_buf->data + 1, 0, 7); + struct completion *comp = misc; + + complete(comp); } +EXPORT_SYMBOL(smu_done_complete); + -static inline void smu_fill_get_pwrup_timer_cmd(struct smu_cmd_buf *cmd_buf) +void smu_spinwait_cmd(struct smu_cmd *cmd) { - cmd_buf->cmd = 0x8e; - cmd_buf->length = 1; - cmd_buf->data[0] = 0x01; + while(cmd->status == 1) + smu_poll(); +} +EXPORT_SYMBOL(smu_spinwait_cmd); + + +/* RTC low level commands */ +static inline int bcd2hex (int n) +{ + return (((n & 0xf0) >> 4) * 10) + (n & 0xf); } -static inline void smu_fill_dis_pwrup_timer_cmd(struct smu_cmd_buf *cmd_buf) + +static inline int hex2bcd (int n) { - cmd_buf->cmd = 0x8e; - cmd_buf->length = 1; - cmd_buf->data[0] = 0x02; + return ((n / 10) << 4) + (n % 10); } -#endif + static inline void smu_fill_set_rtc_cmd(struct smu_cmd_buf *cmd_buf, struct rtc_time *time) @@ -202,100 +346,96 @@ static inline void smu_fill_set_rtc_cmd(struct smu_cmd_buf *cmd_buf, cmd_buf->data[7] = hex2bcd(time->tm_year - 100); } -static inline void smu_fill_get_rtc_cmd(struct smu_cmd_buf *cmd_buf) -{ - cmd_buf->cmd = 0x8e; - cmd_buf->length = 1; - cmd_buf->data[0] = 0x81; -} -static void smu_parse_get_rtc_reply(struct smu_cmd_buf *cmd_buf, - struct rtc_time *time) +int smu_get_rtc_time(struct rtc_time *time, int spinwait) { - time->tm_sec = bcd2hex(cmd_buf->data[0]); - time->tm_min = bcd2hex(cmd_buf->data[1]); - time->tm_hour = bcd2hex(cmd_buf->data[2]); - time->tm_wday = bcd2hex(cmd_buf->data[3]); - time->tm_mday = bcd2hex(cmd_buf->data[4]); - time->tm_mon = bcd2hex(cmd_buf->data[5]) - 1; - time->tm_year = bcd2hex(cmd_buf->data[6]) + 100; -} - -int smu_get_rtc_time(struct rtc_time *time) -{ - unsigned long flags; + struct smu_simple_cmd cmd; int rc; if (smu == NULL) return -ENODEV; memset(time, 0, sizeof(struct rtc_time)); - spin_lock_irqsave(&smu->lock, flags); - smu_fill_get_rtc_cmd(smu->cmd_buf); - rc = smu_do_cmd(smu); - if (rc == 0) - smu_parse_get_rtc_reply(smu->cmd_buf, time); - spin_unlock_irqrestore(&smu->lock, flags); + rc = smu_queue_simple(&cmd, SMU_CMD_RTC_COMMAND, 1, NULL, NULL, + SMU_CMD_RTC_GET_DATETIME); + if (rc) + return rc; + smu_spinwait_simple(&cmd); - return rc; + time->tm_sec = bcd2hex(cmd.buffer[0]); + time->tm_min = bcd2hex(cmd.buffer[1]); + time->tm_hour = bcd2hex(cmd.buffer[2]); + time->tm_wday = bcd2hex(cmd.buffer[3]); + time->tm_mday = bcd2hex(cmd.buffer[4]); + time->tm_mon = bcd2hex(cmd.buffer[5]) - 1; + time->tm_year = bcd2hex(cmd.buffer[6]) + 100; + + return 0; } -int smu_set_rtc_time(struct rtc_time *time) + +int smu_set_rtc_time(struct rtc_time *time, int spinwait) { - unsigned long flags; + struct smu_simple_cmd cmd; int rc; if (smu == NULL) return -ENODEV; - spin_lock_irqsave(&smu->lock, flags); - smu_fill_set_rtc_cmd(smu->cmd_buf, time); - rc = smu_do_cmd(smu); - spin_unlock_irqrestore(&smu->lock, flags); + rc = smu_queue_simple(&cmd, SMU_CMD_RTC_COMMAND, 8, NULL, NULL, + SMU_CMD_RTC_SET_DATETIME, + hex2bcd(time->tm_sec), + hex2bcd(time->tm_min), + hex2bcd(time->tm_hour), + time->tm_wday, + hex2bcd(time->tm_mday), + hex2bcd(time->tm_mon) + 1, + hex2bcd(time->tm_year - 100)); + if (rc) + return rc; + smu_spinwait_simple(&cmd); - return rc; + return 0; } + void smu_shutdown(void) { - const unsigned char *command = "SHUTDOWN"; - unsigned long flags; + struct smu_simple_cmd cmd; if (smu == NULL) return; - spin_lock_irqsave(&smu->lock, flags); - smu->cmd_buf->cmd = 0xaa; - smu->cmd_buf->length = strlen(command); - strcpy(smu->cmd_buf->data, command); - smu_do_cmd(smu); + if (smu_queue_simple(&cmd, SMU_CMD_POWER_COMMAND, 9, NULL, NULL, + 'S', 'H', 'U', 'T', 'D', 'O', 'W', 'N', 0)) + return; + smu_spinwait_simple(&cmd); for (;;) ; - spin_unlock_irqrestore(&smu->lock, flags); } + void smu_restart(void) { - const unsigned char *command = "RESTART"; - unsigned long flags; + struct smu_simple_cmd cmd; if (smu == NULL) return; - spin_lock_irqsave(&smu->lock, flags); - smu->cmd_buf->cmd = 0xaa; - smu->cmd_buf->length = strlen(command); - strcpy(smu->cmd_buf->data, command); - smu_do_cmd(smu); + if (smu_queue_simple(&cmd, SMU_CMD_POWER_COMMAND, 8, NULL, NULL, + 'R', 'E', 'S', 'T', 'A', 'R', 'T', 0)) + return; + smu_spinwait_simple(&cmd); for (;;) ; - spin_unlock_irqrestore(&smu->lock, flags); } + int smu_present(void) { return smu != NULL; } +EXPORT_SYMBOL(smu_present); int smu_init (void) @@ -307,6 +447,8 @@ int smu_init (void) if (np == NULL) return -ENODEV; + printk(KERN_INFO "SMU driver %s %s\n", VERSION, AUTHOR); + if (smu_cmdbuf_abs == 0) { printk(KERN_ERR "SMU: Command buffer not allocated !\n"); return -EINVAL; @@ -318,7 +460,13 @@ int smu_init (void) memset(smu, 0, sizeof(*smu)); spin_lock_init(&smu->lock); + INIT_LIST_HEAD(&smu->cmd_list); + INIT_LIST_HEAD(&smu->cmd_i2c_list); smu->of_node = np; + smu->db_irq = NO_IRQ; + smu->msg_irq = NO_IRQ; + init_timer(&smu->i2c_timer); + /* smu_cmdbuf_abs is in the low 2G of RAM, can be converted to a * 32 bits value safely */ @@ -331,8 +479,8 @@ int smu_init (void) goto fail; } data = (u32 *)get_property(np, "reg", NULL); - of_node_put(np); if (data == NULL) { + of_node_put(np); printk(KERN_ERR "SMU: Can't find doorbell GPIO address !\n"); goto fail; } @@ -341,8 +489,31 @@ int smu_init (void) * and ack. GPIOs are at 0x50, best would be to find that out * in the device-tree though. */ - smu->db_req = 0x50 + *data; - smu->db_ack = 0x50 + *data; + smu->doorbell = *data; + if (smu->doorbell < 0x50) + smu->doorbell += 0x50; + if (np->n_intrs > 0) + smu->db_irq = np->intrs[0].line; + + of_node_put(np); + + /* Now look for the smu-interrupt GPIO */ + do { + np = of_find_node_by_name(NULL, "smu-interrupt"); + if (np == NULL) + break; + data = (u32 *)get_property(np, "reg", NULL); + if (data == NULL) { + of_node_put(np); + break; + } + smu->msg = *data; + if (smu->msg < 0x50) + smu->msg += 0x50; + if (np->n_intrs > 0) + smu->msg_irq = np->intrs[0].line; + of_node_put(np); + } while(0); /* Doorbell buffer is currently hard-coded, I didn't find a proper * device-tree entry giving the address. Best would probably to use @@ -362,3 +533,584 @@ int smu_init (void) return -ENXIO; } + + +static int smu_late_init(void) +{ + if (!smu) + return 0; + + /* + * Try to request the interrupts + */ + + if (smu->db_irq != NO_IRQ) { + if (request_irq(smu->db_irq, smu_db_intr, + SA_SHIRQ, "SMU doorbell", smu) < 0) { + printk(KERN_WARNING "SMU: can't " + "request interrupt %d\n", + smu->db_irq); + smu->db_irq = NO_IRQ; + } + } + + if (smu->msg_irq != NO_IRQ) { + if (request_irq(smu->msg_irq, smu_msg_intr, + SA_SHIRQ, "SMU message", smu) < 0) { + printk(KERN_WARNING "SMU: can't " + "request interrupt %d\n", + smu->msg_irq); + smu->msg_irq = NO_IRQ; + } + } + + return 0; +} +arch_initcall(smu_late_init); + +/* + * sysfs visibility + */ + +static void smu_expose_childs(void *unused) +{ + struct device_node *np; + + for (np = NULL; (np = of_get_next_child(smu->of_node, np)) != NULL;) { + if (device_is_compatible(np, "smu-i2c")) { + char name[32]; + u32 *reg = (u32 *)get_property(np, "reg", NULL); + + if (reg == NULL) + continue; + sprintf(name, "smu-i2c-%02x", *reg); + of_platform_device_create(np, name, &smu->of_dev->dev); + } + } + +} + +static DECLARE_WORK(smu_expose_childs_work, smu_expose_childs, NULL); + +static int smu_platform_probe(struct of_device* dev, + const struct of_device_id *match) +{ + if (!smu) + return -ENODEV; + smu->of_dev = dev; + + /* + * Ok, we are matched, now expose all i2c busses. We have to defer + * that unfortunately or it would deadlock inside the device model + */ + schedule_work(&smu_expose_childs_work); + + return 0; +} + +static struct of_device_id smu_platform_match[] = +{ + { + .type = "smu", + }, + {}, +}; + +static struct of_platform_driver smu_of_platform_driver = +{ + .name = "smu", + .match_table = smu_platform_match, + .probe = smu_platform_probe, +}; + +static int __init smu_init_sysfs(void) +{ + int rc; + + /* + * Due to sysfs bogosity, a sysdev is not a real device, so + * we should in fact create both if we want sysdev semantics + * for power management. + * For now, we don't power manage machines with an SMU chip, + * I'm a bit too far from figuring out how that works with those + * new chipsets, but that will come back and bite us + */ + rc = of_register_driver(&smu_of_platform_driver); + return 0; +} + +device_initcall(smu_init_sysfs); + +struct of_device *smu_get_ofdev(void) +{ + if (!smu) + return NULL; + return smu->of_dev; +} + +EXPORT_SYMBOL_GPL(smu_get_ofdev); + +/* + * i2c interface + */ + +static void smu_i2c_complete_command(struct smu_i2c_cmd *cmd, int fail) +{ + void (*done)(struct smu_i2c_cmd *cmd, void *misc) = cmd->done; + void *misc = cmd->misc; + unsigned long flags; + + /* Check for read case */ + if (!fail && cmd->read) { + if (cmd->pdata[0] < 1) + fail = 1; + else + memcpy(cmd->info.data, &cmd->pdata[1], + cmd->info.datalen); + } + + DPRINTK("SMU: completing, success: %d\n", !fail); + + /* Update status and mark no pending i2c command with lock + * held so nobody comes in while we dequeue an eventual + * pending next i2c command + */ + spin_lock_irqsave(&smu->lock, flags); + smu->cmd_i2c_cur = NULL; + wmb(); + cmd->status = fail ? -EIO : 0; + + /* Is there another i2c command waiting ? */ + if (!list_empty(&smu->cmd_i2c_list)) { + struct smu_i2c_cmd *newcmd; + + /* Fetch it, new current, remove from list */ + newcmd = list_entry(smu->cmd_i2c_list.next, + struct smu_i2c_cmd, link); + smu->cmd_i2c_cur = newcmd; + list_del(&cmd->link); + + /* Queue with low level smu */ + list_add_tail(&cmd->scmd.link, &smu->cmd_list); + if (smu->cmd_cur == NULL) + smu_start_cmd(); + } + spin_unlock_irqrestore(&smu->lock, flags); + + /* Call command completion handler if any */ + if (done) + done(cmd, misc); + +} + + +static void smu_i2c_retry(unsigned long data) +{ + struct smu_i2c_cmd *cmd = (struct smu_i2c_cmd *)data; + + DPRINTK("SMU: i2c failure, requeuing...\n"); + + /* requeue command simply by resetting reply_len */ + cmd->pdata[0] = 0xff; + cmd->scmd.reply_len = 0x10; + smu_queue_cmd(&cmd->scmd); +} + + +static void smu_i2c_low_completion(struct smu_cmd *scmd, void *misc) +{ + struct smu_i2c_cmd *cmd = misc; + int fail = 0; + + DPRINTK("SMU: i2c compl. stage=%d status=%x pdata[0]=%x rlen: %x\n", + cmd->stage, scmd->status, cmd->pdata[0], scmd->reply_len); + + /* Check for possible status */ + if (scmd->status < 0) + fail = 1; + else if (cmd->read) { + if (cmd->stage == 0) + fail = cmd->pdata[0] != 0; + else + fail = cmd->pdata[0] >= 0x80; + } else { + fail = cmd->pdata[0] != 0; + } + + /* Handle failures by requeuing command, after 5ms interval + */ + if (fail && --cmd->retries > 0) { + DPRINTK("SMU: i2c failure, starting timer...\n"); + smu->i2c_timer.function = smu_i2c_retry; + smu->i2c_timer.data = (unsigned long)cmd; + smu->i2c_timer.expires = jiffies + msecs_to_jiffies(5); + add_timer(&smu->i2c_timer); + return; + } + + /* If failure or stage 1, command is complete */ + if (fail || cmd->stage != 0) { + smu_i2c_complete_command(cmd, fail); + return; + } + + DPRINTK("SMU: going to stage 1\n"); + + /* Ok, initial command complete, now poll status */ + scmd->reply_buf = cmd->pdata; + scmd->reply_len = 0x10; + scmd->data_buf = cmd->pdata; + scmd->data_len = 1; + cmd->pdata[0] = 0; + cmd->stage = 1; + cmd->retries = 20; + smu_queue_cmd(scmd); +} + + +int smu_queue_i2c(struct smu_i2c_cmd *cmd) +{ + unsigned long flags; + + if (smu == NULL) + return -ENODEV; + + /* Fill most fields of scmd */ + cmd->scmd.cmd = SMU_CMD_I2C_COMMAND; + cmd->scmd.done = smu_i2c_low_completion; + cmd->scmd.misc = cmd; + cmd->scmd.reply_buf = cmd->pdata; + cmd->scmd.reply_len = 0x10; + cmd->scmd.data_buf = (u8 *)(char *)&cmd->info; + cmd->scmd.status = 1; + cmd->stage = 0; + cmd->pdata[0] = 0xff; + cmd->retries = 20; + cmd->status = 1; + + /* Check transfer type, sanitize some "info" fields + * based on transfer type and do more checking + */ + cmd->info.caddr = cmd->info.devaddr; + cmd->read = cmd->info.devaddr & 0x01; + switch(cmd->info.type) { + case SMU_I2C_TRANSFER_SIMPLE: + memset(&cmd->info.sublen, 0, 4); + break; + case SMU_I2C_TRANSFER_COMBINED: + cmd->info.devaddr &= 0xfe; + case SMU_I2C_TRANSFER_STDSUB: + if (cmd->info.sublen > 3) + return -EINVAL; + break; + default: + return -EINVAL; + } + + /* Finish setting up command based on transfer direction + */ + if (cmd->read) { + if (cmd->info.datalen > SMU_I2C_READ_MAX) + return -EINVAL; + memset(cmd->info.data, 0xff, cmd->info.datalen); + cmd->scmd.data_len = 9; + } else { + if (cmd->info.datalen > SMU_I2C_WRITE_MAX) + return -EINVAL; + cmd->scmd.data_len = 9 + cmd->info.datalen; + } + + DPRINTK("SMU: i2c enqueuing command\n"); + DPRINTK("SMU: %s, len=%d bus=%x addr=%x sub0=%x type=%x\n", + cmd->read ? "read" : "write", cmd->info.datalen, + cmd->info.bus, cmd->info.caddr, + cmd->info.subaddr[0], cmd->info.type); + + + /* Enqueue command in i2c list, and if empty, enqueue also in + * main command list + */ + spin_lock_irqsave(&smu->lock, flags); + if (smu->cmd_i2c_cur == NULL) { + smu->cmd_i2c_cur = cmd; + list_add_tail(&cmd->scmd.link, &smu->cmd_list); + if (smu->cmd_cur == NULL) + smu_start_cmd(); + } else + list_add_tail(&cmd->link, &smu->cmd_i2c_list); + spin_unlock_irqrestore(&smu->lock, flags); + + return 0; +} + + + +/* + * Userland driver interface + */ + + +static LIST_HEAD(smu_clist); +static DEFINE_SPINLOCK(smu_clist_lock); + +enum smu_file_mode { + smu_file_commands, + smu_file_events, + smu_file_closing +}; + +struct smu_private +{ + struct list_head list; + enum smu_file_mode mode; + int busy; + struct smu_cmd cmd; + spinlock_t lock; + wait_queue_head_t wait; + u8 buffer[SMU_MAX_DATA]; +}; + + +static int smu_open(struct inode *inode, struct file *file) +{ + struct smu_private *pp; + unsigned long flags; + + pp = kmalloc(sizeof(struct smu_private), GFP_KERNEL); + if (pp == 0) + return -ENOMEM; + memset(pp, 0, sizeof(struct smu_private)); + spin_lock_init(&pp->lock); + pp->mode = smu_file_commands; + init_waitqueue_head(&pp->wait); + + spin_lock_irqsave(&smu_clist_lock, flags); + list_add(&pp->list, &smu_clist); + spin_unlock_irqrestore(&smu_clist_lock, flags); + file->private_data = pp; + + return 0; +} + + +static void smu_user_cmd_done(struct smu_cmd *cmd, void *misc) +{ + struct smu_private *pp = misc; + + wake_up_all(&pp->wait); +} + + +static ssize_t smu_write(struct file *file, const char __user *buf, + size_t count, loff_t *ppos) +{ + struct smu_private *pp = file->private_data; + unsigned long flags; + struct smu_user_cmd_hdr hdr; + int rc = 0; + + if (pp->busy) + return -EBUSY; + else if (copy_from_user(&hdr, buf, sizeof(hdr))) + return -EFAULT; + else if (hdr.cmdtype == SMU_CMDTYPE_WANTS_EVENTS) { + pp->mode = smu_file_events; + return 0; + } else if (hdr.cmdtype != SMU_CMDTYPE_SMU) + return -EINVAL; + else if (pp->mode != smu_file_commands) + return -EBADFD; + else if (hdr.data_len > SMU_MAX_DATA) + return -EINVAL; + + spin_lock_irqsave(&pp->lock, flags); + if (pp->busy) { + spin_unlock_irqrestore(&pp->lock, flags); + return -EBUSY; + } + pp->busy = 1; + pp->cmd.status = 1; + spin_unlock_irqrestore(&pp->lock, flags); + + if (copy_from_user(pp->buffer, buf + sizeof(hdr), hdr.data_len)) { + pp->busy = 0; + return -EFAULT; + } + + pp->cmd.cmd = hdr.cmd; + pp->cmd.data_len = hdr.data_len; + pp->cmd.reply_len = SMU_MAX_DATA; + pp->cmd.data_buf = pp->buffer; + pp->cmd.reply_buf = pp->buffer; + pp->cmd.done = smu_user_cmd_done; + pp->cmd.misc = pp; + rc = smu_queue_cmd(&pp->cmd); + if (rc < 0) + return rc; + return count; +} + + +static ssize_t smu_read_command(struct file *file, struct smu_private *pp, + char __user *buf, size_t count) +{ + DECLARE_WAITQUEUE(wait, current); + struct smu_user_reply_hdr hdr; + unsigned long flags; + int size, rc = 0; + + if (!pp->busy) + return 0; + if (count < sizeof(struct smu_user_reply_hdr)) + return -EOVERFLOW; + spin_lock_irqsave(&pp->lock, flags); + if (pp->cmd.status == 1) { + if (file->f_flags & O_NONBLOCK) + return -EAGAIN; + add_wait_queue(&pp->wait, &wait); + for (;;) { + set_current_state(TASK_INTERRUPTIBLE); + rc = 0; + if (pp->cmd.status != 1) + break; + rc = -ERESTARTSYS; + if (signal_pending(current)) + break; + spin_unlock_irqrestore(&pp->lock, flags); + schedule(); + spin_lock_irqsave(&pp->lock, flags); + } + set_current_state(TASK_RUNNING); + remove_wait_queue(&pp->wait, &wait); + } + spin_unlock_irqrestore(&pp->lock, flags); + if (rc) + return rc; + if (pp->cmd.status != 0) + pp->cmd.reply_len = 0; + size = sizeof(hdr) + pp->cmd.reply_len; + if (count < size) + size = count; + rc = size; + hdr.status = pp->cmd.status; + hdr.reply_len = pp->cmd.reply_len; + if (copy_to_user(buf, &hdr, sizeof(hdr))) + return -EFAULT; + size -= sizeof(hdr); + if (size && copy_to_user(buf + sizeof(hdr), pp->buffer, size)) + return -EFAULT; + pp->busy = 0; + + return rc; +} + + +static ssize_t smu_read_events(struct file *file, struct smu_private *pp, + char __user *buf, size_t count) +{ + /* Not implemented */ + msleep_interruptible(1000); + return 0; +} + + +static ssize_t smu_read(struct file *file, char __user *buf, + size_t count, loff_t *ppos) +{ + struct smu_private *pp = file->private_data; + + if (pp->mode == smu_file_commands) + return smu_read_command(file, pp, buf, count); + if (pp->mode == smu_file_events) + return smu_read_events(file, pp, buf, count); + + return -EBADFD; +} + +static unsigned int smu_fpoll(struct file *file, poll_table *wait) +{ + struct smu_private *pp = file->private_data; + unsigned int mask = 0; + unsigned long flags; + + if (pp == 0) + return 0; + + if (pp->mode == smu_file_commands) { + poll_wait(file, &pp->wait, wait); + + spin_lock_irqsave(&pp->lock, flags); + if (pp->busy && pp->cmd.status != 1) + mask |= POLLIN; + spin_unlock_irqrestore(&pp->lock, flags); + } if (pp->mode == smu_file_events) { + /* Not yet implemented */ + } + return mask; +} + +static int smu_release(struct inode *inode, struct file *file) +{ + struct smu_private *pp = file->private_data; + unsigned long flags; + unsigned int busy; + + if (pp == 0) + return 0; + + file->private_data = NULL; + + /* Mark file as closing to avoid races with new request */ + spin_lock_irqsave(&pp->lock, flags); + pp->mode = smu_file_closing; + busy = pp->busy; + + /* Wait for any pending request to complete */ + if (busy && pp->cmd.status == 1) { + DECLARE_WAITQUEUE(wait, current); + + add_wait_queue(&pp->wait, &wait); + for (;;) { + set_current_state(TASK_UNINTERRUPTIBLE); + if (pp->cmd.status != 1) + break; + spin_lock_irqsave(&pp->lock, flags); + schedule(); + spin_unlock_irqrestore(&pp->lock, flags); + } + set_current_state(TASK_RUNNING); + remove_wait_queue(&pp->wait, &wait); + } + spin_unlock_irqrestore(&pp->lock, flags); + + spin_lock_irqsave(&smu_clist_lock, flags); + list_del(&pp->list); + spin_unlock_irqrestore(&smu_clist_lock, flags); + kfree(pp); + + return 0; +} + + +static struct file_operations smu_device_fops __pmacdata = { + .llseek = no_llseek, + .read = smu_read, + .write = smu_write, + .poll = smu_fpoll, + .open = smu_open, + .release = smu_release, +}; + +static struct miscdevice pmu_device __pmacdata = { + MISC_DYNAMIC_MINOR, "smu", &smu_device_fops +}; + +static int smu_device_init(void) +{ + if (!smu) + return -ENODEV; + if (misc_register(&pmu_device) < 0) + printk(KERN_ERR "via-pmu: cannot register misc device.\n"); + return 0; +} +device_initcall(smu_device_init); diff --git a/drivers/macintosh/therm_adt746x.c b/drivers/macintosh/therm_adt746x.c index c9ca111..f386966 100644 --- a/drivers/macintosh/therm_adt746x.c +++ b/drivers/macintosh/therm_adt746x.c @@ -599,7 +599,7 @@ thermostat_init(void) sensor_location[2] = "?"; } - of_dev = of_platform_device_create(np, "temperatures"); + of_dev = of_platform_device_create(np, "temperatures", NULL); if (of_dev == NULL) { printk(KERN_ERR "Can't register temperatures device !\n"); diff --git a/drivers/macintosh/therm_pm72.c b/drivers/macintosh/therm_pm72.c index 703e3197..cc507ce 100644 --- a/drivers/macintosh/therm_pm72.c +++ b/drivers/macintosh/therm_pm72.c @@ -2051,7 +2051,7 @@ static int __init therm_pm72_init(void) return -ENODEV; } } - of_dev = of_platform_device_create(np, "temperature"); + of_dev = of_platform_device_create(np, "temperature", NULL); if (of_dev == NULL) { printk(KERN_ERR "Can't register FCU platform device !\n"); return -ENODEV; diff --git a/drivers/macintosh/therm_windtunnel.c b/drivers/macintosh/therm_windtunnel.c index cbb72eb..6aaa1df 100644 --- a/drivers/macintosh/therm_windtunnel.c +++ b/drivers/macintosh/therm_windtunnel.c @@ -504,7 +504,7 @@ g4fan_init( void ) } if( !(np=of_find_node_by_name(NULL, "fan")) ) return -ENODEV; - x.of_dev = of_platform_device_create( np, "temperature" ); + x.of_dev = of_platform_device_create(np, "temperature", NULL); of_node_put( np ); if( !x.of_dev ) { diff --git a/drivers/md/raid6.h b/drivers/md/raid6.h index f80ee63..31cbee7 100644 --- a/drivers/md/raid6.h +++ b/drivers/md/raid6.h @@ -69,9 +69,13 @@ extern const char raid6_empty_zero_page[PAGE_SIZE]; #define __init #define __exit #define __attribute_const__ __attribute__((const)) +#define noinline __attribute__((noinline)) #define preempt_enable() #define preempt_disable() +#define cpu_has_feature(x) 1 +#define enable_kernel_altivec() +#define disable_kernel_altivec() #endif /* __KERNEL__ */ diff --git a/drivers/md/raid6algos.c b/drivers/md/raid6algos.c index acf386f..51c63c0 100644 --- a/drivers/md/raid6algos.c +++ b/drivers/md/raid6algos.c @@ -19,6 +19,7 @@ #include "raid6.h" #ifndef __KERNEL__ #include <sys/mman.h> +#include <stdio.h> #endif struct raid6_calls raid6_call; diff --git a/drivers/md/raid6altivec.uc b/drivers/md/raid6altivec.uc index 1de8f03..b9afd35 100644 --- a/drivers/md/raid6altivec.uc +++ b/drivers/md/raid6altivec.uc @@ -27,16 +27,20 @@ #ifdef CONFIG_ALTIVEC #include <altivec.h> -#include <asm/system.h> -#include <asm/cputable.h> +#ifdef __KERNEL__ +# include <asm/system.h> +# include <asm/cputable.h> +#endif /* - * This is the C data type to use + * This is the C data type to use. We use a vector of + * signed char so vec_cmpgt() will generate the right + * instruction. */ -typedef vector unsigned char unative_t; +typedef vector signed char unative_t; -#define NBYTES(x) ((vector unsigned char) {x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x}) +#define NBYTES(x) ((vector signed char) {x,x,x,x, x,x,x,x, x,x,x,x, x,x,x,x}) #define NSIZE sizeof(unative_t) /* @@ -108,7 +112,11 @@ int raid6_have_altivec(void); int raid6_have_altivec(void) { /* This assumes either all CPUs have Altivec or none does */ +# ifdef __KERNEL__ return cpu_has_feature(CPU_FTR_ALTIVEC); +# else + return 1; +# endif } #endif diff --git a/drivers/md/raid6test/Makefile b/drivers/md/raid6test/Makefile index 5578067..78e0396 100644 --- a/drivers/md/raid6test/Makefile +++ b/drivers/md/raid6test/Makefile @@ -8,6 +8,8 @@ OPTFLAGS = -O2 # Adjust as desired CFLAGS = -I.. -g $(OPTFLAGS) LD = ld PERL = perl +AR = ar +RANLIB = ranlib .c.o: $(CC) $(CFLAGS) -c -o $@ $< @@ -18,18 +20,33 @@ PERL = perl %.uc: ../%.uc cp -f $< $@ -all: raid6.o raid6test +all: raid6.a raid6test -raid6.o: raid6int1.o raid6int2.o raid6int4.o raid6int8.o raid6int16.o \ +raid6.a: raid6int1.o raid6int2.o raid6int4.o raid6int8.o raid6int16.o \ raid6int32.o \ raid6mmx.o raid6sse1.o raid6sse2.o \ + raid6altivec1.o raid6altivec2.o raid6altivec4.o raid6altivec8.o \ raid6recov.o raid6algos.o \ raid6tables.o - $(LD) -r -o $@ $^ + rm -f $@ + $(AR) cq $@ $^ + $(RANLIB) $@ -raid6test: raid6.o test.c +raid6test: test.c raid6.a $(CC) $(CFLAGS) -o raid6test $^ +raid6altivec1.c: raid6altivec.uc ../unroll.pl + $(PERL) ../unroll.pl 1 < raid6altivec.uc > $@ + +raid6altivec2.c: raid6altivec.uc ../unroll.pl + $(PERL) ../unroll.pl 2 < raid6altivec.uc > $@ + +raid6altivec4.c: raid6altivec.uc ../unroll.pl + $(PERL) ../unroll.pl 4 < raid6altivec.uc > $@ + +raid6altivec8.c: raid6altivec.uc ../unroll.pl + $(PERL) ../unroll.pl 8 < raid6altivec.uc > $@ + raid6int1.c: raid6int.uc ../unroll.pl $(PERL) ../unroll.pl 1 < raid6int.uc > $@ @@ -52,7 +69,7 @@ raid6tables.c: mktables ./mktables > raid6tables.c clean: - rm -f *.o mktables mktables.c raid6int.uc raid6*.c raid6test + rm -f *.o *.a mktables mktables.c raid6int.uc raid6*.c raid6test spotless: clean rm -f *~ diff --git a/drivers/media/radio/radio-aimslab.c b/drivers/media/radio/radio-aimslab.c index 8b4ad70..877c770 100644 --- a/drivers/media/radio/radio-aimslab.c +++ b/drivers/media/radio/radio-aimslab.c @@ -29,7 +29,7 @@ #include <linux/module.h> /* Modules */ #include <linux/init.h> /* Initdata */ -#include <linux/ioport.h> /* check_region, request_region */ +#include <linux/ioport.h> /* request_region */ #include <linux/delay.h> /* udelay */ #include <asm/io.h> /* outb, outb_p */ #include <asm/uaccess.h> /* copy to/from user */ diff --git a/drivers/media/radio/radio-aztech.c b/drivers/media/radio/radio-aztech.c index 013c835..5319a9c 100644 --- a/drivers/media/radio/radio-aztech.c +++ b/drivers/media/radio/radio-aztech.c @@ -26,7 +26,7 @@ #include <linux/module.h> /* Modules */ #include <linux/init.h> /* Initdata */ -#include <linux/ioport.h> /* check_region, request_region */ +#include <linux/ioport.h> /* request_region */ #include <linux/delay.h> /* udelay */ #include <asm/io.h> /* outb, outb_p */ #include <asm/uaccess.h> /* copy to/from user */ diff --git a/drivers/media/radio/radio-cadet.c b/drivers/media/radio/radio-cadet.c index 53d399b..022913d 100644 --- a/drivers/media/radio/radio-cadet.c +++ b/drivers/media/radio/radio-cadet.c @@ -29,7 +29,7 @@ #include <linux/module.h> /* Modules */ #include <linux/init.h> /* Initdata */ -#include <linux/ioport.h> /* check_region, request_region */ +#include <linux/ioport.h> /* request_region */ #include <linux/delay.h> /* udelay */ #include <asm/io.h> /* outb, outb_p */ #include <asm/uaccess.h> /* copy to/from user */ diff --git a/drivers/media/radio/radio-gemtek.c b/drivers/media/radio/radio-gemtek.c index 202bfe6..6418f03 100644 --- a/drivers/media/radio/radio-gemtek.c +++ b/drivers/media/radio/radio-gemtek.c @@ -17,7 +17,7 @@ #include <linux/module.h> /* Modules */ #include <linux/init.h> /* Initdata */ -#include <linux/ioport.h> /* check_region, request_region */ +#include <linux/ioport.h> /* request_region */ #include <linux/delay.h> /* udelay */ #include <asm/io.h> /* outb, outb_p */ #include <asm/uaccess.h> /* copy to/from user */ diff --git a/drivers/media/radio/radio-rtrack2.c b/drivers/media/radio/radio-rtrack2.c index c00245d..b2256d6 100644 --- a/drivers/media/radio/radio-rtrack2.c +++ b/drivers/media/radio/radio-rtrack2.c @@ -10,7 +10,7 @@ #include <linux/module.h> /* Modules */ #include <linux/init.h> /* Initdata */ -#include <linux/ioport.h> /* check_region, request_region */ +#include <linux/ioport.h> /* request_region */ #include <linux/delay.h> /* udelay */ #include <asm/io.h> /* outb, outb_p */ #include <asm/uaccess.h> /* copy to/from user */ diff --git a/drivers/media/radio/radio-sf16fmi.c b/drivers/media/radio/radio-sf16fmi.c index 3a464a0..6f03ce4 100644 --- a/drivers/media/radio/radio-sf16fmi.c +++ b/drivers/media/radio/radio-sf16fmi.c @@ -18,7 +18,7 @@ #include <linux/kernel.h> /* __setup */ #include <linux/module.h> /* Modules */ #include <linux/init.h> /* Initdata */ -#include <linux/ioport.h> /* check_region, request_region */ +#include <linux/ioport.h> /* request_region */ #include <linux/delay.h> /* udelay */ #include <linux/videodev.h> /* kernel radio structs */ #include <linux/isapnp.h> diff --git a/drivers/media/radio/radio-sf16fmr2.c b/drivers/media/radio/radio-sf16fmr2.c index 0732efd..71971e9 100644 --- a/drivers/media/radio/radio-sf16fmr2.c +++ b/drivers/media/radio/radio-sf16fmr2.c @@ -14,7 +14,7 @@ #include <linux/module.h> /* Modules */ #include <linux/init.h> /* Initdata */ -#include <linux/ioport.h> /* check_region, request_region */ +#include <linux/ioport.h> /* request_region */ #include <linux/delay.h> /* udelay */ #include <asm/io.h> /* outb, outb_p */ #include <asm/uaccess.h> /* copy to/from user */ diff --git a/drivers/media/radio/radio-terratec.c b/drivers/media/radio/radio-terratec.c index 248d67f..b03573c 100644 --- a/drivers/media/radio/radio-terratec.c +++ b/drivers/media/radio/radio-terratec.c @@ -25,7 +25,7 @@ #include <linux/module.h> /* Modules */ #include <linux/init.h> /* Initdata */ -#include <linux/ioport.h> /* check_region, request_region */ +#include <linux/ioport.h> /* request_region */ #include <linux/delay.h> /* udelay */ #include <asm/io.h> /* outb, outb_p */ #include <asm/uaccess.h> /* copy to/from user */ diff --git a/drivers/media/radio/radio-typhoon.c b/drivers/media/radio/radio-typhoon.c index d7da901..f304f3c 100644 --- a/drivers/media/radio/radio-typhoon.c +++ b/drivers/media/radio/radio-typhoon.c @@ -31,7 +31,7 @@ #include <linux/module.h> /* Modules */ #include <linux/init.h> /* Initdata */ -#include <linux/ioport.h> /* check_region, request_region */ +#include <linux/ioport.h> /* request_region */ #include <linux/proc_fs.h> /* radio card status report */ #include <asm/io.h> /* outb, outb_p */ #include <asm/uaccess.h> /* copy to/from user */ diff --git a/drivers/media/radio/radio-zoltrix.c b/drivers/media/radio/radio-zoltrix.c index 342f92d..4c6d6fb 100644 --- a/drivers/media/radio/radio-zoltrix.c +++ b/drivers/media/radio/radio-zoltrix.c @@ -28,7 +28,7 @@ #include <linux/module.h> /* Modules */ #include <linux/init.h> /* Initdata */ -#include <linux/ioport.h> /* check_region, request_region */ +#include <linux/ioport.h> /* request_region */ #include <linux/delay.h> /* udelay, msleep */ #include <asm/io.h> /* outb, outb_p */ #include <asm/uaccess.h> /* copy to/from user */ diff --git a/drivers/media/video/bttv-driver.c b/drivers/media/video/bttv-driver.c index a564321..c062a017 100644 --- a/drivers/media/video/bttv-driver.c +++ b/drivers/media/video/bttv-driver.c @@ -763,21 +763,21 @@ static void set_pll(struct bttv *btv) /* no PLL needed */ if (btv->pll.pll_current == 0) return; - vprintk(KERN_INFO "bttv%d: PLL can sleep, using XTAL (%d).\n", - btv->c.nr,btv->pll.pll_ifreq); + bttv_printk(KERN_INFO "bttv%d: PLL can sleep, using XTAL (%d).\n", + btv->c.nr,btv->pll.pll_ifreq); btwrite(0x00,BT848_TGCTRL); btwrite(0x00,BT848_PLL_XCI); btv->pll.pll_current = 0; return; } - vprintk(KERN_INFO "bttv%d: PLL: %d => %d ",btv->c.nr, - btv->pll.pll_ifreq, btv->pll.pll_ofreq); + bttv_printk(KERN_INFO "bttv%d: PLL: %d => %d ",btv->c.nr, + btv->pll.pll_ifreq, btv->pll.pll_ofreq); set_pll_freq(btv, btv->pll.pll_ifreq, btv->pll.pll_ofreq); for (i=0; i<10; i++) { /* Let other people run while the PLL stabilizes */ - vprintk("."); + bttv_printk("."); msleep(10); if (btread(BT848_DSTATUS) & BT848_DSTATUS_PLOCK) { @@ -785,12 +785,12 @@ static void set_pll(struct bttv *btv) } else { btwrite(0x08,BT848_TGCTRL); btv->pll.pll_current = btv->pll.pll_ofreq; - vprintk(" ok\n"); + bttv_printk(" ok\n"); return; } } btv->pll.pll_current = -1; - vprintk("failed\n"); + bttv_printk("failed\n"); return; } diff --git a/drivers/media/video/bttvp.h b/drivers/media/video/bttvp.h index 9b0b7ca..7a312f7 100644 --- a/drivers/media/video/bttvp.h +++ b/drivers/media/video/bttvp.h @@ -221,7 +221,7 @@ extern void bttv_gpio_tracking(struct bttv *btv, char *comment); extern int init_bttv_i2c(struct bttv *btv); extern int fini_bttv_i2c(struct bttv *btv); -#define vprintk if (bttv_verbose) printk +#define bttv_printk if (bttv_verbose) printk #define dprintk if (bttv_debug >= 1) printk #define d2printk if (bttv_debug >= 2) printk diff --git a/drivers/media/video/cx88/cx88-dvb.c b/drivers/media/video/cx88/cx88-dvb.c index c9106b1..4334744 100644 --- a/drivers/media/video/cx88/cx88-dvb.c +++ b/drivers/media/video/cx88/cx88-dvb.c @@ -221,9 +221,7 @@ static int lgdt330x_pll_set(struct dvb_frontend* fe, int err; /* Put the analog decoder in standby to keep it quiet */ - if (core->tda9887_conf) { - cx88_call_i2c_clients (dev->core, TUNER_SET_STANDBY, NULL); - } + cx88_call_i2c_clients (dev->core, TUNER_SET_STANDBY, NULL); dvb_pll_configure(core->pll_desc, buf, params->frequency, 0); dprintk(1, "%s: tuner at 0x%02x bytes: 0x%02x 0x%02x 0x%02x 0x%02x\n", @@ -402,6 +400,9 @@ static int dvb_register(struct cx8802_dev *dev) dev->dvb.frontend->ops->info.frequency_max = dev->core->pll_desc->max; } + /* Put the analog decoder in standby to keep it quiet */ + cx88_call_i2c_clients (dev->core, TUNER_SET_STANDBY, NULL); + /* register everything */ return videobuf_dvb_register(&dev->dvb, THIS_MODULE, dev); } diff --git a/drivers/message/fusion/Kconfig b/drivers/message/fusion/Kconfig index 33f209a..1883d22 100644 --- a/drivers/message/fusion/Kconfig +++ b/drivers/message/fusion/Kconfig @@ -35,6 +35,23 @@ config FUSION_FC LSIFC929X LSIFC929XL +config FUSION_SAS + tristate "Fusion MPT ScsiHost drivers for SAS" + depends on PCI && SCSI + select FUSION + select SCSI_SAS_ATTRS + ---help--- + SCSI HOST support for a SAS host adapters. + + List of supported controllers: + + LSISAS1064 + LSISAS1066 + LSISAS1068 + LSISAS1064E + LSISAS1066E + LSISAS1068E + config FUSION_MAX_SGE int "Maximum number of scatter gather entries (16 - 128)" depends on FUSION diff --git a/drivers/message/fusion/Makefile b/drivers/message/fusion/Makefile index 1d2f9db..8a2e265 100644 --- a/drivers/message/fusion/Makefile +++ b/drivers/message/fusion/Makefile @@ -34,5 +34,6 @@ obj-$(CONFIG_FUSION_SPI) += mptbase.o mptscsih.o mptspi.o obj-$(CONFIG_FUSION_FC) += mptbase.o mptscsih.o mptfc.o +obj-$(CONFIG_FUSION_SAS) += mptbase.o mptscsih.o mptsas.o obj-$(CONFIG_FUSION_CTL) += mptctl.o obj-$(CONFIG_FUSION_LAN) += mptlan.o diff --git a/drivers/message/fusion/mptbase.c b/drivers/message/fusion/mptbase.c index f517d06..790a293 100644 --- a/drivers/message/fusion/mptbase.c +++ b/drivers/message/fusion/mptbase.c @@ -135,13 +135,12 @@ static void mpt_adapter_dispose(MPT_ADAPTER *ioc); static void MptDisplayIocCapabilities(MPT_ADAPTER *ioc); static int MakeIocReady(MPT_ADAPTER *ioc, int force, int sleepFlag); -//static u32 mpt_GetIocState(MPT_ADAPTER *ioc, int cooked); static int GetIocFacts(MPT_ADAPTER *ioc, int sleepFlag, int reason); static int GetPortFacts(MPT_ADAPTER *ioc, int portnum, int sleepFlag); static int SendIocInit(MPT_ADAPTER *ioc, int sleepFlag); static int SendPortEnable(MPT_ADAPTER *ioc, int portnum, int sleepFlag); static int mpt_do_upload(MPT_ADAPTER *ioc, int sleepFlag); -static int mpt_downloadboot(MPT_ADAPTER *ioc, int sleepFlag); +static int mpt_downloadboot(MPT_ADAPTER *ioc, MpiFwHeader_t *pFwHeader, int sleepFlag); static int mpt_diag_reset(MPT_ADAPTER *ioc, int ignore, int sleepFlag); static int KickStart(MPT_ADAPTER *ioc, int ignore, int sleepFlag); static int SendIocReset(MPT_ADAPTER *ioc, u8 reset_type, int sleepFlag); @@ -152,6 +151,7 @@ static int WaitForDoorbellReply(MPT_ADAPTER *ioc, int howlong, int sleepFlag); static int GetLanConfigPages(MPT_ADAPTER *ioc); static int GetFcPortPage0(MPT_ADAPTER *ioc, int portnum); static int GetIoUnitPage2(MPT_ADAPTER *ioc); +int mptbase_sas_persist_operation(MPT_ADAPTER *ioc, u8 persist_opcode); static int mpt_GetScsiPortSettings(MPT_ADAPTER *ioc, int portnum); static int mpt_readScsiDevicePageHeaders(MPT_ADAPTER *ioc, int portnum); static void mpt_read_ioc_pg_1(MPT_ADAPTER *ioc); @@ -159,6 +159,8 @@ static void mpt_read_ioc_pg_4(MPT_ADAPTER *ioc); static void mpt_timer_expired(unsigned long data); static int SendEventNotification(MPT_ADAPTER *ioc, u8 EvSwitch); static int SendEventAck(MPT_ADAPTER *ioc, EventNotificationReply_t *evnp); +static int mpt_host_page_access_control(MPT_ADAPTER *ioc, u8 access_control_value, int sleepFlag); +static int mpt_host_page_alloc(MPT_ADAPTER *ioc, pIOCInit_t ioc_init); #ifdef CONFIG_PROC_FS static int procmpt_summary_read(char *buf, char **start, off_t offset, @@ -175,6 +177,7 @@ static int ProcessEventNotification(MPT_ADAPTER *ioc, EventNotificationReply_t * static void mpt_sp_ioc_info(MPT_ADAPTER *ioc, u32 ioc_status, MPT_FRAME_HDR *mf); static void mpt_fc_log_info(MPT_ADAPTER *ioc, u32 log_info); static void mpt_sp_log_info(MPT_ADAPTER *ioc, u32 log_info); +static void mpt_sas_log_info(MPT_ADAPTER *ioc, u32 log_info); /* module entry point */ static int __init fusion_init (void); @@ -206,6 +209,144 @@ pci_enable_io_access(struct pci_dev *pdev) pci_write_config_word(pdev, PCI_COMMAND, command_reg); } +/* + * Process turbo (context) reply... + */ +static void +mpt_turbo_reply(MPT_ADAPTER *ioc, u32 pa) +{ + MPT_FRAME_HDR *mf = NULL; + MPT_FRAME_HDR *mr = NULL; + int req_idx = 0; + int cb_idx; + + dmfprintk((MYIOC_s_INFO_FMT "Got TURBO reply req_idx=%08x\n", + ioc->name, pa)); + + switch (pa >> MPI_CONTEXT_REPLY_TYPE_SHIFT) { + case MPI_CONTEXT_REPLY_TYPE_SCSI_INIT: + req_idx = pa & 0x0000FFFF; + cb_idx = (pa & 0x00FF0000) >> 16; + mf = MPT_INDEX_2_MFPTR(ioc, req_idx); + break; + case MPI_CONTEXT_REPLY_TYPE_LAN: + cb_idx = mpt_lan_index; + /* + * Blind set of mf to NULL here was fatal + * after lan_reply says "freeme" + * Fix sort of combined with an optimization here; + * added explicit check for case where lan_reply + * was just returning 1 and doing nothing else. + * For this case skip the callback, but set up + * proper mf value first here:-) + */ + if ((pa & 0x58000000) == 0x58000000) { + req_idx = pa & 0x0000FFFF; + mf = MPT_INDEX_2_MFPTR(ioc, req_idx); + mpt_free_msg_frame(ioc, mf); + mb(); + return; + break; + } + mr = (MPT_FRAME_HDR *) CAST_U32_TO_PTR(pa); + break; + case MPI_CONTEXT_REPLY_TYPE_SCSI_TARGET: + cb_idx = mpt_stm_index; + mr = (MPT_FRAME_HDR *) CAST_U32_TO_PTR(pa); + break; + default: + cb_idx = 0; + BUG(); + } + + /* Check for (valid) IO callback! */ + if (cb_idx < 1 || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS || + MptCallbacks[cb_idx] == NULL) { + printk(MYIOC_s_WARN_FMT "%s: Invalid cb_idx (%d)!\n", + __FUNCTION__, ioc->name, cb_idx); + goto out; + } + + if (MptCallbacks[cb_idx](ioc, mf, mr)) + mpt_free_msg_frame(ioc, mf); + out: + mb(); +} + +static void +mpt_reply(MPT_ADAPTER *ioc, u32 pa) +{ + MPT_FRAME_HDR *mf; + MPT_FRAME_HDR *mr; + int req_idx; + int cb_idx; + int freeme; + + u32 reply_dma_low; + u16 ioc_stat; + + /* non-TURBO reply! Hmmm, something may be up... + * Newest turbo reply mechanism; get address + * via left shift 1 (get rid of MPI_ADDRESS_REPLY_A_BIT)! + */ + + /* Map DMA address of reply header to cpu address. + * pa is 32 bits - but the dma address may be 32 or 64 bits + * get offset based only only the low addresses + */ + + reply_dma_low = (pa <<= 1); + mr = (MPT_FRAME_HDR *)((u8 *)ioc->reply_frames + + (reply_dma_low - ioc->reply_frames_low_dma)); + + req_idx = le16_to_cpu(mr->u.frame.hwhdr.msgctxu.fld.req_idx); + cb_idx = mr->u.frame.hwhdr.msgctxu.fld.cb_idx; + mf = MPT_INDEX_2_MFPTR(ioc, req_idx); + + dmfprintk((MYIOC_s_INFO_FMT "Got non-TURBO reply=%p req_idx=%x cb_idx=%x Function=%x\n", + ioc->name, mr, req_idx, cb_idx, mr->u.hdr.Function)); + DBG_DUMP_REPLY_FRAME(mr) + + /* Check/log IOC log info + */ + ioc_stat = le16_to_cpu(mr->u.reply.IOCStatus); + if (ioc_stat & MPI_IOCSTATUS_FLAG_LOG_INFO_AVAILABLE) { + u32 log_info = le32_to_cpu(mr->u.reply.IOCLogInfo); + if (ioc->bus_type == FC) + mpt_fc_log_info(ioc, log_info); + else if (ioc->bus_type == SCSI) + mpt_sp_log_info(ioc, log_info); + else if (ioc->bus_type == SAS) + mpt_sas_log_info(ioc, log_info); + } + if (ioc_stat & MPI_IOCSTATUS_MASK) { + if (ioc->bus_type == SCSI && + cb_idx != mpt_stm_index && + cb_idx != mpt_lan_index) + mpt_sp_ioc_info(ioc, (u32)ioc_stat, mf); + } + + + /* Check for (valid) IO callback! */ + if (cb_idx < 1 || cb_idx >= MPT_MAX_PROTOCOL_DRIVERS || + MptCallbacks[cb_idx] == NULL) { + printk(MYIOC_s_WARN_FMT "%s: Invalid cb_idx (%d)!\n", + __FUNCTION__, ioc->name, cb_idx); + freeme = 0; + goto out; + } + + freeme = MptCallbacks[cb_idx](ioc, mf, mr); + + out: + /* Flush (non-TURBO) reply with a WRITE! */ + CHIPREG_WRITE32(&ioc->chip->ReplyFifo, pa); + + if (freeme) + mpt_free_msg_frame(ioc, mf); + mb(); +} + /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ /* * mpt_interrupt - MPT adapter (IOC) specific interrupt handler. @@ -227,164 +368,21 @@ pci_enable_io_access(struct pci_dev *pdev) static irqreturn_t mpt_interrupt(int irq, void *bus_id, struct pt_regs *r) { - MPT_ADAPTER *ioc; - MPT_FRAME_HDR *mf; - MPT_FRAME_HDR *mr; - u32 pa; - int req_idx; - int cb_idx; - int type; - int freeme; - - ioc = (MPT_ADAPTER *)bus_id; + MPT_ADAPTER *ioc = bus_id; + u32 pa; /* * Drain the reply FIFO! - * - * NOTES: I've seen up to 10 replies processed in this loop, so far... - * Update: I've seen up to 9182 replies processed in this loop! ?? - * Update: Limit ourselves to processing max of N replies - * (bottom of loop). */ while (1) { - - if ((pa = CHIPREG_READ32_dmasync(&ioc->chip->ReplyFifo)) == 0xFFFFFFFF) + pa = CHIPREG_READ32_dmasync(&ioc->chip->ReplyFifo); + if (pa == 0xFFFFFFFF) return IRQ_HANDLED; - - cb_idx = 0; - freeme = 0; - - /* - * Check for non-TURBO reply! - */ - if (pa & MPI_ADDRESS_REPLY_A_BIT) { - u32 reply_dma_low; - u16 ioc_stat; - - /* non-TURBO reply! Hmmm, something may be up... - * Newest turbo reply mechanism; get address - * via left shift 1 (get rid of MPI_ADDRESS_REPLY_A_BIT)! - */ - - /* Map DMA address of reply header to cpu address. - * pa is 32 bits - but the dma address may be 32 or 64 bits - * get offset based only only the low addresses - */ - reply_dma_low = (pa = (pa << 1)); - mr = (MPT_FRAME_HDR *)((u8 *)ioc->reply_frames + - (reply_dma_low - ioc->reply_frames_low_dma)); - - req_idx = le16_to_cpu(mr->u.frame.hwhdr.msgctxu.fld.req_idx); - cb_idx = mr->u.frame.hwhdr.msgctxu.fld.cb_idx; - mf = MPT_INDEX_2_MFPTR(ioc, req_idx); - - dmfprintk((MYIOC_s_INFO_FMT "Got non-TURBO reply=%p req_idx=%x cb_idx=%x Function=%x\n", - ioc->name, mr, req_idx, cb_idx, mr->u.hdr.Function)); - DBG_DUMP_REPLY_FRAME(mr) - - /* Check/log IOC log info - */ - ioc_stat = le16_to_cpu(mr->u.reply.IOCStatus); - if (ioc_stat & MPI_IOCSTATUS_FLAG_LOG_INFO_AVAILABLE) { - u32 log_info = le32_to_cpu(mr->u.reply.IOCLogInfo); - if (ioc->bus_type == FC) - mpt_fc_log_info(ioc, log_info); - else if (ioc->bus_type == SCSI) - mpt_sp_log_info(ioc, log_info); - } - if (ioc_stat & MPI_IOCSTATUS_MASK) { - if (ioc->bus_type == SCSI) - mpt_sp_ioc_info(ioc, (u32)ioc_stat, mf); - } - } else { - /* - * Process turbo (context) reply... - */ - dmfprintk((MYIOC_s_INFO_FMT "Got TURBO reply req_idx=%08x\n", ioc->name, pa)); - type = (pa >> MPI_CONTEXT_REPLY_TYPE_SHIFT); - if (type == MPI_CONTEXT_REPLY_TYPE_SCSI_TARGET) { - cb_idx = mpt_stm_index; - mf = NULL; - mr = (MPT_FRAME_HDR *) CAST_U32_TO_PTR(pa); - } else if (type == MPI_CONTEXT_REPLY_TYPE_LAN) { - cb_idx = mpt_lan_index; - /* Blind set of mf to NULL here was fatal - * after lan_reply says "freeme" - * Fix sort of combined with an optimization here; - * added explicit check for case where lan_reply - * was just returning 1 and doing nothing else. - * For this case skip the callback, but set up - * proper mf value first here:-) - */ - if ((pa & 0x58000000) == 0x58000000) { - req_idx = pa & 0x0000FFFF; - mf = MPT_INDEX_2_MFPTR(ioc, req_idx); - freeme = 1; - /* - * IMPORTANT! Invalidate the callback! - */ - cb_idx = 0; - } else { - mf = NULL; - } - mr = (MPT_FRAME_HDR *) CAST_U32_TO_PTR(pa); - } else { - req_idx = pa & 0x0000FFFF; - cb_idx = (pa & 0x00FF0000) >> 16; - mf = MPT_INDEX_2_MFPTR(ioc, req_idx); - mr = NULL; - } - pa = 0; /* No reply flush! */ - } - -#ifdef MPT_DEBUG_IRQ - if (ioc->bus_type == SCSI) { - /* Verify mf, mr are reasonable. - */ - if ((mf) && ((mf >= MPT_INDEX_2_MFPTR(ioc, ioc->req_depth)) - || (mf < ioc->req_frames)) ) { - printk(MYIOC_s_WARN_FMT - "mpt_interrupt: Invalid mf (%p)!\n", ioc->name, (void *)mf); - cb_idx = 0; - pa = 0; - freeme = 0; - } - if ((pa) && (mr) && ((mr >= MPT_INDEX_2_RFPTR(ioc, ioc->req_depth)) - || (mr < ioc->reply_frames)) ) { - printk(MYIOC_s_WARN_FMT - "mpt_interrupt: Invalid rf (%p)!\n", ioc->name, (void *)mr); - cb_idx = 0; - pa = 0; - freeme = 0; - } - if (cb_idx > (MPT_MAX_PROTOCOL_DRIVERS-1)) { - printk(MYIOC_s_WARN_FMT - "mpt_interrupt: Invalid cb_idx (%d)!\n", ioc->name, cb_idx); - cb_idx = 0; - pa = 0; - freeme = 0; - } - } -#endif - - /* Check for (valid) IO callback! */ - if (cb_idx) { - /* Do the callback! */ - freeme = (*(MptCallbacks[cb_idx]))(ioc, mf, mr); - } - - if (pa) { - /* Flush (non-TURBO) reply with a WRITE! */ - CHIPREG_WRITE32(&ioc->chip->ReplyFifo, pa); - } - - if (freeme) { - /* Put Request back on FreeQ! */ - mpt_free_msg_frame(ioc, mf); - } - - mb(); - } /* drain reply FIFO */ + else if (pa & MPI_ADDRESS_REPLY_A_BIT) + mpt_reply(ioc, pa); + else + mpt_turbo_reply(ioc, pa); + } return IRQ_HANDLED; } @@ -509,6 +507,14 @@ mpt_base_reply(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *reply) pCfg->wait_done = 1; wake_up(&mpt_waitq); } + } else if (func == MPI_FUNCTION_SAS_IO_UNIT_CONTROL) { + /* we should be always getting a reply frame */ + memcpy(ioc->persist_reply_frame, reply, + min(MPT_DEFAULT_FRAME_SIZE, + 4*reply->u.reply.MsgLength)); + del_timer(&ioc->persist_timer); + ioc->persist_wait_done = 1; + wake_up(&mpt_waitq); } else { printk(MYIOC_s_ERR_FMT "Unexpected msg function (=%02Xh) reply received!\n", ioc->name, func); @@ -750,6 +756,7 @@ mpt_get_msg_frame(int handle, MPT_ADAPTER *ioc) mf = list_entry(ioc->FreeQ.next, MPT_FRAME_HDR, u.frame.linkage.list); list_del(&mf->u.frame.linkage.list); + mf->u.frame.linkage.arg1 = 0; mf->u.frame.hwhdr.msgctxu.fld.cb_idx = handle; /* byte */ req_offset = (u8 *)mf - (u8 *)ioc->req_frames; /* u16! */ @@ -845,6 +852,7 @@ mpt_free_msg_frame(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf) /* Put Request back on FreeQ! */ spin_lock_irqsave(&ioc->FreeQlock, flags); + mf->u.frame.linkage.arg1 = 0xdeadbeaf; /* signature to know if this mf is freed */ list_add_tail(&mf->u.frame.linkage.list, &ioc->FreeQ); #ifdef MFCNT ioc->mfcnt--; @@ -971,12 +979,123 @@ mpt_send_handshake_request(int handle, MPT_ADAPTER *ioc, int reqBytes, u32 *req, /* Make sure there are no doorbells */ CHIPREG_WRITE32(&ioc->chip->IntStatus, 0); - + return r; } /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ /** + * mpt_host_page_access_control - provides mechanism for the host + * driver to control the IOC's Host Page Buffer access. + * @ioc: Pointer to MPT adapter structure + * @access_control_value: define bits below + * + * Access Control Value - bits[15:12] + * 0h Reserved + * 1h Enable Access { MPI_DB_HPBAC_ENABLE_ACCESS } + * 2h Disable Access { MPI_DB_HPBAC_DISABLE_ACCESS } + * 3h Free Buffer { MPI_DB_HPBAC_FREE_BUFFER } + * + * Returns 0 for success, non-zero for failure. + */ + +static int +mpt_host_page_access_control(MPT_ADAPTER *ioc, u8 access_control_value, int sleepFlag) +{ + int r = 0; + + /* return if in use */ + if (CHIPREG_READ32(&ioc->chip->Doorbell) + & MPI_DOORBELL_ACTIVE) + return -1; + + CHIPREG_WRITE32(&ioc->chip->IntStatus, 0); + + CHIPREG_WRITE32(&ioc->chip->Doorbell, + ((MPI_FUNCTION_HOST_PAGEBUF_ACCESS_CONTROL + <<MPI_DOORBELL_FUNCTION_SHIFT) | + (access_control_value<<12))); + + /* Wait for IOC to clear Doorbell Status bit */ + if ((r = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0) { + return -2; + }else + return 0; +} + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +/** + * mpt_host_page_alloc - allocate system memory for the fw + * If we already allocated memory in past, then resend the same pointer. + * ioc@: Pointer to pointer to IOC adapter + * ioc_init@: Pointer to ioc init config page + * + * Returns 0 for success, non-zero for failure. + */ +static int +mpt_host_page_alloc(MPT_ADAPTER *ioc, pIOCInit_t ioc_init) +{ + char *psge; + int flags_length; + u32 host_page_buffer_sz=0; + + if(!ioc->HostPageBuffer) { + + host_page_buffer_sz = + le32_to_cpu(ioc->facts.HostPageBufferSGE.FlagsLength) & 0xFFFFFF; + + if(!host_page_buffer_sz) + return 0; /* fw doesn't need any host buffers */ + + /* spin till we get enough memory */ + while(host_page_buffer_sz > 0) { + + if((ioc->HostPageBuffer = pci_alloc_consistent( + ioc->pcidev, + host_page_buffer_sz, + &ioc->HostPageBuffer_dma)) != NULL) { + + dinitprintk((MYIOC_s_INFO_FMT + "host_page_buffer @ %p, dma @ %x, sz=%d bytes\n", + ioc->name, + ioc->HostPageBuffer, + ioc->HostPageBuffer_dma, + host_page_buffer_sz)); + ioc->alloc_total += host_page_buffer_sz; + ioc->HostPageBuffer_sz = host_page_buffer_sz; + break; + } + + host_page_buffer_sz -= (4*1024); + } + } + + if(!ioc->HostPageBuffer) { + printk(MYIOC_s_ERR_FMT + "Failed to alloc memory for host_page_buffer!\n", + ioc->name); + return -999; + } + + psge = (char *)&ioc_init->HostPageBufferSGE; + flags_length = MPI_SGE_FLAGS_SIMPLE_ELEMENT | + MPI_SGE_FLAGS_SYSTEM_ADDRESS | + MPI_SGE_FLAGS_32_BIT_ADDRESSING | + MPI_SGE_FLAGS_HOST_TO_IOC | + MPI_SGE_FLAGS_END_OF_BUFFER; + if (sizeof(dma_addr_t) == sizeof(u64)) { + flags_length |= MPI_SGE_FLAGS_64_BIT_ADDRESSING; + } + flags_length = flags_length << MPI_SGE_FLAGS_SHIFT; + flags_length |= ioc->HostPageBuffer_sz; + mpt_add_sge(psge, flags_length, ioc->HostPageBuffer_dma); + ioc->facts.HostPageBufferSGE = ioc_init->HostPageBufferSGE; + +return 0; +} + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +/** * mpt_verify_adapter - Given a unique IOC identifier, set pointer to * the associated MPT adapter structure. * @iocid: IOC unique identifier (integer) @@ -1084,7 +1203,7 @@ mpt_attach(struct pci_dev *pdev, const struct pci_device_id *id) /* Initilize SCSI Config Data structure */ - memset(&ioc->spi_data, 0, sizeof(ScsiCfgData)); + memset(&ioc->spi_data, 0, sizeof(SpiCfgData)); /* Initialize the running configQ head. */ @@ -1213,6 +1332,33 @@ mpt_attach(struct pci_dev *pdev, const struct pci_device_id *id) ioc->prod_name = "LSI53C1035"; ioc->bus_type = SCSI; } + else if (pdev->device == MPI_MANUFACTPAGE_DEVID_SAS1064) { + ioc->prod_name = "LSISAS1064"; + ioc->bus_type = SAS; + ioc->errata_flag_1064 = 1; + } + else if (pdev->device == MPI_MANUFACTPAGE_DEVID_SAS1066) { + ioc->prod_name = "LSISAS1066"; + ioc->bus_type = SAS; + ioc->errata_flag_1064 = 1; + } + else if (pdev->device == MPI_MANUFACTPAGE_DEVID_SAS1068) { + ioc->prod_name = "LSISAS1068"; + ioc->bus_type = SAS; + ioc->errata_flag_1064 = 1; + } + else if (pdev->device == MPI_MANUFACTPAGE_DEVID_SAS1064E) { + ioc->prod_name = "LSISAS1064E"; + ioc->bus_type = SAS; + } + else if (pdev->device == MPI_MANUFACTPAGE_DEVID_SAS1066E) { + ioc->prod_name = "LSISAS1066E"; + ioc->bus_type = SAS; + } + else if (pdev->device == MPI_MANUFACTPAGE_DEVID_SAS1068E) { + ioc->prod_name = "LSISAS1068E"; + ioc->bus_type = SAS; + } if (ioc->errata_flag_1064) pci_disable_io_access(pdev); @@ -1604,8 +1750,23 @@ mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u32 reason, int sleepFlag) */ if (ret == 0) { rc = mpt_do_upload(ioc, sleepFlag); - if (rc != 0) + if (rc == 0) { + if (ioc->alt_ioc && ioc->alt_ioc->cached_fw) { + /* + * Maintain only one pointer to FW memory + * so there will not be two attempt to + * downloadboot onboard dual function + * chips (mpt_adapter_disable, + * mpt_diag_reset) + */ + ioc->cached_fw = NULL; + ddlprintk((MYIOC_s_INFO_FMT ": mpt_upload: alt_%s has cached_fw=%p \n", + ioc->name, ioc->alt_ioc->name, ioc->alt_ioc->cached_fw)); + } + } else { printk(KERN_WARNING MYNAM ": firmware upload failure!\n"); + ret = -5; + } } } } @@ -1640,7 +1801,22 @@ mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u32 reason, int sleepFlag) * and we try GetLanConfigPages again... */ if ((ret == 0) && (reason == MPT_HOSTEVENT_IOC_BRINGUP)) { - if (ioc->bus_type == FC) { + if (ioc->bus_type == SAS) { + + /* clear persistency table */ + if(ioc->facts.IOCExceptions & + MPI_IOCFACTS_EXCEPT_PERSISTENT_TABLE_FULL) { + ret = mptbase_sas_persist_operation(ioc, + MPI_SAS_OP_CLEAR_NOT_PRESENT); + if(ret != 0) + return -1; + } + + /* Find IM volumes + */ + mpt_findImVolumes(ioc); + + } else if (ioc->bus_type == FC) { /* * Pre-fetch FC port WWN and stuff... * (FCPortPage0_t stuff) @@ -1783,7 +1959,7 @@ mpt_adapter_disable(MPT_ADAPTER *ioc) if (ioc->cached_fw != NULL) { ddlprintk((KERN_INFO MYNAM ": mpt_adapter_disable: Pushing FW onto adapter\n")); - if ((ret = mpt_downloadboot(ioc, NO_SLEEP)) < 0) { + if ((ret = mpt_downloadboot(ioc, (MpiFwHeader_t *)ioc->cached_fw, NO_SLEEP)) < 0) { printk(KERN_WARNING MYNAM ": firmware downloadboot failure (%d)!\n", ret); } @@ -1831,9 +2007,9 @@ mpt_adapter_disable(MPT_ADAPTER *ioc) } kfree(ioc->spi_data.nvram); - kfree(ioc->spi_data.pIocPg3); + kfree(ioc->raid_data.pIocPg3); ioc->spi_data.nvram = NULL; - ioc->spi_data.pIocPg3 = NULL; + ioc->raid_data.pIocPg3 = NULL; if (ioc->spi_data.pIocPg4 != NULL) { sz = ioc->spi_data.IocPg4Sz; @@ -1852,6 +2028,23 @@ mpt_adapter_disable(MPT_ADAPTER *ioc) kfree(ioc->ChainToChain); ioc->ChainToChain = NULL; + + if (ioc->HostPageBuffer != NULL) { + if((ret = mpt_host_page_access_control(ioc, + MPI_DB_HPBAC_FREE_BUFFER, NO_SLEEP)) != 0) { + printk(KERN_ERR MYNAM + ": %s: host page buffers free failed (%d)!\n", + __FUNCTION__, ret); + } + dexitprintk((KERN_INFO MYNAM ": %s HostPageBuffer free @ %p, sz=%d bytes\n", + ioc->name, ioc->HostPageBuffer, ioc->HostPageBuffer_sz)); + pci_free_consistent(ioc->pcidev, ioc->HostPageBuffer_sz, + ioc->HostPageBuffer, + ioc->HostPageBuffer_dma); + ioc->HostPageBuffer = NULL; + ioc->HostPageBuffer_sz = 0; + ioc->alloc_total -= ioc->HostPageBuffer_sz; + } } /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ @@ -2034,7 +2227,7 @@ MakeIocReady(MPT_ADAPTER *ioc, int force, int sleepFlag) * Loop here waiting for IOC to come READY. */ ii = 0; - cntdn = ((sleepFlag == CAN_SLEEP) ? HZ : 1000) * 15; /* 15 seconds */ + cntdn = ((sleepFlag == CAN_SLEEP) ? HZ : 1000) * 5; /* 5 seconds */ while ((ioc_state = mpt_GetIocState(ioc, 1)) != MPI_IOC_STATE_READY) { if (ioc_state == MPI_IOC_STATE_OPERATIONAL) { @@ -2212,6 +2405,7 @@ GetIocFacts(MPT_ADAPTER *ioc, int sleepFlag, int reason) le32_to_cpu(facts->CurrentSenseBufferHighAddr); facts->CurReplyFrameSize = le16_to_cpu(facts->CurReplyFrameSize); + facts->IOCCapabilities = le32_to_cpu(facts->IOCCapabilities); /* * Handle NEW (!) IOCFactsReply fields in MPI-1.01.xx @@ -2383,13 +2577,25 @@ SendIocInit(MPT_ADAPTER *ioc, int sleepFlag) ddlprintk((MYIOC_s_INFO_FMT "upload_fw %d facts.Flags=%x\n", ioc->name, ioc->upload_fw, ioc->facts.Flags)); - if (ioc->bus_type == FC) + if(ioc->bus_type == SAS) + ioc_init.MaxDevices = ioc->facts.MaxDevices; + else if(ioc->bus_type == FC) ioc_init.MaxDevices = MPT_MAX_FC_DEVICES; else ioc_init.MaxDevices = MPT_MAX_SCSI_DEVICES; - ioc_init.MaxBuses = MPT_MAX_BUS; - + dinitprintk((MYIOC_s_INFO_FMT "facts.MsgVersion=%x\n", + ioc->name, ioc->facts.MsgVersion)); + if (ioc->facts.MsgVersion >= MPI_VERSION_01_05) { + // set MsgVersion and HeaderVersion host driver was built with + ioc_init.MsgVersion = cpu_to_le16(MPI_VERSION); + ioc_init.HeaderVersion = cpu_to_le16(MPI_HEADER_VERSION); + + if (ioc->facts.Flags & MPI_IOCFACTS_FLAGS_HOST_PAGE_BUFFER_PERSISTENT) { + ioc_init.HostPageBufferSGE = ioc->facts.HostPageBufferSGE; + } else if(mpt_host_page_alloc(ioc, &ioc_init)) + return -99; + } ioc_init.ReplyFrameSize = cpu_to_le16(ioc->reply_sz); /* in BYTES */ if (sizeof(dma_addr_t) == sizeof(u64)) { @@ -2403,17 +2609,21 @@ SendIocInit(MPT_ADAPTER *ioc, int sleepFlag) ioc_init.HostMfaHighAddr = cpu_to_le32(0); ioc_init.SenseBufferHighAddr = cpu_to_le32(0); } - + ioc->facts.CurrentHostMfaHighAddr = ioc_init.HostMfaHighAddr; ioc->facts.CurrentSenseBufferHighAddr = ioc_init.SenseBufferHighAddr; + ioc->facts.MaxDevices = ioc_init.MaxDevices; + ioc->facts.MaxBuses = ioc_init.MaxBuses; dhsprintk((MYIOC_s_INFO_FMT "Sending IOCInit (req @ %p)\n", ioc->name, &ioc_init)); r = mpt_handshake_req_reply_wait(ioc, sizeof(IOCInit_t), (u32*)&ioc_init, sizeof(MPIDefaultReply_t), (u16*)&init_reply, 10 /*seconds*/, sleepFlag); - if (r != 0) + if (r != 0) { + printk(MYIOC_s_ERR_FMT "Sending IOCInit failed(%d)!\n",ioc->name, r); return r; + } /* No need to byte swap the multibyte fields in the reply * since we don't even look at it's contents. @@ -2472,7 +2682,7 @@ SendPortEnable(MPT_ADAPTER *ioc, int portnum, int sleepFlag) { PortEnable_t port_enable; MPIDefaultReply_t reply_buf; - int ii; + int rc; int req_sz; int reply_sz; @@ -2494,22 +2704,15 @@ SendPortEnable(MPT_ADAPTER *ioc, int portnum, int sleepFlag) /* RAID FW may take a long time to enable */ - if (ioc->bus_type == FC) { - ii = mpt_handshake_req_reply_wait(ioc, req_sz, (u32*)&port_enable, - reply_sz, (u16*)&reply_buf, 65 /*seconds*/, sleepFlag); - } else { - ii = mpt_handshake_req_reply_wait(ioc, req_sz, (u32*)&port_enable, + if ( (ioc->facts.ProductID & MPI_FW_HEADER_PID_PROD_MASK) + > MPI_FW_HEADER_PID_PROD_TARGET_SCSI ) { + rc = mpt_handshake_req_reply_wait(ioc, req_sz, (u32*)&port_enable, reply_sz, (u16*)&reply_buf, 300 /*seconds*/, sleepFlag); + } else { + rc = mpt_handshake_req_reply_wait(ioc, req_sz, (u32*)&port_enable, + reply_sz, (u16*)&reply_buf, 30 /*seconds*/, sleepFlag); } - - if (ii != 0) - return ii; - - /* We do not even look at the reply, so we need not - * swap the multi-byte fields. - */ - - return 0; + return rc; } /* @@ -2666,9 +2869,8 @@ mpt_do_upload(MPT_ADAPTER *ioc, int sleepFlag) * <0 for fw upload failure. */ static int -mpt_downloadboot(MPT_ADAPTER *ioc, int sleepFlag) +mpt_downloadboot(MPT_ADAPTER *ioc, MpiFwHeader_t *pFwHeader, int sleepFlag) { - MpiFwHeader_t *pFwHeader; MpiExtImageHeader_t *pExtImage; u32 fwSize; u32 diag0val; @@ -2679,18 +2881,8 @@ mpt_downloadboot(MPT_ADAPTER *ioc, int sleepFlag) u32 load_addr; u32 ioc_state=0; - ddlprintk((MYIOC_s_INFO_FMT "downloadboot: fw size 0x%x, ioc FW Ptr %p\n", - ioc->name, ioc->facts.FWImageSize, ioc->cached_fw)); - - if ( ioc->facts.FWImageSize == 0 ) - return -1; - - if (ioc->cached_fw == NULL) - return -2; - - /* prevent a second downloadboot and memory free with alt_ioc */ - if (ioc->alt_ioc && ioc->alt_ioc->cached_fw) - ioc->alt_ioc->cached_fw = NULL; + ddlprintk((MYIOC_s_INFO_FMT "downloadboot: fw size 0x%x (%d), FW Ptr %p\n", + ioc->name, pFwHeader->ImageSize, pFwHeader->ImageSize, pFwHeader)); CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF); CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_1ST_KEY_VALUE); @@ -2718,16 +2910,17 @@ mpt_downloadboot(MPT_ADAPTER *ioc, int sleepFlag) ioc->name, count)); break; } - /* wait 1 sec */ + /* wait .1 sec */ if (sleepFlag == CAN_SLEEP) { - msleep_interruptible (1000); + msleep_interruptible (100); } else { - mdelay (1000); + mdelay (100); } } if ( count == 30 ) { - ddlprintk((MYIOC_s_INFO_FMT "downloadboot failed! Unable to RESET_ADAPTER diag0val=%x\n", + ddlprintk((MYIOC_s_INFO_FMT "downloadboot failed! " + "Unable to get MPI_DIAG_DRWE mode, diag0val=%x\n", ioc->name, diag0val)); return -3; } @@ -2742,7 +2935,6 @@ mpt_downloadboot(MPT_ADAPTER *ioc, int sleepFlag) /* Set the DiagRwEn and Disable ARM bits */ CHIPREG_WRITE32(&ioc->chip->Diagnostic, (MPI_DIAG_RW_ENABLE | MPI_DIAG_DISABLE_ARM)); - pFwHeader = (MpiFwHeader_t *) ioc->cached_fw; fwSize = (pFwHeader->ImageSize + 3)/4; ptrFw = (u32 *) pFwHeader; @@ -2792,19 +2984,38 @@ mpt_downloadboot(MPT_ADAPTER *ioc, int sleepFlag) /* Clear the internal flash bad bit - autoincrementing register, * so must do two writes. */ - CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, 0x3F000000); - diagRwData = CHIPREG_PIO_READ32(&ioc->pio_chip->DiagRwData); - diagRwData |= 0x4000000; - CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, 0x3F000000); - CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwData, diagRwData); + if (ioc->bus_type == SCSI) { + /* + * 1030 and 1035 H/W errata, workaround to access + * the ClearFlashBadSignatureBit + */ + CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, 0x3F000000); + diagRwData = CHIPREG_PIO_READ32(&ioc->pio_chip->DiagRwData); + diagRwData |= 0x40000000; + CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, 0x3F000000); + CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwData, diagRwData); + + } else /* if((ioc->bus_type == SAS) || (ioc->bus_type == FC)) */ { + diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic); + CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val | + MPI_DIAG_CLEAR_FLASH_BAD_SIG); + + /* wait 1 msec */ + if (sleepFlag == CAN_SLEEP) { + msleep_interruptible (1); + } else { + mdelay (1); + } + } if (ioc->errata_flag_1064) pci_disable_io_access(ioc->pcidev); diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic); - ddlprintk((MYIOC_s_INFO_FMT "downloadboot diag0val=%x, turning off PREVENT_IOC_BOOT, DISABLE_ARM\n", + ddlprintk((MYIOC_s_INFO_FMT "downloadboot diag0val=%x, " + "turning off PREVENT_IOC_BOOT, DISABLE_ARM, RW_ENABLE\n", ioc->name, diag0val)); - diag0val &= ~(MPI_DIAG_PREVENT_IOC_BOOT | MPI_DIAG_DISABLE_ARM); + diag0val &= ~(MPI_DIAG_PREVENT_IOC_BOOT | MPI_DIAG_DISABLE_ARM | MPI_DIAG_RW_ENABLE); ddlprintk((MYIOC_s_INFO_FMT "downloadboot now diag0val=%x\n", ioc->name, diag0val)); CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val); @@ -2812,10 +3023,23 @@ mpt_downloadboot(MPT_ADAPTER *ioc, int sleepFlag) /* Write 0xFF to reset the sequencer */ CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF); + if (ioc->bus_type == SAS) { + ioc_state = mpt_GetIocState(ioc, 0); + if ( (GetIocFacts(ioc, sleepFlag, + MPT_HOSTEVENT_IOC_BRINGUP)) != 0 ) { + ddlprintk((MYIOC_s_INFO_FMT "GetIocFacts failed: IocState=%x\n", + ioc->name, ioc_state)); + return -EFAULT; + } + } + for (count=0; count<HZ*20; count++) { if ((ioc_state = mpt_GetIocState(ioc, 0)) & MPI_IOC_STATE_READY) { ddlprintk((MYIOC_s_INFO_FMT "downloadboot successful! (count=%d) IocState=%x\n", ioc->name, count, ioc_state)); + if (ioc->bus_type == SAS) { + return 0; + } if ((SendIocInit(ioc, sleepFlag)) != 0) { ddlprintk((MYIOC_s_INFO_FMT "downloadboot: SendIocInit failed\n", ioc->name)); @@ -3049,12 +3273,13 @@ mpt_diag_reset(MPT_ADAPTER *ioc, int ignore, int sleepFlag) /* wait 1 sec */ if (sleepFlag == CAN_SLEEP) { - ssleep(1); + msleep_interruptible (1000); } else { mdelay (1000); } } - if ((count = mpt_downloadboot(ioc, sleepFlag)) < 0) { + if ((count = mpt_downloadboot(ioc, + (MpiFwHeader_t *)ioc->cached_fw, sleepFlag)) < 0) { printk(KERN_WARNING MYNAM ": firmware downloadboot failure (%d)!\n", count); } @@ -3637,7 +3862,7 @@ WaitForDoorbellAck(MPT_ADAPTER *ioc, int howlong, int sleepFlag) int count = 0; u32 intstat=0; - cntdn = ((sleepFlag == CAN_SLEEP) ? HZ : 1000) * howlong; + cntdn = 1000 * howlong; if (sleepFlag == CAN_SLEEP) { while (--cntdn) { @@ -3687,7 +3912,7 @@ WaitForDoorbellInt(MPT_ADAPTER *ioc, int howlong, int sleepFlag) int count = 0; u32 intstat=0; - cntdn = ((sleepFlag == CAN_SLEEP) ? HZ : 1000) * howlong; + cntdn = 1000 * howlong; if (sleepFlag == CAN_SLEEP) { while (--cntdn) { intstat = CHIPREG_READ32(&ioc->chip->IntStatus); @@ -4001,6 +4226,85 @@ GetFcPortPage0(MPT_ADAPTER *ioc, int portnum) /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ /* + * mptbase_sas_persist_operation - Perform operation on SAS Persitent Table + * @ioc: Pointer to MPT_ADAPTER structure + * @sas_address: 64bit SAS Address for operation. + * @target_id: specified target for operation + * @bus: specified bus for operation + * @persist_opcode: see below + * + * MPI_SAS_OP_CLEAR_NOT_PRESENT - Free all persist TargetID mappings for + * devices not currently present. + * MPI_SAS_OP_CLEAR_ALL_PERSISTENT - Clear al persist TargetID mappings + * + * NOTE: Don't use not this function during interrupt time. + * + * Returns: 0 for success, non-zero error + */ + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +int +mptbase_sas_persist_operation(MPT_ADAPTER *ioc, u8 persist_opcode) +{ + SasIoUnitControlRequest_t *sasIoUnitCntrReq; + SasIoUnitControlReply_t *sasIoUnitCntrReply; + MPT_FRAME_HDR *mf = NULL; + MPIHeader_t *mpi_hdr; + + + /* insure garbage is not sent to fw */ + switch(persist_opcode) { + + case MPI_SAS_OP_CLEAR_NOT_PRESENT: + case MPI_SAS_OP_CLEAR_ALL_PERSISTENT: + break; + + default: + return -1; + break; + } + + printk("%s: persist_opcode=%x\n",__FUNCTION__, persist_opcode); + + /* Get a MF for this command. + */ + if ((mf = mpt_get_msg_frame(mpt_base_index, ioc)) == NULL) { + printk("%s: no msg frames!\n",__FUNCTION__); + return -1; + } + + mpi_hdr = (MPIHeader_t *) mf; + sasIoUnitCntrReq = (SasIoUnitControlRequest_t *)mf; + memset(sasIoUnitCntrReq,0,sizeof(SasIoUnitControlRequest_t)); + sasIoUnitCntrReq->Function = MPI_FUNCTION_SAS_IO_UNIT_CONTROL; + sasIoUnitCntrReq->MsgContext = mpi_hdr->MsgContext; + sasIoUnitCntrReq->Operation = persist_opcode; + + init_timer(&ioc->persist_timer); + ioc->persist_timer.data = (unsigned long) ioc; + ioc->persist_timer.function = mpt_timer_expired; + ioc->persist_timer.expires = jiffies + HZ*10 /* 10 sec */; + ioc->persist_wait_done=0; + add_timer(&ioc->persist_timer); + mpt_put_msg_frame(mpt_base_index, ioc, mf); + wait_event(mpt_waitq, ioc->persist_wait_done); + + sasIoUnitCntrReply = + (SasIoUnitControlReply_t *)ioc->persist_reply_frame; + if (le16_to_cpu(sasIoUnitCntrReply->IOCStatus) != MPI_IOCSTATUS_SUCCESS) { + printk("%s: IOCStatus=0x%X IOCLogInfo=0x%X\n", + __FUNCTION__, + sasIoUnitCntrReply->IOCStatus, + sasIoUnitCntrReply->IOCLogInfo); + return -1; + } + + printk("%s: success\n",__FUNCTION__); + return 0; +} + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +/* * GetIoUnitPage2 - Retrieve BIOS version and boot order information. * @ioc: Pointer to MPT_ADAPTER structure * @@ -4340,10 +4644,10 @@ mpt_findImVolumes(MPT_ADAPTER *ioc) if (mpt_config(ioc, &cfg) != 0) goto done_and_free; - if ( (mem = (u8 *)ioc->spi_data.pIocPg2) == NULL ) { + if ( (mem = (u8 *)ioc->raid_data.pIocPg2) == NULL ) { mem = kmalloc(iocpage2sz, GFP_ATOMIC); if (mem) { - ioc->spi_data.pIocPg2 = (IOCPage2_t *) mem; + ioc->raid_data.pIocPg2 = (IOCPage2_t *) mem; } else { goto done_and_free; } @@ -4360,7 +4664,7 @@ mpt_findImVolumes(MPT_ADAPTER *ioc) /* At least 1 RAID Volume */ pIocRv = pIoc2->RaidVolume; - ioc->spi_data.isRaid = 0; + ioc->raid_data.isRaid = 0; for (jj = 0; jj < nVols; jj++, pIocRv++) { vid = pIocRv->VolumeID; vbus = pIocRv->VolumeBus; @@ -4369,7 +4673,7 @@ mpt_findImVolumes(MPT_ADAPTER *ioc) /* find the match */ if (vbus == 0) { - ioc->spi_data.isRaid |= (1 << vid); + ioc->raid_data.isRaid |= (1 << vid); } else { /* Error! Always bus 0 */ @@ -4404,8 +4708,8 @@ mpt_read_ioc_pg_3(MPT_ADAPTER *ioc) /* Free the old page */ - kfree(ioc->spi_data.pIocPg3); - ioc->spi_data.pIocPg3 = NULL; + kfree(ioc->raid_data.pIocPg3); + ioc->raid_data.pIocPg3 = NULL; /* There is at least one physical disk. * Read and save IOC Page 3 @@ -4442,7 +4746,7 @@ mpt_read_ioc_pg_3(MPT_ADAPTER *ioc) mem = kmalloc(iocpage3sz, GFP_ATOMIC); if (mem) { memcpy(mem, (u8 *)pIoc3, iocpage3sz); - ioc->spi_data.pIocPg3 = (IOCPage3_t *) mem; + ioc->raid_data.pIocPg3 = (IOCPage3_t *) mem; } } @@ -5366,8 +5670,8 @@ mpt_HardResetHandler(MPT_ADAPTER *ioc, int sleepFlag) } /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ -static char * -EventDescriptionStr(u8 event, u32 evData0) +static void +EventDescriptionStr(u8 event, u32 evData0, char *evStr) { char *ds; @@ -5420,8 +5724,95 @@ EventDescriptionStr(u8 event, u32 evData0) ds = "Events(OFF) Change"; break; case MPI_EVENT_INTEGRATED_RAID: - ds = "Integrated Raid"; + { + u8 ReasonCode = (u8)(evData0 >> 16); + switch (ReasonCode) { + case MPI_EVENT_RAID_RC_VOLUME_CREATED : + ds = "Integrated Raid: Volume Created"; + break; + case MPI_EVENT_RAID_RC_VOLUME_DELETED : + ds = "Integrated Raid: Volume Deleted"; + break; + case MPI_EVENT_RAID_RC_VOLUME_SETTINGS_CHANGED : + ds = "Integrated Raid: Volume Settings Changed"; + break; + case MPI_EVENT_RAID_RC_VOLUME_STATUS_CHANGED : + ds = "Integrated Raid: Volume Status Changed"; + break; + case MPI_EVENT_RAID_RC_VOLUME_PHYSDISK_CHANGED : + ds = "Integrated Raid: Volume Physdisk Changed"; + break; + case MPI_EVENT_RAID_RC_PHYSDISK_CREATED : + ds = "Integrated Raid: Physdisk Created"; + break; + case MPI_EVENT_RAID_RC_PHYSDISK_DELETED : + ds = "Integrated Raid: Physdisk Deleted"; + break; + case MPI_EVENT_RAID_RC_PHYSDISK_SETTINGS_CHANGED : + ds = "Integrated Raid: Physdisk Settings Changed"; + break; + case MPI_EVENT_RAID_RC_PHYSDISK_STATUS_CHANGED : + ds = "Integrated Raid: Physdisk Status Changed"; + break; + case MPI_EVENT_RAID_RC_DOMAIN_VAL_NEEDED : + ds = "Integrated Raid: Domain Validation Needed"; + break; + case MPI_EVENT_RAID_RC_SMART_DATA : + ds = "Integrated Raid; Smart Data"; + break; + case MPI_EVENT_RAID_RC_REPLACE_ACTION_STARTED : + ds = "Integrated Raid: Replace Action Started"; + break; + default: + ds = "Integrated Raid"; + break; + } + break; + } + case MPI_EVENT_SCSI_DEVICE_STATUS_CHANGE: + ds = "SCSI Device Status Change"; + break; + case MPI_EVENT_SAS_DEVICE_STATUS_CHANGE: + { + u8 ReasonCode = (u8)(evData0 >> 16); + switch (ReasonCode) { + case MPI_EVENT_SAS_DEV_STAT_RC_ADDED: + ds = "SAS Device Status Change: Added"; + break; + case MPI_EVENT_SAS_DEV_STAT_RC_NOT_RESPONDING: + ds = "SAS Device Status Change: Deleted"; + break; + case MPI_EVENT_SAS_DEV_STAT_RC_SMART_DATA: + ds = "SAS Device Status Change: SMART Data"; + break; + case MPI_EVENT_SAS_DEV_STAT_RC_NO_PERSIST_ADDED: + ds = "SAS Device Status Change: No Persistancy Added"; + break; + default: + ds = "SAS Device Status Change: Unknown"; + break; + } + break; + } + case MPI_EVENT_ON_BUS_TIMER_EXPIRED: + ds = "Bus Timer Expired"; + break; + case MPI_EVENT_QUEUE_FULL: + ds = "Queue Full"; + break; + case MPI_EVENT_SAS_SES: + ds = "SAS SES Event"; + break; + case MPI_EVENT_PERSISTENT_TABLE_FULL: + ds = "Persistent Table Full"; + break; + case MPI_EVENT_SAS_PHY_LINK_STATUS: + ds = "SAS PHY Link Status"; + break; + case MPI_EVENT_SAS_DISCOVERY_ERROR: + ds = "SAS Discovery Error"; break; + /* * MPT base "custom" events may be added here... */ @@ -5429,7 +5820,7 @@ EventDescriptionStr(u8 event, u32 evData0) ds = "Unknown"; break; } - return ds; + strcpy(evStr,ds); } /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ @@ -5451,7 +5842,7 @@ ProcessEventNotification(MPT_ADAPTER *ioc, EventNotificationReply_t *pEventReply int ii; int r = 0; int handlers = 0; - char *evStr; + char evStr[100]; u8 event; /* @@ -5464,7 +5855,7 @@ ProcessEventNotification(MPT_ADAPTER *ioc, EventNotificationReply_t *pEventReply evData0 = le32_to_cpu(pEventReply->Data[0]); } - evStr = EventDescriptionStr(event, evData0); + EventDescriptionStr(event, evData0, evStr); devtprintk((MYIOC_s_INFO_FMT "MPT event (%s=%02Xh) detected!\n", ioc->name, evStr, @@ -5481,20 +5872,6 @@ ProcessEventNotification(MPT_ADAPTER *ioc, EventNotificationReply_t *pEventReply * Do general / base driver event processing */ switch(event) { - case MPI_EVENT_NONE: /* 00 */ - case MPI_EVENT_LOG_DATA: /* 01 */ - case MPI_EVENT_STATE_CHANGE: /* 02 */ - case MPI_EVENT_UNIT_ATTENTION: /* 03 */ - case MPI_EVENT_IOC_BUS_RESET: /* 04 */ - case MPI_EVENT_EXT_BUS_RESET: /* 05 */ - case MPI_EVENT_RESCAN: /* 06 */ - case MPI_EVENT_LINK_STATUS_CHANGE: /* 07 */ - case MPI_EVENT_LOOP_STATE_CHANGE: /* 08 */ - case MPI_EVENT_LOGOUT: /* 09 */ - case MPI_EVENT_INTEGRATED_RAID: /* 0B */ - case MPI_EVENT_SCSI_DEVICE_STATUS_CHANGE: /* 0C */ - default: - break; case MPI_EVENT_EVENT_CHANGE: /* 0A */ if (evDataLen) { u8 evState = evData0 & 0xFF; @@ -5507,6 +5884,8 @@ ProcessEventNotification(MPT_ADAPTER *ioc, EventNotificationReply_t *pEventReply } } break; + default: + break; } /* @@ -5653,6 +6032,111 @@ mpt_sp_log_info(MPT_ADAPTER *ioc, u32 log_info) printk(MYIOC_s_INFO_FMT "LogInfo(0x%08x): F/W: %s\n", ioc->name, log_info, desc); } +/* strings for sas loginfo */ + static char *originator_str[] = { + "IOP", /* 00h */ + "PL", /* 01h */ + "IR" /* 02h */ + }; + static char *iop_code_str[] = { + NULL, /* 00h */ + "Invalid SAS Address", /* 01h */ + NULL, /* 02h */ + "Invalid Page", /* 03h */ + NULL, /* 04h */ + "Task Terminated" /* 05h */ + }; + static char *pl_code_str[] = { + NULL, /* 00h */ + "Open Failure", /* 01h */ + "Invalid Scatter Gather List", /* 02h */ + "Wrong Relative Offset or Frame Length", /* 03h */ + "Frame Transfer Error", /* 04h */ + "Transmit Frame Connected Low", /* 05h */ + "SATA Non-NCQ RW Error Bit Set", /* 06h */ + "SATA Read Log Receive Data Error", /* 07h */ + "SATA NCQ Fail All Commands After Error", /* 08h */ + "SATA Error in Receive Set Device Bit FIS", /* 09h */ + "Receive Frame Invalid Message", /* 0Ah */ + "Receive Context Message Valid Error", /* 0Bh */ + "Receive Frame Current Frame Error", /* 0Ch */ + "SATA Link Down", /* 0Dh */ + "Discovery SATA Init W IOS", /* 0Eh */ + "Config Invalid Page", /* 0Fh */ + "Discovery SATA Init Timeout", /* 10h */ + "Reset", /* 11h */ + "Abort", /* 12h */ + "IO Not Yet Executed", /* 13h */ + "IO Executed", /* 14h */ + NULL, /* 15h */ + NULL, /* 16h */ + NULL, /* 17h */ + NULL, /* 18h */ + NULL, /* 19h */ + NULL, /* 1Ah */ + NULL, /* 1Bh */ + NULL, /* 1Ch */ + NULL, /* 1Dh */ + NULL, /* 1Eh */ + NULL, /* 1Fh */ + "Enclosure Management" /* 20h */ + }; + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +/* + * mpt_sas_log_info - Log information returned from SAS IOC. + * @ioc: Pointer to MPT_ADAPTER structure + * @log_info: U32 LogInfo reply word from the IOC + * + * Refer to lsi/mpi_log_sas.h. + */ +static void +mpt_sas_log_info(MPT_ADAPTER *ioc, u32 log_info) +{ +union loginfo_type { + u32 loginfo; + struct { + u32 subcode:16; + u32 code:8; + u32 originator:4; + u32 bus_type:4; + }dw; +}; + union loginfo_type sas_loginfo; + char *code_desc = NULL; + + sas_loginfo.loginfo = log_info; + if ((sas_loginfo.dw.bus_type != 3 /*SAS*/) && + (sas_loginfo.dw.originator < sizeof(originator_str)/sizeof(char*))) + return; + if ((sas_loginfo.dw.originator == 0 /*IOP*/) && + (sas_loginfo.dw.code < sizeof(iop_code_str)/sizeof(char*))) { + code_desc = iop_code_str[sas_loginfo.dw.code]; + }else if ((sas_loginfo.dw.originator == 1 /*PL*/) && + (sas_loginfo.dw.code < sizeof(pl_code_str)/sizeof(char*) )) { + code_desc = pl_code_str[sas_loginfo.dw.code]; + } + + if (code_desc != NULL) + printk(MYIOC_s_INFO_FMT + "LogInfo(0x%08x): Originator={%s}, Code={%s}," + " SubCode(0x%04x)\n", + ioc->name, + log_info, + originator_str[sas_loginfo.dw.originator], + code_desc, + sas_loginfo.dw.subcode); + else + printk(MYIOC_s_INFO_FMT + "LogInfo(0x%08x): Originator={%s}, Code=(0x%02x)," + " SubCode(0x%04x)\n", + ioc->name, + log_info, + originator_str[sas_loginfo.dw.originator], + sas_loginfo.dw.code, + sas_loginfo.dw.subcode); +} + /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ /* * mpt_sp_ioc_info - IOC information returned from SCSI Parallel IOC. @@ -5814,6 +6298,7 @@ EXPORT_SYMBOL(mpt_findImVolumes); EXPORT_SYMBOL(mpt_read_ioc_pg_3); EXPORT_SYMBOL(mpt_alloc_fw_memory); EXPORT_SYMBOL(mpt_free_fw_memory); +EXPORT_SYMBOL(mptbase_sas_persist_operation); /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ diff --git a/drivers/message/fusion/mptbase.h b/drivers/message/fusion/mptbase.h index f4827d9..7510527 100644 --- a/drivers/message/fusion/mptbase.h +++ b/drivers/message/fusion/mptbase.h @@ -65,6 +65,7 @@ #include "lsi/mpi_fc.h" /* Fibre Channel (lowlevel) support */ #include "lsi/mpi_targ.h" /* SCSI/FCP Target protcol support */ #include "lsi/mpi_tool.h" /* Tools support */ +#include "lsi/mpi_sas.h" /* SAS support */ /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ @@ -76,8 +77,8 @@ #define COPYRIGHT "Copyright (c) 1999-2005 " MODULEAUTHOR #endif -#define MPT_LINUX_VERSION_COMMON "3.03.02" -#define MPT_LINUX_PACKAGE_NAME "@(#)mptlinux-3.03.02" +#define MPT_LINUX_VERSION_COMMON "3.03.03" +#define MPT_LINUX_PACKAGE_NAME "@(#)mptlinux-3.03.03" #define WHAT_MAGIC_STRING "@" "(" "#" ")" #define show_mptmod_ver(s,ver) \ @@ -423,7 +424,7 @@ typedef struct _MPT_IOCTL { /* * Event Structure and define */ -#define MPTCTL_EVENT_LOG_SIZE (0x0000000A) +#define MPTCTL_EVENT_LOG_SIZE (0x000000032) typedef struct _mpt_ioctl_events { u32 event; /* Specified by define above */ u32 eventContext; /* Index or counter */ @@ -451,16 +452,13 @@ typedef struct _mpt_ioctl_events { #define MPT_SCSICFG_ALL_IDS 0x02 /* WriteSDP1 to all IDS */ /* #define MPT_SCSICFG_BLK_NEGO 0x10 WriteSDP1 with WDTR and SDTR disabled */ -typedef struct _ScsiCfgData { +typedef struct _SpiCfgData { u32 PortFlags; int *nvram; /* table of device NVRAM values */ - IOCPage2_t *pIocPg2; /* table of Raid Volumes */ - IOCPage3_t *pIocPg3; /* table of physical disks */ IOCPage4_t *pIocPg4; /* SEP devices addressing */ dma_addr_t IocPg4_dma; /* Phys Addr of IOCPage4 data */ int IocPg4Sz; /* IOCPage4 size */ u8 dvStatus[MPT_MAX_SCSI_DEVICES]; - int isRaid; /* bit field, 1 if RAID */ u8 minSyncFactor; /* 0xFF if async */ u8 maxSyncOffset; /* 0 if async */ u8 maxBusWidth; /* 0 if narrow, 1 if wide */ @@ -472,10 +470,28 @@ typedef struct _ScsiCfgData { u8 dvScheduled; /* 1 if scheduled */ u8 forceDv; /* 1 to force DV scheduling */ u8 noQas; /* Disable QAS for this adapter */ - u8 Saf_Te; /* 1 to force all Processors as SAF-TE if Inquiry data length is too short to check for SAF-TE */ + u8 Saf_Te; /* 1 to force all Processors as + * SAF-TE if Inquiry data length + * is too short to check for SAF-TE + */ u8 mpt_dv; /* command line option: enhanced=1, basic=0 */ + u8 bus_reset; /* 1 to allow bus reset */ u8 rsvd[1]; -} ScsiCfgData; +}SpiCfgData; + +typedef struct _SasCfgData { + u8 ptClear; /* 1 to automatically clear the + * persistent table. + * 0 to disable + * automatic clearing. + */ +}SasCfgData; + +typedef struct _RaidCfgData { + IOCPage2_t *pIocPg2; /* table of Raid Volumes */ + IOCPage3_t *pIocPg3; /* table of physical disks */ + int isRaid; /* bit field, 1 if RAID */ +}RaidCfgData; /* * Adapter Structure - pci_dev specific. Maximum: MPT_MAX_ADAPTERS @@ -530,11 +546,16 @@ typedef struct _MPT_ADAPTER u8 *sense_buf_pool; dma_addr_t sense_buf_pool_dma; u32 sense_buf_low_dma; + u8 *HostPageBuffer; /* SAS - host page buffer support */ + u32 HostPageBuffer_sz; + dma_addr_t HostPageBuffer_dma; int mtrr_reg; struct pci_dev *pcidev; /* struct pci_dev pointer */ u8 __iomem *memmap; /* mmap address */ struct Scsi_Host *sh; /* Scsi Host pointer */ - ScsiCfgData spi_data; /* Scsi config. data */ + SpiCfgData spi_data; /* Scsi config. data */ + RaidCfgData raid_data; /* Raid config. data */ + SasCfgData sas_data; /* Sas config. data */ MPT_IOCTL *ioctl; /* ioctl data pointer */ struct proc_dir_entry *ioc_dentry; struct _MPT_ADAPTER *alt_ioc; /* ptr to 929 bound adapter port */ @@ -554,31 +575,35 @@ typedef struct _MPT_ADAPTER #else u32 mfcnt; #endif - u32 NB_for_64_byte_frame; + u32 NB_for_64_byte_frame; u32 hs_req[MPT_MAX_FRAME_SIZE/sizeof(u32)]; u16 hs_reply[MPT_MAX_FRAME_SIZE/sizeof(u16)]; IOCFactsReply_t facts; PortFactsReply_t pfacts[2]; FCPortPage0_t fc_port_page0[2]; + struct timer_list persist_timer; /* persist table timer */ + int persist_wait_done; /* persist completion flag */ + u8 persist_reply_frame[MPT_DEFAULT_FRAME_SIZE]; /* persist reply */ LANPage0_t lan_cnfg_page0; LANPage1_t lan_cnfg_page1; - /* + /* * Description: errata_flag_1064 * If a PCIX read occurs within 1 or 2 cycles after the chip receives * a split completion for a read data, an internal address pointer incorrectly * increments by 32 bytes */ - int errata_flag_1064; + int errata_flag_1064; u8 FirstWhoInit; u8 upload_fw; /* If set, do a fw upload */ u8 reload_fw; /* Force a FW Reload on next reset */ - u8 NBShiftFactor; /* NB Shift Factor based on Block Size (Facts) */ + u8 NBShiftFactor; /* NB Shift Factor based on Block Size (Facts) */ u8 pad1[4]; int DoneCtx; int TaskCtx; int InternalCtx; - struct list_head list; + struct list_head list; struct net_device *netdev; + struct list_head sas_topology; } MPT_ADAPTER; /* @@ -964,6 +989,7 @@ extern void mpt_alloc_fw_memory(MPT_ADAPTER *ioc, int size); extern void mpt_free_fw_memory(MPT_ADAPTER *ioc); extern int mpt_findImVolumes(MPT_ADAPTER *ioc); extern int mpt_read_ioc_pg_3(MPT_ADAPTER *ioc); +extern int mptbase_sas_persist_operation(MPT_ADAPTER *ioc, u8 persist_opcode); /* * Public data decl's... diff --git a/drivers/message/fusion/mptctl.c b/drivers/message/fusion/mptctl.c index 7577c24..cb2d59d 100644 --- a/drivers/message/fusion/mptctl.c +++ b/drivers/message/fusion/mptctl.c @@ -1326,7 +1326,7 @@ mptctl_gettargetinfo (unsigned long arg) */ if (hd && hd->Targets) { mpt_findImVolumes(ioc); - pIoc2 = ioc->spi_data.pIocPg2; + pIoc2 = ioc->raid_data.pIocPg2; for ( id = 0; id <= max_id; ) { if ( pIoc2 && pIoc2->NumActiveVolumes ) { if ( id == pIoc2->RaidVolume[0].VolumeID ) { @@ -1348,7 +1348,7 @@ mptctl_gettargetinfo (unsigned long arg) --maxWordsLeft; goto next_id; } else { - pIoc3 = ioc->spi_data.pIocPg3; + pIoc3 = ioc->raid_data.pIocPg3; for ( jj = 0; jj < pIoc3->NumPhysDisks; jj++ ) { if ( pIoc3->PhysDisk[jj].PhysDiskID == id ) goto next_id; diff --git a/drivers/message/fusion/mptfc.c b/drivers/message/fusion/mptfc.c index 13771ab..a628be9 100644 --- a/drivers/message/fusion/mptfc.c +++ b/drivers/message/fusion/mptfc.c @@ -189,7 +189,7 @@ mptfc_probe(struct pci_dev *pdev, const struct pci_device_id *id) printk(MYIOC_s_WARN_FMT "Skipping ioc=%p because SCSI Initiator mode is NOT enabled!\n", ioc->name, ioc); - return -ENODEV; + return 0; } sh = scsi_host_alloc(&mptfc_driver_template, sizeof(MPT_SCSI_HOST)); diff --git a/drivers/message/fusion/mptlan.c b/drivers/message/fusion/mptlan.c index 52794be..ed3c891 100644 --- a/drivers/message/fusion/mptlan.c +++ b/drivers/message/fusion/mptlan.c @@ -312,7 +312,12 @@ static int mpt_lan_ioc_reset(MPT_ADAPTER *ioc, int reset_phase) { struct net_device *dev = ioc->netdev; - struct mpt_lan_priv *priv = netdev_priv(dev); + struct mpt_lan_priv *priv; + + if (dev == NULL) + return(1); + else + priv = netdev_priv(dev); dlprintk((KERN_INFO MYNAM ": IOC %s_reset routed to LAN driver!\n", reset_phase==MPT_IOC_SETUP_RESET ? "setup" : ( diff --git a/drivers/message/fusion/mptsas.c b/drivers/message/fusion/mptsas.c new file mode 100644 index 0000000..429820e --- /dev/null +++ b/drivers/message/fusion/mptsas.c @@ -0,0 +1,1235 @@ +/* + * linux/drivers/message/fusion/mptsas.c + * For use with LSI Logic PCI chip/adapter(s) + * running LSI Logic Fusion MPT (Message Passing Technology) firmware. + * + * Copyright (c) 1999-2005 LSI Logic Corporation + * (mailto:mpt_linux_developer@lsil.com) + * Copyright (c) 2005 Dell + */ +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +/* + This 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 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. + + NO WARRANTY + THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR + CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT + LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, + MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is + solely responsible for determining the appropriateness of using and + distributing the Program and assumes all risks associated with its + exercise of rights under this Agreement, including but not limited to + the risks and costs of program errors, damage to or loss of data, + programs or equipment, and unavailability or interruption of operations. + + DISCLAIMER OF LIABILITY + NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY + DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), 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 OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED + HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES + + 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 <linux/module.h> +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/errno.h> +#include <linux/sched.h> +#include <linux/workqueue.h> + +#include <scsi/scsi_cmnd.h> +#include <scsi/scsi_device.h> +#include <scsi/scsi_host.h> +#include <scsi/scsi_transport_sas.h> + +#include "mptbase.h" +#include "mptscsih.h" + + +#define my_NAME "Fusion MPT SAS Host driver" +#define my_VERSION MPT_LINUX_VERSION_COMMON +#define MYNAM "mptsas" + +MODULE_AUTHOR(MODULEAUTHOR); +MODULE_DESCRIPTION(my_NAME); +MODULE_LICENSE("GPL"); + +static int mpt_pq_filter; +module_param(mpt_pq_filter, int, 0); +MODULE_PARM_DESC(mpt_pq_filter, + "Enable peripheral qualifier filter: enable=1 " + "(default=0)"); + +static int mpt_pt_clear; +module_param(mpt_pt_clear, int, 0); +MODULE_PARM_DESC(mpt_pt_clear, + "Clear persistency table: enable=1 " + "(default=MPTSCSIH_PT_CLEAR=0)"); + +static int mptsasDoneCtx = -1; +static int mptsasTaskCtx = -1; +static int mptsasInternalCtx = -1; /* Used only for internal commands */ + + +/* + * SAS topology structures + * + * The MPT Fusion firmware interface spreads information about the + * SAS topology over many manufacture pages, thus we need some data + * structure to collect it and process it for the SAS transport class. + */ + +struct mptsas_devinfo { + u16 handle; /* unique id to address this device */ + u8 phy_id; /* phy number of parent device */ + u8 port_id; /* sas physical port this device + is assoc'd with */ + u8 target; /* logical target id of this device */ + u8 bus; /* logical bus number of this device */ + u64 sas_address; /* WWN of this device, + SATA is assigned by HBA,expander */ + u32 device_info; /* bitfield detailed info about this device */ +}; + +struct mptsas_phyinfo { + u8 phy_id; /* phy index */ + u8 port_id; /* port number this phy is part of */ + u8 negotiated_link_rate; /* nego'd link rate for this phy */ + u8 hw_link_rate; /* hardware max/min phys link rate */ + u8 programmed_link_rate; /* programmed max/min phy link rate */ + struct mptsas_devinfo identify; /* point to phy device info */ + struct mptsas_devinfo attached; /* point to attached device info */ + struct sas_rphy *rphy; +}; + +struct mptsas_portinfo { + struct list_head list; + u16 handle; /* unique id to address this */ + u8 num_phys; /* number of phys */ + struct mptsas_phyinfo *phy_info; +}; + +/* + * This is pretty ugly. We will be able to seriously clean it up + * once the DV code in mptscsih goes away and we can properly + * implement ->target_alloc. + */ +static int +mptsas_slave_alloc(struct scsi_device *device) +{ + struct Scsi_Host *host = device->host; + MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)host->hostdata; + struct sas_rphy *rphy; + struct mptsas_portinfo *p; + VirtDevice *vdev; + uint target = device->id; + int i; + + if ((vdev = hd->Targets[target]) != NULL) + goto out; + + vdev = kmalloc(sizeof(VirtDevice), GFP_KERNEL); + if (!vdev) { + printk(MYIOC_s_ERR_FMT "slave_alloc kmalloc(%zd) FAILED!\n", + hd->ioc->name, sizeof(VirtDevice)); + return -ENOMEM; + } + + memset(vdev, 0, sizeof(VirtDevice)); + vdev->tflags = MPT_TARGET_FLAGS_Q_YES|MPT_TARGET_FLAGS_VALID_INQUIRY; + vdev->ioc_id = hd->ioc->id; + + rphy = dev_to_rphy(device->sdev_target->dev.parent); + list_for_each_entry(p, &hd->ioc->sas_topology, list) { + for (i = 0; i < p->num_phys; i++) { + if (p->phy_info[i].attached.sas_address == + rphy->identify.sas_address) { + vdev->target_id = + p->phy_info[i].attached.target; + vdev->bus_id = p->phy_info[i].attached.bus; + hd->Targets[device->id] = vdev; + goto out; + } + } + } + + printk("No matching SAS device found!!\n"); + kfree(vdev); + return -ENODEV; + + out: + vdev->num_luns++; + device->hostdata = vdev; + return 0; +} + +static struct scsi_host_template mptsas_driver_template = { + .proc_name = "mptsas", + .proc_info = mptscsih_proc_info, + .name = "MPT SPI Host", + .info = mptscsih_info, + .queuecommand = mptscsih_qcmd, + .slave_alloc = mptsas_slave_alloc, + .slave_configure = mptscsih_slave_configure, + .slave_destroy = mptscsih_slave_destroy, + .change_queue_depth = mptscsih_change_queue_depth, + .eh_abort_handler = mptscsih_abort, + .eh_device_reset_handler = mptscsih_dev_reset, + .eh_bus_reset_handler = mptscsih_bus_reset, + .eh_host_reset_handler = mptscsih_host_reset, + .bios_param = mptscsih_bios_param, + .can_queue = MPT_FC_CAN_QUEUE, + .this_id = -1, + .sg_tablesize = MPT_SCSI_SG_DEPTH, + .max_sectors = 8192, + .cmd_per_lun = 7, + .use_clustering = ENABLE_CLUSTERING, +}; + +static struct sas_function_template mptsas_transport_functions = { +}; + +static struct scsi_transport_template *mptsas_transport_template; + +#ifdef SASDEBUG +static void mptsas_print_phy_data(MPI_SAS_IO_UNIT0_PHY_DATA *phy_data) +{ + printk("---- IO UNIT PAGE 0 ------------\n"); + printk("Handle=0x%X\n", + le16_to_cpu(phy_data->AttachedDeviceHandle)); + printk("Controller Handle=0x%X\n", + le16_to_cpu(phy_data->ControllerDevHandle)); + printk("Port=0x%X\n", phy_data->Port); + printk("Port Flags=0x%X\n", phy_data->PortFlags); + printk("PHY Flags=0x%X\n", phy_data->PhyFlags); + printk("Negotiated Link Rate=0x%X\n", phy_data->NegotiatedLinkRate); + printk("Controller PHY Device Info=0x%X\n", + le32_to_cpu(phy_data->ControllerPhyDeviceInfo)); + printk("DiscoveryStatus=0x%X\n", + le32_to_cpu(phy_data->DiscoveryStatus)); + printk("\n"); +} + +static void mptsas_print_phy_pg0(SasPhyPage0_t *pg0) +{ + __le64 sas_address; + + memcpy(&sas_address, &pg0->SASAddress, sizeof(__le64)); + + printk("---- SAS PHY PAGE 0 ------------\n"); + printk("Attached Device Handle=0x%X\n", + le16_to_cpu(pg0->AttachedDevHandle)); + printk("SAS Address=0x%llX\n", + (unsigned long long)le64_to_cpu(sas_address)); + printk("Attached PHY Identifier=0x%X\n", pg0->AttachedPhyIdentifier); + printk("Attached Device Info=0x%X\n", + le32_to_cpu(pg0->AttachedDeviceInfo)); + printk("Programmed Link Rate=0x%X\n", pg0->ProgrammedLinkRate); + printk("Change Count=0x%X\n", pg0->ChangeCount); + printk("PHY Info=0x%X\n", le32_to_cpu(pg0->PhyInfo)); + printk("\n"); +} + +static void mptsas_print_device_pg0(SasDevicePage0_t *pg0) +{ + __le64 sas_address; + + memcpy(&sas_address, &pg0->SASAddress, sizeof(__le64)); + + printk("---- SAS DEVICE PAGE 0 ---------\n"); + printk("Handle=0x%X\n" ,le16_to_cpu(pg0->DevHandle)); + printk("Enclosure Handle=0x%X\n", le16_to_cpu(pg0->EnclosureHandle)); + printk("Slot=0x%X\n", le16_to_cpu(pg0->Slot)); + printk("SAS Address=0x%llX\n", le64_to_cpu(sas_address)); + printk("Target ID=0x%X\n", pg0->TargetID); + printk("Bus=0x%X\n", pg0->Bus); + printk("PhyNum=0x%X\n", pg0->PhyNum); + printk("AccessStatus=0x%X\n", le16_to_cpu(pg0->AccessStatus)); + printk("Device Info=0x%X\n", le32_to_cpu(pg0->DeviceInfo)); + printk("Flags=0x%X\n", le16_to_cpu(pg0->Flags)); + printk("Physical Port=0x%X\n", pg0->PhysicalPort); + printk("\n"); +} + +static void mptsas_print_expander_pg1(SasExpanderPage1_t *pg1) +{ + printk("---- SAS EXPANDER PAGE 1 ------------\n"); + + printk("Physical Port=0x%X\n", pg1->PhysicalPort); + printk("PHY Identifier=0x%X\n", pg1->Phy); + printk("Negotiated Link Rate=0x%X\n", pg1->NegotiatedLinkRate); + printk("Programmed Link Rate=0x%X\n", pg1->ProgrammedLinkRate); + printk("Hardware Link Rate=0x%X\n", pg1->HwLinkRate); + printk("Owner Device Handle=0x%X\n", + le16_to_cpu(pg1->OwnerDevHandle)); + printk("Attached Device Handle=0x%X\n", + le16_to_cpu(pg1->AttachedDevHandle)); +} +#else +#define mptsas_print_phy_data(phy_data) do { } while (0) +#define mptsas_print_phy_pg0(pg0) do { } while (0) +#define mptsas_print_device_pg0(pg0) do { } while (0) +#define mptsas_print_expander_pg1(pg1) do { } while (0) +#endif + +static int +mptsas_sas_io_unit_pg0(MPT_ADAPTER *ioc, struct mptsas_portinfo *port_info) +{ + ConfigExtendedPageHeader_t hdr; + CONFIGPARMS cfg; + SasIOUnitPage0_t *buffer; + dma_addr_t dma_handle; + int error, i; + + hdr.PageVersion = MPI_SASIOUNITPAGE0_PAGEVERSION; + hdr.ExtPageLength = 0; + hdr.PageNumber = 0; + hdr.Reserved1 = 0; + hdr.Reserved2 = 0; + hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED; + hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_IO_UNIT; + + cfg.cfghdr.ehdr = &hdr; + cfg.physAddr = -1; + cfg.pageAddr = 0; + cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER; + cfg.dir = 0; /* read */ + cfg.timeout = 10; + + error = mpt_config(ioc, &cfg); + if (error) + goto out; + if (!hdr.ExtPageLength) { + error = -ENXIO; + goto out; + } + + buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4, + &dma_handle); + if (!buffer) { + error = -ENOMEM; + goto out; + } + + cfg.physAddr = dma_handle; + cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT; + + error = mpt_config(ioc, &cfg); + if (error) + goto out_free_consistent; + + port_info->num_phys = buffer->NumPhys; + port_info->phy_info = kcalloc(port_info->num_phys, + sizeof(struct mptsas_phyinfo),GFP_KERNEL); + if (!port_info->phy_info) { + error = -ENOMEM; + goto out_free_consistent; + } + + for (i = 0; i < port_info->num_phys; i++) { + mptsas_print_phy_data(&buffer->PhyData[i]); + port_info->phy_info[i].phy_id = i; + port_info->phy_info[i].port_id = + buffer->PhyData[i].Port; + port_info->phy_info[i].negotiated_link_rate = + buffer->PhyData[i].NegotiatedLinkRate; + } + + out_free_consistent: + pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4, + buffer, dma_handle); + out: + return error; +} + +static int +mptsas_sas_phy_pg0(MPT_ADAPTER *ioc, struct mptsas_phyinfo *phy_info, + u32 form, u32 form_specific) +{ + ConfigExtendedPageHeader_t hdr; + CONFIGPARMS cfg; + SasPhyPage0_t *buffer; + dma_addr_t dma_handle; + int error; + + hdr.PageVersion = MPI_SASPHY0_PAGEVERSION; + hdr.ExtPageLength = 0; + hdr.PageNumber = 0; + hdr.Reserved1 = 0; + hdr.Reserved2 = 0; + hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED; + hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_PHY; + + cfg.cfghdr.ehdr = &hdr; + cfg.dir = 0; /* read */ + cfg.timeout = 10; + + /* Get Phy Pg 0 for each Phy. */ + cfg.physAddr = -1; + cfg.pageAddr = form + form_specific; + cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER; + + error = mpt_config(ioc, &cfg); + if (error) + goto out; + + if (!hdr.ExtPageLength) { + error = -ENXIO; + goto out; + } + + buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4, + &dma_handle); + if (!buffer) { + error = -ENOMEM; + goto out; + } + + cfg.physAddr = dma_handle; + cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT; + + error = mpt_config(ioc, &cfg); + if (error) + goto out_free_consistent; + + mptsas_print_phy_pg0(buffer); + + phy_info->hw_link_rate = buffer->HwLinkRate; + phy_info->programmed_link_rate = buffer->ProgrammedLinkRate; + phy_info->identify.handle = le16_to_cpu(buffer->OwnerDevHandle); + phy_info->attached.handle = le16_to_cpu(buffer->AttachedDevHandle); + + out_free_consistent: + pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4, + buffer, dma_handle); + out: + return error; +} + +static int +mptsas_sas_device_pg0(MPT_ADAPTER *ioc, struct mptsas_devinfo *device_info, + u32 form, u32 form_specific) +{ + ConfigExtendedPageHeader_t hdr; + CONFIGPARMS cfg; + SasDevicePage0_t *buffer; + dma_addr_t dma_handle; + __le64 sas_address; + int error; + + hdr.PageVersion = MPI_SASDEVICE0_PAGEVERSION; + hdr.ExtPageLength = 0; + hdr.PageNumber = 0; + hdr.Reserved1 = 0; + hdr.Reserved2 = 0; + hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED; + hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_DEVICE; + + cfg.cfghdr.ehdr = &hdr; + cfg.pageAddr = form + form_specific; + cfg.physAddr = -1; + cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER; + cfg.dir = 0; /* read */ + cfg.timeout = 10; + + error = mpt_config(ioc, &cfg); + if (error) + goto out; + if (!hdr.ExtPageLength) { + error = -ENXIO; + goto out; + } + + buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4, + &dma_handle); + if (!buffer) { + error = -ENOMEM; + goto out; + } + + cfg.physAddr = dma_handle; + cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT; + + error = mpt_config(ioc, &cfg); + if (error) + goto out_free_consistent; + + mptsas_print_device_pg0(buffer); + + device_info->handle = le16_to_cpu(buffer->DevHandle); + device_info->phy_id = buffer->PhyNum; + device_info->port_id = buffer->PhysicalPort; + device_info->target = buffer->TargetID; + device_info->bus = buffer->Bus; + memcpy(&sas_address, &buffer->SASAddress, sizeof(__le64)); + device_info->sas_address = le64_to_cpu(sas_address); + device_info->device_info = + le32_to_cpu(buffer->DeviceInfo); + + out_free_consistent: + pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4, + buffer, dma_handle); + out: + return error; +} + +static int +mptsas_sas_expander_pg0(MPT_ADAPTER *ioc, struct mptsas_portinfo *port_info, + u32 form, u32 form_specific) +{ + ConfigExtendedPageHeader_t hdr; + CONFIGPARMS cfg; + SasExpanderPage0_t *buffer; + dma_addr_t dma_handle; + int error; + + hdr.PageVersion = MPI_SASEXPANDER0_PAGEVERSION; + hdr.ExtPageLength = 0; + hdr.PageNumber = 0; + hdr.Reserved1 = 0; + hdr.Reserved2 = 0; + hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED; + hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_EXPANDER; + + cfg.cfghdr.ehdr = &hdr; + cfg.physAddr = -1; + cfg.pageAddr = form + form_specific; + cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER; + cfg.dir = 0; /* read */ + cfg.timeout = 10; + + error = mpt_config(ioc, &cfg); + if (error) + goto out; + + if (!hdr.ExtPageLength) { + error = -ENXIO; + goto out; + } + + buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4, + &dma_handle); + if (!buffer) { + error = -ENOMEM; + goto out; + } + + cfg.physAddr = dma_handle; + cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT; + + error = mpt_config(ioc, &cfg); + if (error) + goto out_free_consistent; + + /* save config data */ + port_info->num_phys = buffer->NumPhys; + port_info->handle = le16_to_cpu(buffer->DevHandle); + port_info->phy_info = kcalloc(port_info->num_phys, + sizeof(struct mptsas_phyinfo),GFP_KERNEL); + if (!port_info->phy_info) { + error = -ENOMEM; + goto out_free_consistent; + } + + out_free_consistent: + pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4, + buffer, dma_handle); + out: + return error; +} + +static int +mptsas_sas_expander_pg1(MPT_ADAPTER *ioc, struct mptsas_phyinfo *phy_info, + u32 form, u32 form_specific) +{ + ConfigExtendedPageHeader_t hdr; + CONFIGPARMS cfg; + SasExpanderPage1_t *buffer; + dma_addr_t dma_handle; + int error; + + hdr.PageVersion = MPI_SASEXPANDER0_PAGEVERSION; + hdr.ExtPageLength = 0; + hdr.PageNumber = 1; + hdr.Reserved1 = 0; + hdr.Reserved2 = 0; + hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED; + hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_EXPANDER; + + cfg.cfghdr.ehdr = &hdr; + cfg.physAddr = -1; + cfg.pageAddr = form + form_specific; + cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER; + cfg.dir = 0; /* read */ + cfg.timeout = 10; + + error = mpt_config(ioc, &cfg); + if (error) + goto out; + + if (!hdr.ExtPageLength) { + error = -ENXIO; + goto out; + } + + buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4, + &dma_handle); + if (!buffer) { + error = -ENOMEM; + goto out; + } + + cfg.physAddr = dma_handle; + cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT; + + error = mpt_config(ioc, &cfg); + if (error) + goto out_free_consistent; + + + mptsas_print_expander_pg1(buffer); + + /* save config data */ + phy_info->phy_id = buffer->Phy; + phy_info->port_id = buffer->PhysicalPort; + phy_info->negotiated_link_rate = buffer->NegotiatedLinkRate; + phy_info->programmed_link_rate = buffer->ProgrammedLinkRate; + phy_info->hw_link_rate = buffer->HwLinkRate; + phy_info->identify.handle = le16_to_cpu(buffer->OwnerDevHandle); + phy_info->attached.handle = le16_to_cpu(buffer->AttachedDevHandle); + + + out_free_consistent: + pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4, + buffer, dma_handle); + out: + return error; +} + +static void +mptsas_parse_device_info(struct sas_identify *identify, + struct mptsas_devinfo *device_info) +{ + u16 protocols; + + identify->sas_address = device_info->sas_address; + identify->phy_identifier = device_info->phy_id; + + /* + * Fill in Phy Initiator Port Protocol. + * Bits 6:3, more than one bit can be set, fall through cases. + */ + protocols = device_info->device_info & 0x78; + identify->initiator_port_protocols = 0; + if (protocols & MPI_SAS_DEVICE_INFO_SSP_INITIATOR) + identify->initiator_port_protocols |= SAS_PROTOCOL_SSP; + if (protocols & MPI_SAS_DEVICE_INFO_STP_INITIATOR) + identify->initiator_port_protocols |= SAS_PROTOCOL_STP; + if (protocols & MPI_SAS_DEVICE_INFO_SMP_INITIATOR) + identify->initiator_port_protocols |= SAS_PROTOCOL_SMP; + if (protocols & MPI_SAS_DEVICE_INFO_SATA_HOST) + identify->initiator_port_protocols |= SAS_PROTOCOL_SATA; + + /* + * Fill in Phy Target Port Protocol. + * Bits 10:7, more than one bit can be set, fall through cases. + */ + protocols = device_info->device_info & 0x780; + identify->target_port_protocols = 0; + if (protocols & MPI_SAS_DEVICE_INFO_SSP_TARGET) + identify->target_port_protocols |= SAS_PROTOCOL_SSP; + if (protocols & MPI_SAS_DEVICE_INFO_STP_TARGET) + identify->target_port_protocols |= SAS_PROTOCOL_STP; + if (protocols & MPI_SAS_DEVICE_INFO_SMP_TARGET) + identify->target_port_protocols |= SAS_PROTOCOL_SMP; + if (protocols & MPI_SAS_DEVICE_INFO_SATA_DEVICE) + identify->target_port_protocols |= SAS_PROTOCOL_SATA; + + /* + * Fill in Attached device type. + */ + switch (device_info->device_info & + MPI_SAS_DEVICE_INFO_MASK_DEVICE_TYPE) { + case MPI_SAS_DEVICE_INFO_NO_DEVICE: + identify->device_type = SAS_PHY_UNUSED; + break; + case MPI_SAS_DEVICE_INFO_END_DEVICE: + identify->device_type = SAS_END_DEVICE; + break; + case MPI_SAS_DEVICE_INFO_EDGE_EXPANDER: + identify->device_type = SAS_EDGE_EXPANDER_DEVICE; + break; + case MPI_SAS_DEVICE_INFO_FANOUT_EXPANDER: + identify->device_type = SAS_FANOUT_EXPANDER_DEVICE; + break; + } +} + +static int mptsas_probe_one_phy(struct device *dev, + struct mptsas_phyinfo *phy_info, int index) +{ + struct sas_phy *port; + int error; + + port = sas_phy_alloc(dev, index); + if (!port) + return -ENOMEM; + + port->port_identifier = phy_info->port_id; + mptsas_parse_device_info(&port->identify, &phy_info->identify); + + /* + * Set Negotiated link rate. + */ + switch (phy_info->negotiated_link_rate) { + case MPI_SAS_IOUNIT0_RATE_PHY_DISABLED: + port->negotiated_linkrate = SAS_PHY_DISABLED; + break; + case MPI_SAS_IOUNIT0_RATE_FAILED_SPEED_NEGOTIATION: + port->negotiated_linkrate = SAS_LINK_RATE_FAILED; + break; + case MPI_SAS_IOUNIT0_RATE_1_5: + port->negotiated_linkrate = SAS_LINK_RATE_1_5_GBPS; + break; + case MPI_SAS_IOUNIT0_RATE_3_0: + port->negotiated_linkrate = SAS_LINK_RATE_3_0_GBPS; + break; + case MPI_SAS_IOUNIT0_RATE_SATA_OOB_COMPLETE: + case MPI_SAS_IOUNIT0_RATE_UNKNOWN: + default: + port->negotiated_linkrate = SAS_LINK_RATE_UNKNOWN; + break; + } + + /* + * Set Max hardware link rate. + */ + switch (phy_info->hw_link_rate & MPI_SAS_PHY0_PRATE_MAX_RATE_MASK) { + case MPI_SAS_PHY0_HWRATE_MAX_RATE_1_5: + port->maximum_linkrate_hw = SAS_LINK_RATE_1_5_GBPS; + break; + case MPI_SAS_PHY0_PRATE_MAX_RATE_3_0: + port->maximum_linkrate_hw = SAS_LINK_RATE_3_0_GBPS; + break; + default: + break; + } + + /* + * Set Max programmed link rate. + */ + switch (phy_info->programmed_link_rate & + MPI_SAS_PHY0_PRATE_MAX_RATE_MASK) { + case MPI_SAS_PHY0_PRATE_MAX_RATE_1_5: + port->maximum_linkrate = SAS_LINK_RATE_1_5_GBPS; + break; + case MPI_SAS_PHY0_PRATE_MAX_RATE_3_0: + port->maximum_linkrate = SAS_LINK_RATE_3_0_GBPS; + break; + default: + break; + } + + /* + * Set Min hardware link rate. + */ + switch (phy_info->hw_link_rate & MPI_SAS_PHY0_HWRATE_MIN_RATE_MASK) { + case MPI_SAS_PHY0_HWRATE_MIN_RATE_1_5: + port->minimum_linkrate_hw = SAS_LINK_RATE_1_5_GBPS; + break; + case MPI_SAS_PHY0_PRATE_MIN_RATE_3_0: + port->minimum_linkrate_hw = SAS_LINK_RATE_3_0_GBPS; + break; + default: + break; + } + + /* + * Set Min programmed link rate. + */ + switch (phy_info->programmed_link_rate & + MPI_SAS_PHY0_PRATE_MIN_RATE_MASK) { + case MPI_SAS_PHY0_PRATE_MIN_RATE_1_5: + port->minimum_linkrate = SAS_LINK_RATE_1_5_GBPS; + break; + case MPI_SAS_PHY0_PRATE_MIN_RATE_3_0: + port->minimum_linkrate = SAS_LINK_RATE_3_0_GBPS; + break; + default: + break; + } + + error = sas_phy_add(port); + if (error) { + sas_phy_free(port); + return error; + } + + if (phy_info->attached.handle) { + struct sas_rphy *rphy; + + rphy = sas_rphy_alloc(port); + if (!rphy) + return 0; /* non-fatal: an rphy can be added later */ + + mptsas_parse_device_info(&rphy->identify, &phy_info->attached); + error = sas_rphy_add(rphy); + if (error) { + sas_rphy_free(rphy); + return error; + } + + phy_info->rphy = rphy; + } + + return 0; +} + +static int +mptsas_probe_hba_phys(MPT_ADAPTER *ioc, int *index) +{ + struct mptsas_portinfo *port_info; + u32 handle = 0xFFFF; + int error = -ENOMEM, i; + + port_info = kmalloc(sizeof(*port_info), GFP_KERNEL); + if (!port_info) + goto out; + memset(port_info, 0, sizeof(*port_info)); + + error = mptsas_sas_io_unit_pg0(ioc, port_info); + if (error) + goto out_free_port_info; + + list_add_tail(&port_info->list, &ioc->sas_topology); + + for (i = 0; i < port_info->num_phys; i++) { + mptsas_sas_phy_pg0(ioc, &port_info->phy_info[i], + (MPI_SAS_PHY_PGAD_FORM_PHY_NUMBER << + MPI_SAS_PHY_PGAD_FORM_SHIFT), i); + + mptsas_sas_device_pg0(ioc, &port_info->phy_info[i].identify, + (MPI_SAS_DEVICE_PGAD_FORM_GET_NEXT_HANDLE << + MPI_SAS_DEVICE_PGAD_FORM_SHIFT), handle); + handle = port_info->phy_info[i].identify.handle; + + if (port_info->phy_info[i].attached.handle) { + mptsas_sas_device_pg0(ioc, + &port_info->phy_info[i].attached, + (MPI_SAS_DEVICE_PGAD_FORM_HANDLE << + MPI_SAS_DEVICE_PGAD_FORM_SHIFT), + port_info->phy_info[i].attached.handle); + } + + mptsas_probe_one_phy(&ioc->sh->shost_gendev, + &port_info->phy_info[i], *index); + (*index)++; + } + + return 0; + + out_free_port_info: + kfree(port_info); + out: + return error; +} + +static int +mptsas_probe_expander_phys(MPT_ADAPTER *ioc, u32 *handle, int *index) +{ + struct mptsas_portinfo *port_info, *p; + int error = -ENOMEM, i, j; + + port_info = kmalloc(sizeof(*port_info), GFP_KERNEL); + if (!port_info) + goto out; + memset(port_info, 0, sizeof(*port_info)); + + error = mptsas_sas_expander_pg0(ioc, port_info, + (MPI_SAS_EXPAND_PGAD_FORM_GET_NEXT_HANDLE << + MPI_SAS_EXPAND_PGAD_FORM_SHIFT), *handle); + if (error) + goto out_free_port_info; + + *handle = port_info->handle; + + list_add_tail(&port_info->list, &ioc->sas_topology); + for (i = 0; i < port_info->num_phys; i++) { + struct device *parent; + + mptsas_sas_expander_pg1(ioc, &port_info->phy_info[i], + (MPI_SAS_EXPAND_PGAD_FORM_HANDLE_PHY_NUM << + MPI_SAS_EXPAND_PGAD_FORM_SHIFT), (i << 16) + *handle); + + if (port_info->phy_info[i].identify.handle) { + mptsas_sas_device_pg0(ioc, + &port_info->phy_info[i].identify, + (MPI_SAS_DEVICE_PGAD_FORM_HANDLE << + MPI_SAS_DEVICE_PGAD_FORM_SHIFT), + port_info->phy_info[i].identify.handle); + } + + if (port_info->phy_info[i].attached.handle) { + mptsas_sas_device_pg0(ioc, + &port_info->phy_info[i].attached, + (MPI_SAS_DEVICE_PGAD_FORM_HANDLE << + MPI_SAS_DEVICE_PGAD_FORM_SHIFT), + port_info->phy_info[i].attached.handle); + } + + /* + * If we find a parent port handle this expander is + * attached to another expander, else it hangs of the + * HBA phys. + */ + parent = &ioc->sh->shost_gendev; + list_for_each_entry(p, &ioc->sas_topology, list) { + for (j = 0; j < p->num_phys; j++) { + if (port_info->phy_info[i].identify.handle == + p->phy_info[j].attached.handle) + parent = &p->phy_info[j].rphy->dev; + } + } + + mptsas_probe_one_phy(parent, &port_info->phy_info[i], *index); + (*index)++; + } + + return 0; + + out_free_port_info: + kfree(port_info); + out: + return error; +} + +static void +mptsas_scan_sas_topology(MPT_ADAPTER *ioc) +{ + u32 handle = 0xFFFF; + int index = 0; + + mptsas_probe_hba_phys(ioc, &index); + while (!mptsas_probe_expander_phys(ioc, &handle, &index)) + ; +} + +static int +mptsas_probe(struct pci_dev *pdev, const struct pci_device_id *id) +{ + struct Scsi_Host *sh; + MPT_SCSI_HOST *hd; + MPT_ADAPTER *ioc; + unsigned long flags; + int sz, ii; + int numSGE = 0; + int scale; + int ioc_cap; + u8 *mem; + int error=0; + int r; + + r = mpt_attach(pdev,id); + if (r) + return r; + + ioc = pci_get_drvdata(pdev); + ioc->DoneCtx = mptsasDoneCtx; + ioc->TaskCtx = mptsasTaskCtx; + ioc->InternalCtx = mptsasInternalCtx; + + /* Added sanity check on readiness of the MPT adapter. + */ + if (ioc->last_state != MPI_IOC_STATE_OPERATIONAL) { + printk(MYIOC_s_WARN_FMT + "Skipping because it's not operational!\n", + ioc->name); + return -ENODEV; + } + + if (!ioc->active) { + printk(MYIOC_s_WARN_FMT "Skipping because it's disabled!\n", + ioc->name); + return -ENODEV; + } + + /* Sanity check - ensure at least 1 port is INITIATOR capable + */ + ioc_cap = 0; + for (ii = 0; ii < ioc->facts.NumberOfPorts; ii++) { + if (ioc->pfacts[ii].ProtocolFlags & + MPI_PORTFACTS_PROTOCOL_INITIATOR) + ioc_cap++; + } + + if (!ioc_cap) { + printk(MYIOC_s_WARN_FMT + "Skipping ioc=%p because SCSI Initiator mode " + "is NOT enabled!\n", ioc->name, ioc); + return 0; + } + + sh = scsi_host_alloc(&mptsas_driver_template, sizeof(MPT_SCSI_HOST)); + if (!sh) { + printk(MYIOC_s_WARN_FMT + "Unable to register controller with SCSI subsystem\n", + ioc->name); + return -1; + } + + spin_lock_irqsave(&ioc->FreeQlock, flags); + + /* Attach the SCSI Host to the IOC structure + */ + ioc->sh = sh; + + sh->io_port = 0; + sh->n_io_port = 0; + sh->irq = 0; + + /* set 16 byte cdb's */ + sh->max_cmd_len = 16; + + sh->max_id = ioc->pfacts->MaxDevices + 1; + + sh->transportt = mptsas_transport_template; + + sh->max_lun = MPT_LAST_LUN + 1; + sh->max_channel = 0; + sh->this_id = ioc->pfacts[0].PortSCSIID; + + /* Required entry. + */ + sh->unique_id = ioc->id; + + INIT_LIST_HEAD(&ioc->sas_topology); + + /* Verify that we won't exceed the maximum + * number of chain buffers + * We can optimize: ZZ = req_sz/sizeof(SGE) + * For 32bit SGE's: + * numSGE = 1 + (ZZ-1)*(maxChain -1) + ZZ + * + (req_sz - 64)/sizeof(SGE) + * A slightly different algorithm is required for + * 64bit SGEs. + */ + scale = ioc->req_sz/(sizeof(dma_addr_t) + sizeof(u32)); + if (sizeof(dma_addr_t) == sizeof(u64)) { + numSGE = (scale - 1) * + (ioc->facts.MaxChainDepth-1) + scale + + (ioc->req_sz - 60) / (sizeof(dma_addr_t) + + sizeof(u32)); + } else { + numSGE = 1 + (scale - 1) * + (ioc->facts.MaxChainDepth-1) + scale + + (ioc->req_sz - 64) / (sizeof(dma_addr_t) + + sizeof(u32)); + } + + if (numSGE < sh->sg_tablesize) { + /* Reset this value */ + dprintk((MYIOC_s_INFO_FMT + "Resetting sg_tablesize to %d from %d\n", + ioc->name, numSGE, sh->sg_tablesize)); + sh->sg_tablesize = numSGE; + } + + spin_unlock_irqrestore(&ioc->FreeQlock, flags); + + hd = (MPT_SCSI_HOST *) sh->hostdata; + hd->ioc = ioc; + + /* SCSI needs scsi_cmnd lookup table! + * (with size equal to req_depth*PtrSz!) + */ + sz = ioc->req_depth * sizeof(void *); + mem = kmalloc(sz, GFP_ATOMIC); + if (mem == NULL) { + error = -ENOMEM; + goto mptsas_probe_failed; + } + + memset(mem, 0, sz); + hd->ScsiLookup = (struct scsi_cmnd **) mem; + + dprintk((MYIOC_s_INFO_FMT "ScsiLookup @ %p, sz=%d\n", + ioc->name, hd->ScsiLookup, sz)); + + /* Allocate memory for the device structures. + * A non-Null pointer at an offset + * indicates a device exists. + * max_id = 1 + maximum id (hosts.h) + */ + sz = sh->max_id * sizeof(void *); + mem = kmalloc(sz, GFP_ATOMIC); + if (mem == NULL) { + error = -ENOMEM; + goto mptsas_probe_failed; + } + + memset(mem, 0, sz); + hd->Targets = (VirtDevice **) mem; + + dprintk((KERN_INFO + " Targets @ %p, sz=%d\n", hd->Targets, sz)); + + /* Clear the TM flags + */ + hd->tmPending = 0; + hd->tmState = TM_STATE_NONE; + hd->resetPending = 0; + hd->abortSCpnt = NULL; + + /* Clear the pointer used to store + * single-threaded commands, i.e., those + * issued during a bus scan, dv and + * configuration pages. + */ + hd->cmdPtr = NULL; + + /* Initialize this SCSI Hosts' timers + * To use, set the timer expires field + * and add_timer + */ + init_timer(&hd->timer); + hd->timer.data = (unsigned long) hd; + hd->timer.function = mptscsih_timer_expired; + + hd->mpt_pq_filter = mpt_pq_filter; + ioc->sas_data.ptClear = mpt_pt_clear; + + if (ioc->sas_data.ptClear==1) { + mptbase_sas_persist_operation( + ioc, MPI_SAS_OP_CLEAR_ALL_PERSISTENT); + } + + ddvprintk((MYIOC_s_INFO_FMT + "mpt_pq_filter %x mpt_pq_filter %x\n", + ioc->name, + mpt_pq_filter, + mpt_pq_filter)); + + init_waitqueue_head(&hd->scandv_waitq); + hd->scandv_wait_done = 0; + hd->last_queue_full = 0; + + error = scsi_add_host(sh, &ioc->pcidev->dev); + if (error) { + dprintk((KERN_ERR MYNAM + "scsi_add_host failed\n")); + goto mptsas_probe_failed; + } + + mptsas_scan_sas_topology(ioc); + + return 0; + +mptsas_probe_failed: + + mptscsih_remove(pdev); + return error; +} + +static void __devexit mptsas_remove(struct pci_dev *pdev) +{ + MPT_ADAPTER *ioc = pci_get_drvdata(pdev); + struct mptsas_portinfo *p, *n; + + sas_remove_host(ioc->sh); + + list_for_each_entry_safe(p, n, &ioc->sas_topology, list) { + list_del(&p->list); + kfree(p); + } + + mptscsih_remove(pdev); +} + +static struct pci_device_id mptsas_pci_table[] = { + { PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_SAS1064, + PCI_ANY_ID, PCI_ANY_ID }, + { PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_SAS1066, + PCI_ANY_ID, PCI_ANY_ID }, + { PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_SAS1068, + PCI_ANY_ID, PCI_ANY_ID }, + { PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_SAS1064E, + PCI_ANY_ID, PCI_ANY_ID }, + { PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_SAS1066E, + PCI_ANY_ID, PCI_ANY_ID }, + { PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_SAS1068E, + PCI_ANY_ID, PCI_ANY_ID }, + {0} /* Terminating entry */ +}; +MODULE_DEVICE_TABLE(pci, mptsas_pci_table); + + +static struct pci_driver mptsas_driver = { + .name = "mptsas", + .id_table = mptsas_pci_table, + .probe = mptsas_probe, + .remove = __devexit_p(mptsas_remove), + .shutdown = mptscsih_shutdown, +#ifdef CONFIG_PM + .suspend = mptscsih_suspend, + .resume = mptscsih_resume, +#endif +}; + +static int __init +mptsas_init(void) +{ + show_mptmod_ver(my_NAME, my_VERSION); + + mptsas_transport_template = + sas_attach_transport(&mptsas_transport_functions); + if (!mptsas_transport_template) + return -ENODEV; + + mptsasDoneCtx = mpt_register(mptscsih_io_done, MPTSAS_DRIVER); + mptsasTaskCtx = mpt_register(mptscsih_taskmgmt_complete, MPTSAS_DRIVER); + mptsasInternalCtx = + mpt_register(mptscsih_scandv_complete, MPTSAS_DRIVER); + + if (mpt_event_register(mptsasDoneCtx, mptscsih_event_process) == 0) { + devtprintk((KERN_INFO MYNAM + ": Registered for IOC event notifications\n")); + } + + if (mpt_reset_register(mptsasDoneCtx, mptscsih_ioc_reset) == 0) { + dprintk((KERN_INFO MYNAM + ": Registered for IOC reset notifications\n")); + } + + return pci_register_driver(&mptsas_driver); +} + +static void __exit +mptsas_exit(void) +{ + pci_unregister_driver(&mptsas_driver); + sas_release_transport(mptsas_transport_template); + + mpt_reset_deregister(mptsasDoneCtx); + mpt_event_deregister(mptsasDoneCtx); + + mpt_deregister(mptsasInternalCtx); + mpt_deregister(mptsasTaskCtx); + mpt_deregister(mptsasDoneCtx); +} + +module_init(mptsas_init); +module_exit(mptsas_exit); diff --git a/drivers/message/fusion/mptscsih.c b/drivers/message/fusion/mptscsih.c index 4a003dc..5cb07eb2 100644 --- a/drivers/message/fusion/mptscsih.c +++ b/drivers/message/fusion/mptscsih.c @@ -62,6 +62,7 @@ #include <scsi/scsi_device.h> #include <scsi/scsi_host.h> #include <scsi/scsi_tcq.h> +#include <scsi/scsi_dbg.h> #include "mptbase.h" #include "mptscsih.h" @@ -93,8 +94,9 @@ typedef struct _BIG_SENSE_BUF { #define MPT_ICFLAG_BUF_CAP 0x01 /* ReadBuffer Read Capacity format */ #define MPT_ICFLAG_ECHO 0x02 /* ReadBuffer Echo buffer format */ -#define MPT_ICFLAG_PHYS_DISK 0x04 /* Any SCSI IO but do Phys Disk Format */ -#define MPT_ICFLAG_TAGGED_CMD 0x08 /* Do tagged IO */ +#define MPT_ICFLAG_EBOS 0x04 /* ReadBuffer Echo buffer has EBOS */ +#define MPT_ICFLAG_PHYS_DISK 0x08 /* Any SCSI IO but do Phys Disk Format */ +#define MPT_ICFLAG_TAGGED_CMD 0x10 /* Do tagged IO */ #define MPT_ICFLAG_DID_RESET 0x20 /* Bus Reset occurred with this command */ #define MPT_ICFLAG_RESERVED 0x40 /* Reserved has been issued */ @@ -159,6 +161,8 @@ int mptscsih_scandv_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR static int mptscsih_do_cmd(MPT_SCSI_HOST *hd, INTERNAL_CMD *iocmd); static int mptscsih_synchronize_cache(MPT_SCSI_HOST *hd, int portnum); +static struct work_struct mptscsih_persistTask; + #ifdef MPTSCSIH_ENABLE_DOMAIN_VALIDATION static int mptscsih_do_raid(MPT_SCSI_HOST *hd, u8 action, INTERNAL_CMD *io); static void mptscsih_domainValidation(void *hd); @@ -167,6 +171,7 @@ static void mptscsih_qas_check(MPT_SCSI_HOST *hd, int id); static int mptscsih_doDv(MPT_SCSI_HOST *hd, int channel, int target); static void mptscsih_dv_parms(MPT_SCSI_HOST *hd, DVPARAMETERS *dv,void *pPage); static void mptscsih_fillbuf(char *buffer, int size, int index, int width); +static void mptscsih_set_dvflags_raid(MPT_SCSI_HOST *hd, int id); #endif void mptscsih_remove(struct pci_dev *); @@ -606,11 +611,24 @@ mptscsih_io_done(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr) xfer_cnt = le32_to_cpu(pScsiReply->TransferCount); sc->resid = sc->request_bufflen - xfer_cnt; + /* + * if we get a data underrun indication, yet no data was + * transferred and the SCSI status indicates that the + * command was never started, change the data underrun + * to success + */ + if (status == MPI_IOCSTATUS_SCSI_DATA_UNDERRUN && xfer_cnt == 0 && + (scsi_status == MPI_SCSI_STATUS_BUSY || + scsi_status == MPI_SCSI_STATUS_RESERVATION_CONFLICT || + scsi_status == MPI_SCSI_STATUS_TASK_SET_FULL)) { + status = MPI_IOCSTATUS_SUCCESS; + } + dreplyprintk((KERN_NOTICE "Reply ha=%d id=%d lun=%d:\n" "IOCStatus=%04xh SCSIState=%02xh SCSIStatus=%02xh\n" "resid=%d bufflen=%d xfer_cnt=%d\n", ioc->id, pScsiReq->TargetID, pScsiReq->LUN[1], - status, scsi_state, scsi_status, sc->resid, + status, scsi_state, scsi_status, sc->resid, sc->request_bufflen, xfer_cnt)); if (scsi_state & MPI_SCSI_STATE_AUTOSENSE_VALID) @@ -619,8 +637,11 @@ mptscsih_io_done(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr) /* * Look for + dump FCP ResponseInfo[]! */ - if (scsi_state & MPI_SCSI_STATE_RESPONSE_INFO_VALID) { - printk(KERN_NOTICE " FCP_ResponseInfo=%08xh\n", + if (scsi_state & MPI_SCSI_STATE_RESPONSE_INFO_VALID && + pScsiReply->ResponseInfo) { + printk(KERN_NOTICE "ha=%d id=%d lun=%d: " + "FCP_ResponseInfo=%08xh\n", + ioc->id, pScsiReq->TargetID, pScsiReq->LUN[1], le32_to_cpu(pScsiReply->ResponseInfo)); } @@ -661,23 +682,13 @@ mptscsih_io_done(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr) break; case MPI_IOCSTATUS_SCSI_RESIDUAL_MISMATCH: /* 0x0049 */ - if ( xfer_cnt >= sc->underflow ) { - /* Sufficient data transfer occurred */ + sc->resid = sc->request_bufflen - xfer_cnt; + if((xfer_cnt==0)||(sc->underflow > xfer_cnt)) + sc->result=DID_SOFT_ERROR << 16; + else /* Sufficient data transfer occurred */ sc->result = (DID_OK << 16) | scsi_status; - } else if ( xfer_cnt == 0 ) { - /* A CRC Error causes this condition; retry */ - sc->result = (DRIVER_SENSE << 24) | (DID_OK << 16) | - (CHECK_CONDITION << 1); - sc->sense_buffer[0] = 0x70; - sc->sense_buffer[2] = NO_SENSE; - sc->sense_buffer[12] = 0; - sc->sense_buffer[13] = 0; - } else { - sc->result = DID_SOFT_ERROR << 16; - } - dreplyprintk((KERN_NOTICE - "RESIDUAL_MISMATCH: result=%x on id=%d\n", - sc->result, sc->device->id)); + dreplyprintk((KERN_NOTICE + "RESIDUAL_MISMATCH: result=%x on id=%d\n", sc->result, sc->device->id)); break; case MPI_IOCSTATUS_SCSI_DATA_UNDERRUN: /* 0x0045 */ @@ -692,7 +703,10 @@ mptscsih_io_done(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr) ; } else { if (xfer_cnt < sc->underflow) { - sc->result = DID_SOFT_ERROR << 16; + if (scsi_status == SAM_STAT_BUSY) + sc->result = SAM_STAT_BUSY; + else + sc->result = DID_SOFT_ERROR << 16; } if (scsi_state & (MPI_SCSI_STATE_AUTOSENSE_FAILED | MPI_SCSI_STATE_NO_SCSI_STATUS)) { /* What to do? @@ -717,8 +731,10 @@ mptscsih_io_done(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr) case MPI_IOCSTATUS_SCSI_RECOVERED_ERROR: /* 0x0040 */ case MPI_IOCSTATUS_SUCCESS: /* 0x0000 */ - scsi_status = pScsiReply->SCSIStatus; - 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) { @@ -890,12 +906,13 @@ mptscsih_search_running_cmds(MPT_SCSI_HOST *hd, uint target, uint lun) SCSIIORequest_t *mf = NULL; int ii; int max = hd->ioc->req_depth; + struct scsi_cmnd *sc; dsprintk((KERN_INFO MYNAM ": search_running target %d lun %d max %d\n", target, lun, max)); for (ii=0; ii < max; ii++) { - if (hd->ScsiLookup[ii] != NULL) { + if ((sc = hd->ScsiLookup[ii]) != NULL) { mf = (SCSIIORequest_t *)MPT_INDEX_2_MFPTR(hd->ioc, ii); @@ -910,9 +927,22 @@ mptscsih_search_running_cmds(MPT_SCSI_HOST *hd, uint target, uint lun) hd->ScsiLookup[ii] = NULL; mptscsih_freeChainBuffers(hd->ioc, ii); mpt_free_msg_frame(hd->ioc, (MPT_FRAME_HDR *)mf); + if (sc->use_sg) { + pci_unmap_sg(hd->ioc->pcidev, + (struct scatterlist *) sc->request_buffer, + sc->use_sg, + sc->sc_data_direction); + } else if (sc->request_bufflen) { + pci_unmap_single(hd->ioc->pcidev, + sc->SCp.dma_handle, + sc->request_bufflen, + sc->sc_data_direction); + } + sc->host_scribble = NULL; + sc->result = DID_NO_CONNECT << 16; + sc->scsi_done(sc); } } - return; } @@ -967,8 +997,10 @@ mptscsih_remove(struct pci_dev *pdev) unsigned long flags; int sz1; - if(!host) + if(!host) { + mpt_detach(pdev); return; + } scsi_remove_host(host); @@ -1256,8 +1288,7 @@ mptscsih_qcmd(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *)) MPT_SCSI_HOST *hd; MPT_FRAME_HDR *mf; SCSIIORequest_t *pScsiReq; - VirtDevice *pTarget; - int target; + VirtDevice *pTarget = SCpnt->device->hostdata; int lun; u32 datalen; u32 scsictl; @@ -1267,12 +1298,9 @@ mptscsih_qcmd(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *)) int ii; hd = (MPT_SCSI_HOST *) SCpnt->device->host->hostdata; - target = SCpnt->device->id; lun = SCpnt->device->lun; SCpnt->scsi_done = done; - pTarget = hd->Targets[target]; - dmfprintk((MYIOC_s_INFO_FMT "qcmd: SCpnt=%p, done()=%p\n", (hd && hd->ioc) ? hd->ioc->name : "ioc?", SCpnt, done)); @@ -1315,7 +1343,7 @@ mptscsih_qcmd(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *)) /* Default to untagged. Once a target structure has been allocated, * use the Inquiry data to determine if device supports tagged. */ - if ( pTarget + if (pTarget && (pTarget->tflags & MPT_TARGET_FLAGS_Q_YES) && (SCpnt->device->tagged_supported)) { scsictl = scsidir | MPI_SCSIIO_CONTROL_SIMPLEQ; @@ -1325,8 +1353,8 @@ mptscsih_qcmd(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *)) /* Use the above information to set up the message frame */ - pScsiReq->TargetID = (u8) target; - pScsiReq->Bus = (u8) SCpnt->device->channel; + pScsiReq->TargetID = (u8) pTarget->target_id; + pScsiReq->Bus = pTarget->bus_id; pScsiReq->ChainOffset = 0; pScsiReq->Function = MPI_FUNCTION_SCSI_IO_REQUEST; pScsiReq->CDBLength = SCpnt->cmd_len; @@ -1378,7 +1406,7 @@ mptscsih_qcmd(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *)) #ifdef MPTSCSIH_ENABLE_DOMAIN_VALIDATION if (hd->ioc->bus_type == SCSI) { - int dvStatus = hd->ioc->spi_data.dvStatus[target]; + int dvStatus = hd->ioc->spi_data.dvStatus[pTarget->target_id]; int issueCmd = 1; if (dvStatus || hd->ioc->spi_data.forceDv) { @@ -1426,6 +1454,7 @@ mptscsih_qcmd(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *)) return 0; fail: + hd->ScsiLookup[my_idx] = NULL; mptscsih_freeChainBuffers(hd->ioc, my_idx); mpt_free_msg_frame(hd->ioc, mf); return SCSI_MLQUEUE_HOST_BUSY; @@ -1713,24 +1742,23 @@ mptscsih_abort(struct scsi_cmnd * SCpnt) MPT_FRAME_HDR *mf; u32 ctx2abort; int scpnt_idx; + int retval; /* If we can't locate our host adapter structure, return FAILED status. */ if ((hd = (MPT_SCSI_HOST *) SCpnt->device->host->hostdata) == NULL) { SCpnt->result = DID_RESET << 16; SCpnt->scsi_done(SCpnt); - dfailprintk((KERN_WARNING MYNAM ": mptscsih_abort: " + dfailprintk((KERN_INFO MYNAM ": mptscsih_abort: " "Can't locate host! (sc=%p)\n", SCpnt)); return FAILED; } ioc = hd->ioc; - if (hd->resetPending) + if (hd->resetPending) { return FAILED; - - printk(KERN_WARNING MYNAM ": %s: >> Attempting task abort! (sc=%p)\n", - hd->ioc->name, SCpnt); + } if (hd->timeouts < -1) hd->timeouts++; @@ -1738,16 +1766,20 @@ mptscsih_abort(struct scsi_cmnd * SCpnt) /* Find this command */ if ((scpnt_idx = SCPNT_TO_LOOKUP_IDX(SCpnt)) < 0) { - /* Cmd not found in ScsiLookup. + /* Cmd not found in ScsiLookup. * Do OS callback. */ SCpnt->result = DID_RESET << 16; - dtmprintk((KERN_WARNING MYNAM ": %s: mptscsih_abort: " + dtmprintk((KERN_INFO MYNAM ": %s: mptscsih_abort: " "Command not in the active list! (sc=%p)\n", hd->ioc->name, SCpnt)); return SUCCESS; } + printk(KERN_WARNING MYNAM ": %s: attempting task abort! (sc=%p)\n", + hd->ioc->name, SCpnt); + scsi_print_command(SCpnt); + /* Most important! Set TaskMsgContext to SCpnt's MsgContext! * (the IO to be ABORT'd) * @@ -1760,38 +1792,22 @@ mptscsih_abort(struct scsi_cmnd * SCpnt) hd->abortSCpnt = SCpnt; - if (mptscsih_TMHandler(hd, MPI_SCSITASKMGMT_TASKTYPE_ABORT_TASK, + retval = mptscsih_TMHandler(hd, MPI_SCSITASKMGMT_TASKTYPE_ABORT_TASK, SCpnt->device->channel, SCpnt->device->id, SCpnt->device->lun, - ctx2abort, 2 /* 2 second timeout */) - < 0) { + ctx2abort, 2 /* 2 second timeout */); - /* The TM request failed and the subsequent FW-reload failed! - * Fatal error case. - */ - printk(MYIOC_s_WARN_FMT "Error issuing abort task! (sc=%p)\n", - hd->ioc->name, SCpnt); + printk (KERN_WARNING MYNAM ": %s: task abort: %s (sc=%p)\n", + hd->ioc->name, + ((retval == 0) ? "SUCCESS" : "FAILED" ), SCpnt); - /* We must clear our pending flag before clearing our state. - */ + if (retval == 0) + return SUCCESS; + + if(retval != FAILED ) { hd->tmPending = 0; hd->tmState = TM_STATE_NONE; - - /* Unmap the DMA buffers, if any. */ - if (SCpnt->use_sg) { - pci_unmap_sg(ioc->pcidev, (struct scatterlist *) SCpnt->request_buffer, - SCpnt->use_sg, SCpnt->sc_data_direction); - } else if (SCpnt->request_bufflen) { - pci_unmap_single(ioc->pcidev, SCpnt->SCp.dma_handle, - SCpnt->request_bufflen, SCpnt->sc_data_direction); - } - hd->ScsiLookup[scpnt_idx] = NULL; - SCpnt->result = DID_RESET << 16; - SCpnt->scsi_done(SCpnt); /* Issue the command callback */ - mptscsih_freeChainBuffers(ioc, scpnt_idx); - mpt_free_msg_frame(ioc, mf); - return FAILED; } - return SUCCESS; + return FAILED; } /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ @@ -1807,11 +1823,12 @@ int mptscsih_dev_reset(struct scsi_cmnd * SCpnt) { MPT_SCSI_HOST *hd; + int retval; /* If we can't locate our host adapter structure, return FAILED status. */ if ((hd = (MPT_SCSI_HOST *) SCpnt->device->host->hostdata) == NULL){ - dtmprintk((KERN_WARNING MYNAM ": mptscsih_dev_reset: " + dtmprintk((KERN_INFO MYNAM ": mptscsih_dev_reset: " "Can't locate host! (sc=%p)\n", SCpnt)); return FAILED; @@ -1820,24 +1837,26 @@ mptscsih_dev_reset(struct scsi_cmnd * SCpnt) if (hd->resetPending) return FAILED; - printk(KERN_WARNING MYNAM ": %s: >> Attempting target reset! (sc=%p)\n", + printk(KERN_WARNING MYNAM ": %s: attempting target reset! (sc=%p)\n", hd->ioc->name, SCpnt); + scsi_print_command(SCpnt); - if (mptscsih_TMHandler(hd, MPI_SCSITASKMGMT_TASKTYPE_TARGET_RESET, + retval = mptscsih_TMHandler(hd, MPI_SCSITASKMGMT_TASKTYPE_TARGET_RESET, SCpnt->device->channel, SCpnt->device->id, - 0, 0, 5 /* 5 second timeout */) - < 0){ - /* The TM request failed and the subsequent FW-reload failed! - * Fatal error case. - */ - printk(MYIOC_s_WARN_FMT "Error processing TaskMgmt request (sc=%p)\n", - hd->ioc->name, SCpnt); + 0, 0, 5 /* 5 second timeout */); + + printk (KERN_WARNING MYNAM ": %s: target reset: %s (sc=%p)\n", + hd->ioc->name, + ((retval == 0) ? "SUCCESS" : "FAILED" ), SCpnt); + + if (retval == 0) + return SUCCESS; + + if(retval != FAILED ) { hd->tmPending = 0; hd->tmState = TM_STATE_NONE; - return FAILED; } - - return SUCCESS; + return FAILED; } /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ @@ -1853,41 +1872,39 @@ int mptscsih_bus_reset(struct scsi_cmnd * SCpnt) { MPT_SCSI_HOST *hd; - spinlock_t *host_lock = SCpnt->device->host->host_lock; + int retval; /* If we can't locate our host adapter structure, return FAILED status. */ if ((hd = (MPT_SCSI_HOST *) SCpnt->device->host->hostdata) == NULL){ - dtmprintk((KERN_WARNING MYNAM ": mptscsih_bus_reset: " + dtmprintk((KERN_INFO MYNAM ": mptscsih_bus_reset: " "Can't locate host! (sc=%p)\n", SCpnt ) ); return FAILED; } - printk(KERN_WARNING MYNAM ": %s: >> Attempting bus reset! (sc=%p)\n", + printk(KERN_WARNING MYNAM ": %s: attempting bus reset! (sc=%p)\n", hd->ioc->name, SCpnt); + scsi_print_command(SCpnt); if (hd->timeouts < -1) hd->timeouts++; - /* We are now ready to execute the task management request. */ - if (mptscsih_TMHandler(hd, MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS, - SCpnt->device->channel, 0, 0, 0, 5 /* 5 second timeout */) - < 0){ + retval = mptscsih_TMHandler(hd, MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS, + SCpnt->device->channel, 0, 0, 0, 5 /* 5 second timeout */); - /* The TM request failed and the subsequent FW-reload failed! - * Fatal error case. - */ - printk(MYIOC_s_WARN_FMT - "Error processing TaskMgmt request (sc=%p)\n", - hd->ioc->name, SCpnt); + printk (KERN_WARNING MYNAM ": %s: bus reset: %s (sc=%p)\n", + hd->ioc->name, + ((retval == 0) ? "SUCCESS" : "FAILED" ), SCpnt); + + if (retval == 0) + return SUCCESS; + + if(retval != FAILED ) { hd->tmPending = 0; hd->tmState = TM_STATE_NONE; - spin_lock_irq(host_lock); - return FAILED; } - - return SUCCESS; + return FAILED; } /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ @@ -2169,7 +2186,7 @@ mptscsih_slave_alloc(struct scsi_device *device) vdev->raidVolume = 0; hd->Targets[device->id] = vdev; if (hd->ioc->bus_type == SCSI) { - if (hd->ioc->spi_data.isRaid & (1 << device->id)) { + if (hd->ioc->raid_data.isRaid & (1 << device->id)) { vdev->raidVolume = 1; ddvtprintk((KERN_INFO "RAID Volume @ id %d\n", device->id)); @@ -2180,22 +2197,7 @@ mptscsih_slave_alloc(struct scsi_device *device) out: vdev->num_luns++; - return 0; -} - -static int -mptscsih_is_raid_volume(MPT_SCSI_HOST *hd, uint id) -{ - int i; - - if (!hd->ioc->spi_data.isRaid || !hd->ioc->spi_data.pIocPg3) - return 0; - - for (i = 0; i < hd->ioc->spi_data.pIocPg3->NumPhysDisks; i++) { - if (id == hd->ioc->spi_data.pIocPg3->PhysDisk[i].PhysDiskID) - return 1; - } - + device->hostdata = vdev; return 0; } @@ -2226,7 +2228,7 @@ mptscsih_slave_destroy(struct scsi_device *device) hd->Targets[target] = NULL; if (hd->ioc->bus_type == SCSI) { - if (mptscsih_is_raid_volume(hd, target)) { + if (mptscsih_is_phys_disk(hd->ioc, target)) { hd->ioc->spi_data.forceDv |= MPT_SCSICFG_RELOAD_IOC_PG3; } else { hd->ioc->spi_data.dvStatus[target] = @@ -2439,6 +2441,7 @@ mptscsih_ioc_reset(MPT_ADAPTER *ioc, int reset_phase) { MPT_SCSI_HOST *hd; unsigned long flags; + int ii; dtmprintk((KERN_WARNING MYNAM ": IOC %s_reset routed to SCSI host driver!\n", @@ -2496,11 +2499,8 @@ mptscsih_ioc_reset(MPT_ADAPTER *ioc, int reset_phase) /* ScsiLookup initialization */ - { - int ii; - for (ii=0; ii < hd->ioc->req_depth; ii++) - hd->ScsiLookup[ii] = NULL; - } + for (ii=0; ii < hd->ioc->req_depth; ii++) + hd->ScsiLookup[ii] = NULL; /* 2. Chain Buffer initialization */ @@ -2549,6 +2549,16 @@ mptscsih_ioc_reset(MPT_ADAPTER *ioc, int reset_phase) } /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ +/* work queue thread to clear the persitency table */ +static void +mptscsih_sas_persist_clear_table(void * arg) +{ + MPT_ADAPTER *ioc = (MPT_ADAPTER *)arg; + + mptbase_sas_persist_operation(ioc, MPI_SAS_OP_CLEAR_NOT_PRESENT); +} + +/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ int mptscsih_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *pEvReply) { @@ -2558,18 +2568,18 @@ mptscsih_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *pEvReply) devtprintk((MYIOC_s_INFO_FMT "MPT event (=%02Xh) routed to SCSI host driver!\n", ioc->name, event)); + if (ioc->sh == NULL || + ((hd = (MPT_SCSI_HOST *)ioc->sh->hostdata) == NULL)) + return 1; + switch (event) { case MPI_EVENT_UNIT_ATTENTION: /* 03 */ /* FIXME! */ break; case MPI_EVENT_IOC_BUS_RESET: /* 04 */ case MPI_EVENT_EXT_BUS_RESET: /* 05 */ - hd = NULL; - if (ioc->sh) { - hd = (MPT_SCSI_HOST *) ioc->sh->hostdata; - if (hd && (ioc->bus_type == SCSI) && (hd->soft_resets < -1)) - hd->soft_resets++; - } + if (hd && (ioc->bus_type == SCSI) && (hd->soft_resets < -1)) + hd->soft_resets++; break; case MPI_EVENT_LOGOUT: /* 09 */ /* FIXME! */ @@ -2588,69 +2598,24 @@ mptscsih_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *pEvReply) break; case MPI_EVENT_INTEGRATED_RAID: /* 0B */ + { + pMpiEventDataRaid_t pRaidEventData = + (pMpiEventDataRaid_t) pEvReply->Data; #ifdef MPTSCSIH_ENABLE_DOMAIN_VALIDATION - /* negoNvram set to 0 if DV enabled and to USE_NVRAM if - * if DV disabled. Need to check for target mode. - */ - hd = NULL; - if (ioc->sh) - hd = (MPT_SCSI_HOST *) ioc->sh->hostdata; - - if (hd && (ioc->bus_type == SCSI) && (hd->negoNvram == 0)) { - ScsiCfgData *pSpi; - Ioc3PhysDisk_t *pPDisk; - int numPDisk; - u8 reason; - u8 physDiskNum; - - reason = (le32_to_cpu(pEvReply->Data[0]) & 0x00FF0000) >> 16; - if (reason == MPI_EVENT_RAID_RC_DOMAIN_VAL_NEEDED) { - /* New or replaced disk. - * Set DV flag and schedule DV. - */ - pSpi = &ioc->spi_data; - physDiskNum = (le32_to_cpu(pEvReply->Data[0]) & 0xFF000000) >> 24; - ddvtprintk(("DV requested for phys disk id %d\n", physDiskNum)); - if (pSpi->pIocPg3) { - pPDisk = pSpi->pIocPg3->PhysDisk; - numPDisk =pSpi->pIocPg3->NumPhysDisks; - - while (numPDisk) { - if (physDiskNum == pPDisk->PhysDiskNum) { - pSpi->dvStatus[pPDisk->PhysDiskID] = (MPT_SCSICFG_NEED_DV | MPT_SCSICFG_DV_NOT_DONE); - pSpi->forceDv = MPT_SCSICFG_NEED_DV; - ddvtprintk(("NEED_DV set for phys disk id %d\n", pPDisk->PhysDiskID)); - break; - } - pPDisk++; - numPDisk--; - } - - if (numPDisk == 0) { - /* The physical disk that needs DV was not found - * in the stored IOC Page 3. The driver must reload - * this page. DV routine will set the NEED_DV flag for - * all phys disks that have DV_NOT_DONE set. - */ - pSpi->forceDv = MPT_SCSICFG_NEED_DV | MPT_SCSICFG_RELOAD_IOC_PG3; - ddvtprintk(("phys disk %d not found. Setting reload IOC Pg3 Flag\n", physDiskNum)); - } - } - } - } + /* Domain Validation Needed */ + if (ioc->bus_type == SCSI && + pRaidEventData->ReasonCode == + MPI_EVENT_RAID_RC_DOMAIN_VAL_NEEDED) + mptscsih_set_dvflags_raid(hd, pRaidEventData->PhysDiskNum); #endif + break; + } -#if defined(MPT_DEBUG_DV) || defined(MPT_DEBUG_DV_TINY) - printk("Raid Event RF: "); - { - u32 *m = (u32 *)pEvReply; - int ii; - int n = (int)pEvReply->MsgLength; - for (ii=6; ii < n; ii++) - printk(" %08x", le32_to_cpu(m[ii])); - printk("\n"); - } -#endif + /* Persistent table is full. */ + case MPI_EVENT_PERSISTENT_TABLE_FULL: + INIT_WORK(&mptscsih_persistTask, + mptscsih_sas_persist_clear_table,(void *)ioc); + schedule_work(&mptscsih_persistTask); break; case MPI_EVENT_NONE: /* 00 */ @@ -2687,7 +2652,7 @@ mptscsih_initTarget(MPT_SCSI_HOST *hd, int bus_id, int target_id, u8 lun, char * { int indexed_lun, lun_index; VirtDevice *vdev; - ScsiCfgData *pSpi; + SpiCfgData *pSpi; char data_56; dinitprintk((MYIOC_s_INFO_FMT "initTarget bus=%d id=%d lun=%d hd=%p\n", @@ -2794,7 +2759,7 @@ mptscsih_initTarget(MPT_SCSI_HOST *hd, int bus_id, int target_id, u8 lun, char * static void mptscsih_setTargetNegoParms(MPT_SCSI_HOST *hd, VirtDevice *target, char byte56) { - ScsiCfgData *pspi_data = &hd->ioc->spi_data; + SpiCfgData *pspi_data = &hd->ioc->spi_data; int id = (int) target->target_id; int nvram; VirtDevice *vdev; @@ -2973,11 +2938,13 @@ mptscsih_setTargetNegoParms(MPT_SCSI_HOST *hd, VirtDevice *target, char byte56) static void mptscsih_set_dvflags(MPT_SCSI_HOST *hd, SCSIIORequest_t *pReq) { + MPT_ADAPTER *ioc = hd->ioc; u8 cmd; - ScsiCfgData *pSpi; + SpiCfgData *pSpi; - ddvtprintk((" set_dvflags: id=%d lun=%d negoNvram=%x cmd=%x\n", - pReq->TargetID, pReq->LUN[1], hd->negoNvram, pReq->CDB[0])); + ddvtprintk((MYIOC_s_NOTE_FMT + " set_dvflags: id=%d lun=%d negoNvram=%x cmd=%x\n", + hd->ioc->name, pReq->TargetID, pReq->LUN[1], hd->negoNvram, pReq->CDB[0])); if ((pReq->LUN[1] != 0) || (hd->negoNvram != 0)) return; @@ -2985,12 +2952,12 @@ mptscsih_set_dvflags(MPT_SCSI_HOST *hd, SCSIIORequest_t *pReq) cmd = pReq->CDB[0]; if ((cmd == READ_CAPACITY) || (cmd == MODE_SENSE)) { - pSpi = &hd->ioc->spi_data; - if ((pSpi->isRaid & (1 << pReq->TargetID)) && pSpi->pIocPg3) { + pSpi = &ioc->spi_data; + if ((ioc->raid_data.isRaid & (1 << pReq->TargetID)) && ioc->raid_data.pIocPg3) { /* Set NEED_DV for all hidden disks */ - Ioc3PhysDisk_t *pPDisk = pSpi->pIocPg3->PhysDisk; - int numPDisk = pSpi->pIocPg3->NumPhysDisks; + Ioc3PhysDisk_t *pPDisk = ioc->raid_data.pIocPg3->PhysDisk; + int numPDisk = ioc->raid_data.pIocPg3->NumPhysDisks; while (numPDisk) { pSpi->dvStatus[pPDisk->PhysDiskID] |= MPT_SCSICFG_NEED_DV; @@ -3004,6 +2971,50 @@ mptscsih_set_dvflags(MPT_SCSI_HOST *hd, SCSIIORequest_t *pReq) } } +/* mptscsih_raid_set_dv_flags() + * + * New or replaced disk. Set DV flag and schedule DV. + */ +static void +mptscsih_set_dvflags_raid(MPT_SCSI_HOST *hd, int id) +{ + MPT_ADAPTER *ioc = hd->ioc; + SpiCfgData *pSpi = &ioc->spi_data; + Ioc3PhysDisk_t *pPDisk; + int numPDisk; + + if (hd->negoNvram != 0) + return; + + ddvtprintk(("DV requested for phys disk id %d\n", id)); + if (ioc->raid_data.pIocPg3) { + pPDisk = ioc->raid_data.pIocPg3->PhysDisk; + numPDisk = ioc->raid_data.pIocPg3->NumPhysDisks; + while (numPDisk) { + if (id == pPDisk->PhysDiskNum) { + pSpi->dvStatus[pPDisk->PhysDiskID] = + (MPT_SCSICFG_NEED_DV | MPT_SCSICFG_DV_NOT_DONE); + pSpi->forceDv = MPT_SCSICFG_NEED_DV; + ddvtprintk(("NEED_DV set for phys disk id %d\n", + pPDisk->PhysDiskID)); + break; + } + pPDisk++; + numPDisk--; + } + + if (numPDisk == 0) { + /* The physical disk that needs DV was not found + * in the stored IOC Page 3. The driver must reload + * this page. DV routine will set the NEED_DV flag for + * all phys disks that have DV_NOT_DONE set. + */ + pSpi->forceDv = MPT_SCSICFG_NEED_DV | MPT_SCSICFG_RELOAD_IOC_PG3; + ddvtprintk(("phys disk %d not found. Setting reload IOC Pg3 Flag\n",id)); + } + } +} + /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ /* * If no Target, bus reset on 1st I/O. Set the flag to @@ -3091,7 +3102,7 @@ mptscsih_writeSDP1(MPT_SCSI_HOST *hd, int portnum, int target_id, int flags) MPT_ADAPTER *ioc = hd->ioc; Config_t *pReq; SCSIDevicePage1_t *pData; - VirtDevice *pTarget; + VirtDevice *pTarget=NULL; MPT_FRAME_HDR *mf; dma_addr_t dataDma; u16 req_idx; @@ -3190,7 +3201,7 @@ mptscsih_writeSDP1(MPT_SCSI_HOST *hd, int portnum, int target_id, int flags) #endif if (flags & MPT_SCSICFG_BLK_NEGO) - negoFlags = MPT_TARGET_NO_NEGO_WIDE | MPT_TARGET_NO_NEGO_SYNC; + negoFlags |= MPT_TARGET_NO_NEGO_WIDE | MPT_TARGET_NO_NEGO_SYNC; mptscsih_setDevicePage1Flags(width, factor, offset, &requested, &configuration, negoFlags); @@ -4011,7 +4022,7 @@ mptscsih_synchronize_cache(MPT_SCSI_HOST *hd, int portnum) /* If target Ptr NULL or if this target is NOT a disk, skip. */ - if ((pTarget) && (pTarget->tflags & MPT_TARGET_FLAGS_Q_YES)){ + if ((pTarget) && (pTarget->inq_data[0] == TYPE_DISK)){ for (lun=0; lun <= MPT_LAST_LUN; lun++) { /* If LUN present, issue the command */ @@ -4106,9 +4117,9 @@ mptscsih_domainValidation(void *arg) if ((ioc->spi_data.forceDv & MPT_SCSICFG_RELOAD_IOC_PG3) != 0) { mpt_read_ioc_pg_3(ioc); - if (ioc->spi_data.pIocPg3) { - Ioc3PhysDisk_t *pPDisk = ioc->spi_data.pIocPg3->PhysDisk; - int numPDisk = ioc->spi_data.pIocPg3->NumPhysDisks; + if (ioc->raid_data.pIocPg3) { + Ioc3PhysDisk_t *pPDisk = ioc->raid_data.pIocPg3->PhysDisk; + int numPDisk = ioc->raid_data.pIocPg3->NumPhysDisks; while (numPDisk) { if (ioc->spi_data.dvStatus[pPDisk->PhysDiskID] & MPT_SCSICFG_DV_NOT_DONE) @@ -4147,7 +4158,7 @@ mptscsih_domainValidation(void *arg) isPhysDisk = mptscsih_is_phys_disk(ioc, id); if (isPhysDisk) { for (ii=0; ii < MPT_MAX_SCSI_DEVICES; ii++) { - if (hd->ioc->spi_data.isRaid & (1 << ii)) { + if (hd->ioc->raid_data.isRaid & (1 << ii)) { hd->ioc->spi_data.dvStatus[ii] |= MPT_SCSICFG_DV_PENDING; } } @@ -4166,7 +4177,7 @@ mptscsih_domainValidation(void *arg) if (isPhysDisk) { for (ii=0; ii < MPT_MAX_SCSI_DEVICES; ii++) { - if (hd->ioc->spi_data.isRaid & (1 << ii)) { + if (hd->ioc->raid_data.isRaid & (1 << ii)) { hd->ioc->spi_data.dvStatus[ii] &= ~MPT_SCSICFG_DV_PENDING; } } @@ -4188,21 +4199,21 @@ mptscsih_domainValidation(void *arg) /* Search IOC page 3 to determine if this is hidden physical disk */ -static int +/* Search IOC page 3 to determine if this is hidden physical disk + */ +static int mptscsih_is_phys_disk(MPT_ADAPTER *ioc, int id) { - if (ioc->spi_data.pIocPg3) { - Ioc3PhysDisk_t *pPDisk = ioc->spi_data.pIocPg3->PhysDisk; - int numPDisk = ioc->spi_data.pIocPg3->NumPhysDisks; + int i; - while (numPDisk) { - if (pPDisk->PhysDiskID == id) { - return 1; - } - pPDisk++; - numPDisk--; - } + if (!ioc->raid_data.isRaid || !ioc->raid_data.pIocPg3) + return 0; + + for (i = 0; i < ioc->raid_data.pIocPg3->NumPhysDisks; i++) { + if (id == ioc->raid_data.pIocPg3->PhysDisk[i].PhysDiskID) + return 1; } + return 0; } @@ -4408,7 +4419,7 @@ mptscsih_doDv(MPT_SCSI_HOST *hd, int bus_number, int id) /* Skip this ID? Set cfg.cfghdr.hdr to force config page write */ { - ScsiCfgData *pspi_data = &hd->ioc->spi_data; + SpiCfgData *pspi_data = &hd->ioc->spi_data; if (pspi_data->nvram && (pspi_data->nvram[id] != MPT_HOST_NVRAM_INVALID)) { /* Set the factor from nvram */ nfactor = (pspi_data->nvram[id] & MPT_NVRAM_SYNC_MASK) >> 8; @@ -4438,11 +4449,11 @@ mptscsih_doDv(MPT_SCSI_HOST *hd, int bus_number, int id) } /* Finish iocmd inititialization - hidden or visible disk? */ - if (ioc->spi_data.pIocPg3) { + if (ioc->raid_data.pIocPg3) { /* Search IOC page 3 for matching id */ - Ioc3PhysDisk_t *pPDisk = ioc->spi_data.pIocPg3->PhysDisk; - int numPDisk = ioc->spi_data.pIocPg3->NumPhysDisks; + Ioc3PhysDisk_t *pPDisk = ioc->raid_data.pIocPg3->PhysDisk; + int numPDisk = ioc->raid_data.pIocPg3->NumPhysDisks; while (numPDisk) { if (pPDisk->PhysDiskID == id) { @@ -4466,7 +4477,7 @@ mptscsih_doDv(MPT_SCSI_HOST *hd, int bus_number, int id) /* RAID Volume ID's may double for a physical device. If RAID but * not a physical ID as well, skip DV. */ - if ((hd->ioc->spi_data.isRaid & (1 << id)) && !(iocmd.flags & MPT_ICFLAG_PHYS_DISK)) + if ((hd->ioc->raid_data.isRaid & (1 << id)) && !(iocmd.flags & MPT_ICFLAG_PHYS_DISK)) goto target_done; @@ -4815,6 +4826,8 @@ mptscsih_doDv(MPT_SCSI_HOST *hd, int bus_number, int id) notDone = 0; if (iocmd.flags & MPT_ICFLAG_ECHO) { bufsize = ((pbuf1[2] & 0x1F) <<8) | pbuf1[3]; + if (pbuf1[0] & 0x01) + iocmd.flags |= MPT_ICFLAG_EBOS; } else { bufsize = pbuf1[1]<<16 | pbuf1[2]<<8 | pbuf1[3]; } @@ -4911,6 +4924,9 @@ mptscsih_doDv(MPT_SCSI_HOST *hd, int bus_number, int id) } iocmd.flags &= ~MPT_ICFLAG_DID_RESET; + if (iocmd.flags & MPT_ICFLAG_EBOS) + goto skip_Reserve; + repeat = 5; while (repeat && (!(iocmd.flags & MPT_ICFLAG_RESERVED))) { iocmd.cmd = RESERVE; @@ -4954,6 +4970,7 @@ mptscsih_doDv(MPT_SCSI_HOST *hd, int bus_number, int id) } } +skip_Reserve: mptscsih_fillbuf(pbuf1, sz, patt, 1); iocmd.cmd = WRITE_BUFFER; iocmd.data_dma = buf1_dma; @@ -5198,11 +5215,12 @@ mptscsih_dv_parms(MPT_SCSI_HOST *hd, DVPARAMETERS *dv,void *pPage) * If not an LVD bus, the adapter minSyncFactor has been * already throttled back. */ + negoFlags = hd->ioc->spi_data.noQas; if ((hd->Targets)&&((pTarget = hd->Targets[(int)id]) != NULL) && !pTarget->raidVolume) { width = pTarget->maxWidth; offset = pTarget->maxOffset; factor = pTarget->minSyncFactor; - negoFlags = pTarget->negoFlags; + negoFlags |= pTarget->negoFlags; } else { if (hd->ioc->spi_data.nvram && (hd->ioc->spi_data.nvram[id] != MPT_HOST_NVRAM_INVALID)) { data = hd->ioc->spi_data.nvram[id]; @@ -5223,7 +5241,6 @@ mptscsih_dv_parms(MPT_SCSI_HOST *hd, DVPARAMETERS *dv,void *pPage) } /* Set the negotiation flags */ - negoFlags = hd->ioc->spi_data.noQas; if (!width) negoFlags |= MPT_TARGET_NO_NEGO_WIDE; diff --git a/drivers/message/fusion/mptscsih.h b/drivers/message/fusion/mptscsih.h index 51c0255..971fda4 100644 --- a/drivers/message/fusion/mptscsih.h +++ b/drivers/message/fusion/mptscsih.h @@ -1,5 +1,5 @@ /* - * linux/drivers/message/fusion/mptscsi.h + * linux/drivers/message/fusion/mptscsih.h * High performance SCSI / Fibre Channel SCSI Host device driver. * For use with PCI chip/adapter(s): * LSIFC9xx/LSI409xx Fibre Channel @@ -53,8 +53,8 @@ * SCSI Public stuff... */ -#define MPT_SCSI_CMD_PER_DEV_HIGH 31 -#define MPT_SCSI_CMD_PER_DEV_LOW 7 +#define MPT_SCSI_CMD_PER_DEV_HIGH 64 +#define MPT_SCSI_CMD_PER_DEV_LOW 32 #define MPT_SCSI_CMD_PER_LUN 7 @@ -77,6 +77,7 @@ #define MPTSCSIH_MAX_WIDTH 1 #define MPTSCSIH_MIN_SYNC 0x08 #define MPTSCSIH_SAF_TE 0 +#define MPTSCSIH_PT_CLEAR 0 #endif diff --git a/drivers/message/fusion/mptspi.c b/drivers/message/fusion/mptspi.c index 587d127..5c0e307 100644 --- a/drivers/message/fusion/mptspi.c +++ b/drivers/message/fusion/mptspi.c @@ -199,7 +199,7 @@ mptspi_probe(struct pci_dev *pdev, const struct pci_device_id *id) printk(MYIOC_s_WARN_FMT "Skipping ioc=%p because SCSI Initiator mode is NOT enabled!\n", ioc->name, ioc); - return -ENODEV; + return 0; } sh = scsi_host_alloc(&mptspi_driver_template, sizeof(MPT_SCSI_HOST)); diff --git a/drivers/message/i2o/config-osm.c b/drivers/message/i2o/config-osm.c index af32ab4..10432f6 100644 --- a/drivers/message/i2o/config-osm.c +++ b/drivers/message/i2o/config-osm.c @@ -56,8 +56,11 @@ static int __init i2o_config_init(void) return -EBUSY; } #ifdef CONFIG_I2O_CONFIG_OLD_IOCTL - if (i2o_config_old_init()) + if (i2o_config_old_init()) { + osm_err("old config handler initialization failed\n"); i2o_driver_unregister(&i2o_config_driver); + return -EBUSY; + } #endif return 0; diff --git a/drivers/mtd/devices/docecc.c b/drivers/mtd/devices/docecc.c index 9a087c1..24f670b 100644 --- a/drivers/mtd/devices/docecc.c +++ b/drivers/mtd/devices/docecc.c @@ -40,7 +40,7 @@ #include <linux/mtd/mtd.h> #include <linux/mtd/doc2000.h> -#define DEBUG 0 +#define DEBUG_ECC 0 /* need to undef it (from asm/termbits.h) */ #undef B0 @@ -249,7 +249,7 @@ eras_dec_rs(dtype Alpha_to[NN + 1], dtype Index_of[NN + 1], lambda[j] ^= Alpha_to[modnn(u + tmp)]; } } -#if DEBUG >= 1 +#if DEBUG_ECC >= 1 /* Test code that verifies the erasure locator polynomial just constructed Needed only for decoder debugging. */ @@ -276,7 +276,7 @@ eras_dec_rs(dtype Alpha_to[NN + 1], dtype Index_of[NN + 1], count = -1; goto finish; } -#if DEBUG >= 2 +#if DEBUG_ECC >= 2 printf("\n Erasure positions as determined by roots of Eras Loc Poly:\n"); for (i = 0; i < count; i++) printf("%d ", loc[i]); @@ -409,7 +409,7 @@ eras_dec_rs(dtype Alpha_to[NN + 1], dtype Index_of[NN + 1], den ^= Alpha_to[modnn(lambda[i+1] + i * root[j])]; } if (den == 0) { -#if DEBUG >= 1 +#if DEBUG_ECC >= 1 printf("\n ERROR: denominator = 0\n"); #endif /* Convert to dual- basis */ diff --git a/drivers/mtd/maps/sharpsl-flash.c b/drivers/mtd/maps/sharpsl-flash.c index d15da6f..b7f093f 100644 --- a/drivers/mtd/maps/sharpsl-flash.c +++ b/drivers/mtd/maps/sharpsl-flash.c @@ -82,7 +82,7 @@ int __init init_sharpsl(void) } else if (machine_is_tosa()) { sharpsl_partitions[0].size=0x006a0000; sharpsl_partitions[0].offset=0x00160000; - } else if (machine_is_spitz()) { + } else if (machine_is_spitz() || machine_is_akita() || machine_is_borzoi()) { sharpsl_partitions[0].size=0x006b0000; sharpsl_partitions[0].offset=0x00140000; } else { diff --git a/drivers/mtd/nand/sharpsl.c b/drivers/mtd/nand/sharpsl.c index 9853b87..88b5b5b 100644 --- a/drivers/mtd/nand/sharpsl.c +++ b/drivers/mtd/nand/sharpsl.c @@ -221,10 +221,16 @@ sharpsl_nand_init(void) sharpsl_partition_info[1].size=25 * 1024 * 1024; } else if (machine_is_husky()) { sharpsl_partition_info[1].size=53 * 1024 * 1024; - } + } else if (machine_is_spitz()) { + sharpsl_partition_info[1].size=5 * 1024 * 1024; + } else if (machine_is_akita()) { + sharpsl_partition_info[1].size=58 * 1024 * 1024; + } else if (machine_is_borzoi()) { + sharpsl_partition_info[1].size=32 * 1024 * 1024; + } } - if (machine_is_husky()) { + if (machine_is_husky() || machine_is_borzoi()) { /* Need to use small eraseblock size for backward compatibility */ sharpsl_mtd->flags |= MTD_NO_VIRTBLOCKS; } diff --git a/drivers/net/8139cp.c b/drivers/net/8139cp.c index 34b80de..bc53744 100644 --- a/drivers/net/8139cp.c +++ b/drivers/net/8139cp.c @@ -353,8 +353,6 @@ struct cp_private { struct net_device_stats net_stats; struct cp_extra_stats cp_stats; - struct cp_dma_stats *nic_stats; - dma_addr_t nic_stats_dma; unsigned rx_tail ____cacheline_aligned; struct cp_desc *rx_ring; @@ -1143,10 +1141,6 @@ static int cp_alloc_rings (struct cp_private *cp) cp->rx_ring = mem; cp->tx_ring = &cp->rx_ring[CP_RX_RING_SIZE]; - mem += (CP_RING_BYTES - CP_STATS_SIZE); - cp->nic_stats = mem; - cp->nic_stats_dma = cp->ring_dma + (CP_RING_BYTES - CP_STATS_SIZE); - return cp_init_rings(cp); } @@ -1187,7 +1181,6 @@ static void cp_free_rings (struct cp_private *cp) pci_free_consistent(cp->pdev, CP_RING_BYTES, cp->rx_ring, cp->ring_dma); cp->rx_ring = NULL; cp->tx_ring = NULL; - cp->nic_stats = NULL; } static int cp_open (struct net_device *dev) @@ -1516,13 +1509,17 @@ static void cp_get_ethtool_stats (struct net_device *dev, struct ethtool_stats *estats, u64 *tmp_stats) { struct cp_private *cp = netdev_priv(dev); + struct cp_dma_stats *nic_stats; + dma_addr_t dma; int i; - memset(cp->nic_stats, 0, sizeof(struct cp_dma_stats)); + nic_stats = pci_alloc_consistent(cp->pdev, sizeof(*nic_stats), &dma); + if (!nic_stats) + return; /* begin NIC statistics dump */ - cpw32(StatsAddr + 4, (cp->nic_stats_dma >> 16) >> 16); - cpw32(StatsAddr, (cp->nic_stats_dma & 0xffffffff) | DumpStats); + cpw32(StatsAddr + 4, (u64)dma >> 32); + cpw32(StatsAddr, ((u64)dma & DMA_32BIT_MASK) | DumpStats); cpr32(StatsAddr); for (i = 0; i < 1000; i++) { @@ -1532,24 +1529,27 @@ static void cp_get_ethtool_stats (struct net_device *dev, } cpw32(StatsAddr, 0); cpw32(StatsAddr + 4, 0); + cpr32(StatsAddr); i = 0; - tmp_stats[i++] = le64_to_cpu(cp->nic_stats->tx_ok); - tmp_stats[i++] = le64_to_cpu(cp->nic_stats->rx_ok); - tmp_stats[i++] = le64_to_cpu(cp->nic_stats->tx_err); - tmp_stats[i++] = le32_to_cpu(cp->nic_stats->rx_err); - tmp_stats[i++] = le16_to_cpu(cp->nic_stats->rx_fifo); - tmp_stats[i++] = le16_to_cpu(cp->nic_stats->frame_align); - tmp_stats[i++] = le32_to_cpu(cp->nic_stats->tx_ok_1col); - tmp_stats[i++] = le32_to_cpu(cp->nic_stats->tx_ok_mcol); - tmp_stats[i++] = le64_to_cpu(cp->nic_stats->rx_ok_phys); - tmp_stats[i++] = le64_to_cpu(cp->nic_stats->rx_ok_bcast); - tmp_stats[i++] = le32_to_cpu(cp->nic_stats->rx_ok_mcast); - tmp_stats[i++] = le16_to_cpu(cp->nic_stats->tx_abort); - tmp_stats[i++] = le16_to_cpu(cp->nic_stats->tx_underrun); + tmp_stats[i++] = le64_to_cpu(nic_stats->tx_ok); + tmp_stats[i++] = le64_to_cpu(nic_stats->rx_ok); + tmp_stats[i++] = le64_to_cpu(nic_stats->tx_err); + tmp_stats[i++] = le32_to_cpu(nic_stats->rx_err); + tmp_stats[i++] = le16_to_cpu(nic_stats->rx_fifo); + tmp_stats[i++] = le16_to_cpu(nic_stats->frame_align); + tmp_stats[i++] = le32_to_cpu(nic_stats->tx_ok_1col); + tmp_stats[i++] = le32_to_cpu(nic_stats->tx_ok_mcol); + tmp_stats[i++] = le64_to_cpu(nic_stats->rx_ok_phys); + tmp_stats[i++] = le64_to_cpu(nic_stats->rx_ok_bcast); + tmp_stats[i++] = le32_to_cpu(nic_stats->rx_ok_mcast); + tmp_stats[i++] = le16_to_cpu(nic_stats->tx_abort); + tmp_stats[i++] = le16_to_cpu(nic_stats->tx_underrun); tmp_stats[i++] = cp->cp_stats.rx_frags; if (i != CP_NUM_STATS) BUG(); + + pci_free_consistent(cp->pdev, sizeof(*nic_stats), nic_stats, dma); } static struct ethtool_ops cp_ethtool_ops = { diff --git a/drivers/net/8390.c b/drivers/net/8390.c index 6d76f3a..f870274 100644 --- a/drivers/net/8390.c +++ b/drivers/net/8390.c @@ -1094,7 +1094,7 @@ static void NS8390_trigger_send(struct net_device *dev, unsigned int length, outb_p(E8390_NODMA+E8390_PAGE0, e8390_base+E8390_CMD); - if (inb_p(e8390_base) & E8390_TRANS) + if (inb_p(e8390_base + E8390_CMD) & E8390_TRANS) { printk(KERN_WARNING "%s: trigger_send() called with the transmitter busy.\n", dev->name); diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index 54fff9c..96f14ab 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -1951,7 +1951,7 @@ config SKGE ---help--- This driver support the Marvell Yukon or SysKonnect SK-98xx/SK-95xx and related Gigabit Ethernet adapters. It is a new smaller driver - driver with better performance and more complete ethtool support. + with better performance and more complete ethtool support. It does not support the link failover and network management features that "portable" vendor supplied sk98lin driver does. diff --git a/drivers/net/arcnet/com90io.c b/drivers/net/arcnet/com90io.c index 52c77cb..1f03027 100644 --- a/drivers/net/arcnet/com90io.c +++ b/drivers/net/arcnet/com90io.c @@ -160,7 +160,7 @@ static int __init com90io_probe(struct net_device *dev) return -ENODEV; } if (!request_region(ioaddr, ARCNET_TOTAL_SIZE, "com90io probe")) { - BUGMSG(D_INIT_REASONS, "IO check_region %x-%x failed.\n", + BUGMSG(D_INIT_REASONS, "IO request_region %x-%x failed.\n", ioaddr, ioaddr + ARCNET_TOTAL_SIZE - 1); return -ENXIO; } @@ -242,7 +242,7 @@ static int __init com90io_found(struct net_device *dev) BUGMSG(D_NORMAL, "Can't get IRQ %d!\n", dev->irq); return -ENODEV; } - /* Reserve the I/O region - guaranteed to work by check_region */ + /* Reserve the I/O region */ if (!request_region(dev->base_addr, ARCNET_TOTAL_SIZE, "arcnet (COM90xx-IO)")) { free_irq(dev->irq, dev); return -EBUSY; diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index 94c9f68..6d00c3d 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c @@ -1653,7 +1653,8 @@ static int bond_enslave(struct net_device *bond_dev, struct net_device *slave_de int old_features = bond_dev->features; int res = 0; - if (slave_dev->do_ioctl == NULL) { + if (!bond->params.use_carrier && slave_dev->ethtool_ops == NULL && + slave_dev->do_ioctl == NULL) { printk(KERN_WARNING DRV_NAME ": Warning : no link monitoring support for %s\n", slave_dev->name); @@ -2879,6 +2880,7 @@ static void bond_arp_send_all(struct bonding *bond, struct slave *slave) * This target is not on a VLAN */ if (rt->u.dst.dev == bond->dev) { + ip_rt_put(rt); dprintk("basa: rtdev == bond->dev: arp_send\n"); bond_arp_send(slave->dev, ARPOP_REQUEST, targets[i], bond->master_ip, 0); @@ -2898,6 +2900,7 @@ static void bond_arp_send_all(struct bonding *bond, struct slave *slave) } if (vlan_id) { + ip_rt_put(rt); bond_arp_send(slave->dev, ARPOP_REQUEST, targets[i], vlan->vlan_ip, vlan_id); continue; @@ -2909,6 +2912,7 @@ static void bond_arp_send_all(struct bonding *bond, struct slave *slave) bond->dev->name, NIPQUAD(fl.fl4_dst), rt->u.dst.dev ? rt->u.dst.dev->name : "NULL"); } + ip_rt_put(rt); } } @@ -5036,6 +5040,14 @@ static int __init bonding_init(void) return 0; out_err: + /* + * rtnl_unlock() will run netdev_run_todo(), putting the + * thus-far-registered bonding devices into a state which + * unregigister_netdevice() will accept + */ + rtnl_unlock(); + rtnl_lock(); + /* free and unregister all bonds that were successfully added */ bond_free_all(); diff --git a/drivers/net/e100.c b/drivers/net/e100.c index 25cc20e..fbf1c06 100644 --- a/drivers/net/e100.c +++ b/drivers/net/e100.c @@ -1387,13 +1387,13 @@ static void e100_update_stats(struct nic *nic) ns->collisions += nic->tx_collisions; ns->tx_errors += le32_to_cpu(s->tx_max_collisions) + le32_to_cpu(s->tx_lost_crs); - ns->rx_dropped += le32_to_cpu(s->rx_resource_errors); ns->rx_length_errors += le32_to_cpu(s->rx_short_frame_errors) + nic->rx_over_length_errors; ns->rx_crc_errors += le32_to_cpu(s->rx_crc_errors); ns->rx_frame_errors += le32_to_cpu(s->rx_alignment_errors); ns->rx_over_errors += le32_to_cpu(s->rx_overrun_errors); ns->rx_fifo_errors += le32_to_cpu(s->rx_overrun_errors); + ns->rx_missed_errors += le32_to_cpu(s->rx_resource_errors); ns->rx_errors += le32_to_cpu(s->rx_crc_errors) + le32_to_cpu(s->rx_alignment_errors) + le32_to_cpu(s->rx_short_frame_errors) + @@ -1727,12 +1727,10 @@ static inline int e100_rx_indicate(struct nic *nic, struct rx *rx, if(unlikely(!(rfd_status & cb_ok))) { /* Don't indicate if hardware indicates errors */ - nic->net_stats.rx_dropped++; dev_kfree_skb_any(skb); } else if(actual_size > ETH_DATA_LEN + VLAN_ETH_HLEN) { /* Don't indicate oversized frames */ nic->rx_over_length_errors++; - nic->net_stats.rx_dropped++; dev_kfree_skb_any(skb); } else { nic->net_stats.rx_packets++; diff --git a/drivers/net/e1000/e1000_main.c b/drivers/net/e1000/e1000_main.c index 7c8a0a2..ee687c9 100644 --- a/drivers/net/e1000/e1000_main.c +++ b/drivers/net/e1000/e1000_main.c @@ -2544,7 +2544,6 @@ e1000_update_stats(struct e1000_adapter *adapter) adapter->stats.crcerrs + adapter->stats.algnerrc + adapter->stats.rlec + adapter->stats.mpc + adapter->stats.cexterr; - adapter->net_stats.rx_dropped = adapter->stats.mpc; adapter->net_stats.rx_length_errors = adapter->stats.rlec; adapter->net_stats.rx_crc_errors = adapter->stats.crcerrs; adapter->net_stats.rx_frame_errors = adapter->stats.algnerrc; diff --git a/drivers/net/ixgb/ixgb_main.c b/drivers/net/ixgb/ixgb_main.c index 5c55537..89d6d69 100644 --- a/drivers/net/ixgb/ixgb_main.c +++ b/drivers/net/ixgb/ixgb_main.c @@ -1616,8 +1616,6 @@ ixgb_update_stats(struct ixgb_adapter *adapter) adapter->stats.icbc + adapter->stats.ecbc + adapter->stats.mpc; - adapter->net_stats.rx_dropped = adapter->stats.mpc; - /* see above * adapter->net_stats.rx_length_errors = adapter->stats.rlec; */ diff --git a/drivers/net/r8169.c b/drivers/net/r8169.c index f0471d1..f9223c1 100644 --- a/drivers/net/r8169.c +++ b/drivers/net/r8169.c @@ -100,11 +100,11 @@ VERSION 2.2LK <2005/01/25> #ifdef CONFIG_R8169_NAPI #define rtl8169_rx_skb netif_receive_skb -#define rtl8169_rx_hwaccel_skb vlan_hwaccel_rx +#define rtl8169_rx_hwaccel_skb vlan_hwaccel_receive_skb #define rtl8169_rx_quota(count, quota) min(count, quota) #else #define rtl8169_rx_skb netif_rx -#define rtl8169_rx_hwaccel_skb vlan_hwaccel_receive_skb +#define rtl8169_rx_hwaccel_skb vlan_hwaccel_rx #define rtl8169_rx_quota(count, quota) count #endif diff --git a/drivers/net/s2io.c b/drivers/net/s2io.c index c829e6a..dd451e0 100644 --- a/drivers/net/s2io.c +++ b/drivers/net/s2io.c @@ -428,7 +428,7 @@ static int init_shared_mem(struct s2io_nic *nic) DBG_PRINT(INIT_DBG, "%s: Zero DMA address for TxDL. ", dev->name); DBG_PRINT(INIT_DBG, - "Virtual address %llx\n", (u64)tmp_v); + "Virtual address %p\n", tmp_v); tmp_v = pci_alloc_consistent(nic->pdev, PAGE_SIZE, &tmp_p); if (!tmp_v) { @@ -657,9 +657,10 @@ static void free_shared_mem(struct s2io_nic *nic) mac_control->zerodma_virt_addr, (dma_addr_t)0); DBG_PRINT(INIT_DBG, - "%s: Freeing TxDL with zero DMA addr. ", dev->name); - DBG_PRINT(INIT_DBG, "Virtual address %llx\n", - (u64)(mac_control->zerodma_virt_addr)); + "%s: Freeing TxDL with zero DMA addr. ", + dev->name); + DBG_PRINT(INIT_DBG, "Virtual address %p\n", + mac_control->zerodma_virt_addr); } kfree(mac_control->fifos[i].list_info); } diff --git a/drivers/net/sk98lin/skge.c b/drivers/net/sk98lin/skge.c index 6ee4771..2e72d79 100644 --- a/drivers/net/sk98lin/skge.c +++ b/drivers/net/sk98lin/skge.c @@ -5216,17 +5216,15 @@ static struct pci_device_id skge_pci_tbl[] = { { PCI_VENDOR_ID_3COM, 0x80eb, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, { PCI_VENDOR_ID_SYSKONNECT, 0x4300, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, { PCI_VENDOR_ID_SYSKONNECT, 0x4320, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, - { PCI_VENDOR_ID_DLINK, 0x4c00, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, +/* DLink card does not have valid VPD so this driver gags + * { PCI_VENDOR_ID_DLINK, 0x4c00, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, + */ { PCI_VENDOR_ID_MARVELL, 0x4320, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, -#if 0 /* don't handle Yukon2 cards at the moment -- mlindner@syskonnect.de */ - { PCI_VENDOR_ID_MARVELL, 0x4360, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, - { PCI_VENDOR_ID_MARVELL, 0x4361, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, -#endif { PCI_VENDOR_ID_MARVELL, 0x5005, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, { PCI_VENDOR_ID_CNET, 0x434e, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, - { PCI_VENDOR_ID_LINKSYS, 0x1032, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, + { PCI_VENDOR_ID_LINKSYS, 0x1032, PCI_ANY_ID, 0x0015, }, { PCI_VENDOR_ID_LINKSYS, 0x1064, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, - { 0, } + { 0 } }; MODULE_DEVICE_TABLE(pci, skge_pci_tbl); diff --git a/drivers/net/skge.c b/drivers/net/skge.c index d7c9851..fd398da 100644 --- a/drivers/net/skge.c +++ b/drivers/net/skge.c @@ -42,7 +42,7 @@ #include "skge.h" #define DRV_NAME "skge" -#define DRV_VERSION "0.9" +#define DRV_VERSION "1.1" #define PFX DRV_NAME " " #define DEFAULT_TX_RING_SIZE 128 @@ -105,41 +105,28 @@ static const u32 rxirqmask[] = { IS_R1_F, IS_R2_F }; static const u32 txirqmask[] = { IS_XA1_F, IS_XA2_F }; static const u32 portirqmask[] = { IS_PORT_1, IS_PORT_2 }; -/* Don't need to look at whole 16K. - * last interesting register is descriptor poll timer. - */ -#define SKGE_REGS_LEN (29*128) - static int skge_get_regs_len(struct net_device *dev) { - return SKGE_REGS_LEN; + return 0x4000; } /* - * Returns copy of control register region - * I/O region is divided into banks and certain regions are unreadable + * Returns copy of whole control register region + * Note: skip RAM address register because accessing it will + * cause bus hangs! */ static void skge_get_regs(struct net_device *dev, struct ethtool_regs *regs, void *p) { const struct skge_port *skge = netdev_priv(dev); - unsigned long offs; const void __iomem *io = skge->hw->regs; - static const unsigned long bankmap - = (1<<0) | (1<<2) | (1<<8) | (1<<9) - | (1<<12) | (1<<13) | (1<<14) | (1<<15) | (1<<16) - | (1<<17) | (1<<20) | (1<<21) | (1<<22) | (1<<23) - | (1<<24) | (1<<25) | (1<<26) | (1<<27) | (1<<28); regs->version = 1; - for (offs = 0; offs < regs->len; offs += 128) { - u32 len = min_t(u32, 128, regs->len - offs); + memset(p, 0, regs->len); + memcpy_fromio(p, io, B3_RAM_ADDR); - if (bankmap & (1<<(offs/128))) - memcpy_fromio(p + offs, io + offs, len); - else - memset(p + offs, 0, len); - } + memcpy_fromio(p + B3_RI_WTO_R1, io + B3_RI_WTO_R1, + regs->len - B3_RI_WTO_R1); } /* Wake on Lan only supported on Yukon chps with rev 1 or above */ @@ -669,7 +656,7 @@ static void skge_led(struct skge_port *skge, enum led_mode mode) PHY_M_LED_BLINK_RT(BLINK_84MS) | PHY_M_LEDC_TX_CTRL | PHY_M_LEDC_DP_CTRL); - + gm_phy_write(hw, port, PHY_MARV_LED_OVER, PHY_M_LED_MO_RX(MO_LED_OFF) | (skge->speed == SPEED_100 ? @@ -775,17 +762,6 @@ static int skge_ring_alloc(struct skge_ring *ring, void *vaddr, u64 base) return 0; } -static struct sk_buff *skge_rx_alloc(struct net_device *dev, unsigned int size) -{ - struct sk_buff *skb = dev_alloc_skb(size); - - if (likely(skb)) { - skb->dev = dev; - skb_reserve(skb, NET_IP_ALIGN); - } - return skb; -} - /* Allocate and setup a new buffer for receiving */ static void skge_rx_setup(struct skge_port *skge, struct skge_element *e, struct sk_buff *skb, unsigned int bufsize) @@ -858,16 +834,17 @@ static int skge_rx_fill(struct skge_port *skge) { struct skge_ring *ring = &skge->rx_ring; struct skge_element *e; - unsigned int bufsize = skge->rx_buf_size; e = ring->start; do { - struct sk_buff *skb = skge_rx_alloc(skge->netdev, bufsize); + struct sk_buff *skb; + skb = dev_alloc_skb(skge->rx_buf_size + NET_IP_ALIGN); if (!skb) return -ENOMEM; - skge_rx_setup(skge, e, skb, bufsize); + skb_reserve(skb, NET_IP_ALIGN); + skge_rx_setup(skge, e, skb, skge->rx_buf_size); } while ( (e = e->next) != ring->start); ring->to_clean = ring->start; @@ -876,7 +853,7 @@ static int skge_rx_fill(struct skge_port *skge) static void skge_link_up(struct skge_port *skge) { - skge_write8(skge->hw, SK_REG(skge->port, LNK_LED_REG), + skge_write8(skge->hw, SK_REG(skge->port, LNK_LED_REG), LED_BLK_OFF|LED_SYNC_OFF|LED_ON); netif_carrier_on(skge->netdev); @@ -987,6 +964,8 @@ static void genesis_reset(struct skge_hw *hw, int port) { const u8 zero[8] = { 0 }; + skge_write8(hw, SK_REG(port, GMAC_IRQ_MSK), 0); + /* reset the statistics module */ xm_write32(hw, port, XM_GP_PORT, XM_GP_RES_STAT); xm_write16(hw, port, XM_IMSK, 0xffff); /* disable XMAC IRQs */ @@ -1021,8 +1000,6 @@ static void bcom_check_link(struct skge_hw *hw, int port) (void) xm_phy_read(hw, port, PHY_BCOM_STAT); status = xm_phy_read(hw, port, PHY_BCOM_STAT); - pr_debug("bcom_check_link status=0x%x\n", status); - if ((status & PHY_ST_LSYNC) == 0) { u16 cmd = xm_read16(hw, port, XM_MMU_CMD); cmd &= ~(XM_MMU_ENA_RX | XM_MMU_ENA_TX); @@ -1106,8 +1083,6 @@ static void bcom_phy_init(struct skge_port *skge, int jumbo) { 0x17, 0x0013 }, { 0x15, 0x0A04 }, { 0x18, 0x0420 }, }; - pr_debug("bcom_phy_init\n"); - /* read Id from external PHY (all have the same address) */ id1 = xm_phy_read(hw, port, PHY_XMAC_ID1); @@ -1340,6 +1315,8 @@ static void genesis_stop(struct skge_port *skge) int port = skge->port; u32 reg; + genesis_reset(hw, port); + /* Clear Tx packet arbiter timeout IRQ */ skge_write16(hw, B3_PA_CTRL, port == 0 ? PA_CLR_TO_TX1 : PA_CLR_TO_TX2); @@ -1465,7 +1442,6 @@ static void genesis_link_up(struct skge_port *skge) u16 cmd; u32 mode, msk; - pr_debug("genesis_link_up\n"); cmd = xm_read16(hw, port, XM_MMU_CMD); /* @@ -1578,7 +1554,6 @@ static void yukon_init(struct skge_hw *hw, int port) struct skge_port *skge = netdev_priv(hw->dev[port]); u16 ctrl, ct1000, adv; - pr_debug("yukon_init\n"); if (skge->autoneg == AUTONEG_ENABLE) { u16 ectrl = gm_phy_read(hw, port, PHY_MARV_EXT_CTRL); @@ -1668,6 +1643,22 @@ static void yukon_reset(struct skge_hw *hw, int port) | GM_RXCR_UCF_ENA | GM_RXCR_MCF_ENA); } +/* Apparently, early versions of Yukon-Lite had wrong chip_id? */ +static int is_yukon_lite_a0(struct skge_hw *hw) +{ + u32 reg; + int ret; + + if (hw->chip_id != CHIP_ID_YUKON) + return 0; + + reg = skge_read32(hw, B2_FAR); + skge_write8(hw, B2_FAR + 3, 0xff); + ret = (skge_read8(hw, B2_FAR + 3) != 0); + skge_write32(hw, B2_FAR, reg); + return ret; +} + static void yukon_mac_init(struct skge_hw *hw, int port) { struct skge_port *skge = netdev_priv(hw->dev[port]); @@ -1677,9 +1668,11 @@ static void yukon_mac_init(struct skge_hw *hw, int port) /* WA code for COMA mode -- set PHY reset */ if (hw->chip_id == CHIP_ID_YUKON_LITE && - hw->chip_rev >= CHIP_REV_YU_LITE_A3) - skge_write32(hw, B2_GP_IO, - (skge_read32(hw, B2_GP_IO) | GP_DIR_9 | GP_IO_9)); + hw->chip_rev >= CHIP_REV_YU_LITE_A3) { + reg = skge_read32(hw, B2_GP_IO); + reg |= GP_DIR_9 | GP_IO_9; + skge_write32(hw, B2_GP_IO, reg); + } /* hard reset */ skge_write32(hw, SK_REG(port, GPHY_CTRL), GPC_RST_SET); @@ -1687,10 +1680,12 @@ static void yukon_mac_init(struct skge_hw *hw, int port) /* WA code for COMA mode -- clear PHY reset */ if (hw->chip_id == CHIP_ID_YUKON_LITE && - hw->chip_rev >= CHIP_REV_YU_LITE_A3) - skge_write32(hw, B2_GP_IO, - (skge_read32(hw, B2_GP_IO) | GP_DIR_9) - & ~GP_IO_9); + hw->chip_rev >= CHIP_REV_YU_LITE_A3) { + reg = skge_read32(hw, B2_GP_IO); + reg |= GP_DIR_9; + reg &= ~GP_IO_9; + skge_write32(hw, B2_GP_IO, reg); + } /* Set hardware config mode */ reg = GPC_INT_POL_HI | GPC_DIS_FC | GPC_DIS_SLEEP | @@ -1729,7 +1724,7 @@ static void yukon_mac_init(struct skge_hw *hw, int port) } gma_write16(hw, port, GM_GP_CTRL, reg); - skge_read16(hw, GMAC_IRQ_SRC); + skge_read16(hw, SK_REG(port, GMAC_IRQ_SRC)); yukon_init(hw, port); @@ -1779,9 +1774,11 @@ static void yukon_mac_init(struct skge_hw *hw, int port) /* Configure Rx MAC FIFO */ skge_write16(hw, SK_REG(port, RX_GMF_FL_MSK), RX_FF_FL_DEF_MSK); reg = GMF_OPER_ON | GMF_RX_F_FL_ON; - if (hw->chip_id == CHIP_ID_YUKON_LITE && - hw->chip_rev >= CHIP_REV_YU_LITE_A3) + + /* disable Rx GMAC FIFO Flush for YUKON-Lite Rev. A0 only */ + if (is_yukon_lite_a0(hw)) reg &= ~GMF_RX_F_FL_ON; + skge_write8(hw, SK_REG(port, RX_GMF_CTRL_T), GMF_RST_CLR); skge_write16(hw, SK_REG(port, RX_GMF_CTRL_T), reg); /* @@ -1801,20 +1798,26 @@ static void yukon_stop(struct skge_port *skge) struct skge_hw *hw = skge->hw; int port = skge->port; - if (hw->chip_id == CHIP_ID_YUKON_LITE && - hw->chip_rev >= CHIP_REV_YU_LITE_A3) { - skge_write32(hw, B2_GP_IO, - skge_read32(hw, B2_GP_IO) | GP_DIR_9 | GP_IO_9); - } + skge_write8(hw, SK_REG(port, GMAC_IRQ_MSK), 0); + yukon_reset(hw, port); gma_write16(hw, port, GM_GP_CTRL, gma_read16(hw, port, GM_GP_CTRL) & ~(GM_GPCR_TX_ENA|GM_GPCR_RX_ENA)); gma_read16(hw, port, GM_GP_CTRL); + if (hw->chip_id == CHIP_ID_YUKON_LITE && + hw->chip_rev >= CHIP_REV_YU_LITE_A3) { + u32 io = skge_read32(hw, B2_GP_IO); + + io |= GP_DIR_9 | GP_IO_9; + skge_write32(hw, B2_GP_IO, io); + skge_read32(hw, B2_GP_IO); + } + /* set GPHY Control reset */ - skge_write32(hw, SK_REG(port, GPHY_CTRL), GPC_RST_SET); - skge_write32(hw, SK_REG(port, GMAC_CTRL), GMC_RST_SET); + skge_write8(hw, SK_REG(port, GPHY_CTRL), GPC_RST_SET); + skge_write8(hw, SK_REG(port, GMAC_CTRL), GMC_RST_SET); } static void yukon_get_stats(struct skge_port *skge, u64 *data) @@ -1873,10 +1876,8 @@ static void yukon_link_up(struct skge_port *skge) int port = skge->port; u16 reg; - pr_debug("yukon_link_up\n"); - /* Enable Transmit FIFO Underrun */ - skge_write8(hw, GMAC_IRQ_MSK, GMAC_DEF_MSK); + skge_write8(hw, SK_REG(port, GMAC_IRQ_MSK), GMAC_DEF_MSK); reg = gma_read16(hw, port, GM_GP_CTRL); if (skge->duplex == DUPLEX_FULL || skge->autoneg == AUTONEG_ENABLE) @@ -1896,7 +1897,6 @@ static void yukon_link_down(struct skge_port *skge) int port = skge->port; u16 ctrl; - pr_debug("yukon_link_down\n"); gm_phy_write(hw, port, PHY_MARV_INT_MASK, 0); ctrl = gma_read16(hw, port, GM_GP_CTRL); @@ -2112,7 +2112,6 @@ static int skge_up(struct net_device *dev) skge_write8(hw, Q_ADDR(rxqaddr[port], Q_CSR), CSR_START | CSR_IRQ_CL_F); skge_led(skge, LED_MODE_ON); - pr_debug("skge_up completed\n"); return 0; free_rx_ring: @@ -2135,15 +2134,20 @@ static int skge_down(struct net_device *dev) netif_stop_queue(dev); + skge_write8(skge->hw, SK_REG(skge->port, LNK_LED_REG), LED_OFF); + if (hw->chip_id == CHIP_ID_GENESIS) + genesis_stop(skge); + else + yukon_stop(skge); + + hw->intr_mask &= ~portirqmask[skge->port]; + skge_write32(hw, B0_IMSK, hw->intr_mask); + /* Stop transmitter */ skge_write8(hw, Q_ADDR(txqaddr[port], Q_CSR), CSR_STOP); skge_write32(hw, RB_ADDR(txqaddr[port], RB_CTRL), RB_RST_SET|RB_DIS_OP_MD); - if (hw->chip_id == CHIP_ID_GENESIS) - genesis_stop(skge); - else - yukon_stop(skge); /* Disable Force Sync bit and Enable Alloc bit */ skge_write8(hw, SK_REG(port, TXA_CTRL), @@ -2367,8 +2371,6 @@ static void genesis_set_multicast(struct net_device *dev) u32 mode; u8 filter[8]; - pr_debug("genesis_set_multicast flags=%x count=%d\n", dev->flags, dev->mc_count); - mode = xm_read32(hw, port, XM_MODE); mode |= XM_MD_ENA_HASH; if (dev->flags & IFF_PROMISC) @@ -2435,6 +2437,14 @@ static void yukon_set_multicast(struct net_device *dev) gma_write16(hw, port, GM_RX_CTRL, reg); } +static inline u16 phy_length(const struct skge_hw *hw, u32 status) +{ + if (hw->chip_id == CHIP_ID_GENESIS) + return status >> XMR_FS_LEN_SHIFT; + else + return status >> GMR_FS_LEN_SHIFT; +} + static inline int bad_phy_status(const struct skge_hw *hw, u32 status) { if (hw->chip_id == CHIP_ID_GENESIS) @@ -2444,80 +2454,99 @@ static inline int bad_phy_status(const struct skge_hw *hw, u32 status) (status & GMR_FS_RX_OK) == 0; } -static void skge_rx_error(struct skge_port *skge, int slot, - u32 control, u32 status) -{ - if (netif_msg_rx_err(skge)) - printk(KERN_DEBUG PFX "%s: rx err, slot %d control 0x%x status 0x%x\n", - skge->netdev->name, slot, control, status); - - if ((control & (BMU_EOF|BMU_STF)) != (BMU_STF|BMU_EOF)) - skge->net_stats.rx_length_errors++; - else if (skge->hw->chip_id == CHIP_ID_GENESIS) { - if (status & (XMR_FS_RUNT|XMR_FS_LNG_ERR)) - skge->net_stats.rx_length_errors++; - if (status & XMR_FS_FRA_ERR) - skge->net_stats.rx_frame_errors++; - if (status & XMR_FS_FCS_ERR) - skge->net_stats.rx_crc_errors++; - } else { - if (status & (GMR_FS_LONG_ERR|GMR_FS_UN_SIZE)) - skge->net_stats.rx_length_errors++; - if (status & GMR_FS_FRAGMENT) - skge->net_stats.rx_frame_errors++; - if (status & GMR_FS_CRC_ERR) - skge->net_stats.rx_crc_errors++; - } -} /* Get receive buffer from descriptor. * Handles copy of small buffers and reallocation failures */ static inline struct sk_buff *skge_rx_get(struct skge_port *skge, struct skge_element *e, - unsigned int len) + u32 control, u32 status, u16 csum) { - struct sk_buff *nskb, *skb; + struct sk_buff *skb; + u16 len = control & BMU_BBC; + + if (unlikely(netif_msg_rx_status(skge))) + printk(KERN_DEBUG PFX "%s: rx slot %td status 0x%x len %d\n", + skge->netdev->name, e - skge->rx_ring.start, + status, len); + + if (len > skge->rx_buf_size) + goto error; + + if ((control & (BMU_EOF|BMU_STF)) != (BMU_STF|BMU_EOF)) + goto error; + + if (bad_phy_status(skge->hw, status)) + goto error; + + if (phy_length(skge->hw, status) != len) + goto error; if (len < RX_COPY_THRESHOLD) { - nskb = skge_rx_alloc(skge->netdev, len + NET_IP_ALIGN); - if (unlikely(!nskb)) - return NULL; + skb = dev_alloc_skb(len + 2); + if (!skb) + goto resubmit; + skb_reserve(skb, 2); pci_dma_sync_single_for_cpu(skge->hw->pdev, pci_unmap_addr(e, mapaddr), len, PCI_DMA_FROMDEVICE); - memcpy(nskb->data, e->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); - - if (skge->rx_csum) { - struct skge_rx_desc *rd = e->desc; - nskb->csum = le16_to_cpu(rd->csum2); - nskb->ip_summed = CHECKSUM_HW; - } skge_rx_reuse(e, skge->rx_buf_size); - return nskb; } else { - nskb = skge_rx_alloc(skge->netdev, skge->rx_buf_size); - if (unlikely(!nskb)) - return NULL; + struct sk_buff *nskb; + nskb = dev_alloc_skb(skge->rx_buf_size + NET_IP_ALIGN); + if (!nskb) + goto resubmit; pci_unmap_single(skge->hw->pdev, pci_unmap_addr(e, mapaddr), pci_unmap_len(e, maplen), PCI_DMA_FROMDEVICE); skb = e->skb; - if (skge->rx_csum) { - struct skge_rx_desc *rd = e->desc; - skb->csum = le16_to_cpu(rd->csum2); - skb->ip_summed = CHECKSUM_HW; - } - + prefetch(skb->data); skge_rx_setup(skge, e, nskb, skge->rx_buf_size); - return skb; } + + skb_put(skb, len); + skb->dev = skge->netdev; + if (skge->rx_csum) { + skb->csum = csum; + skb->ip_summed = CHECKSUM_HW; + } + + skb->protocol = eth_type_trans(skb, skge->netdev); + + return skb; +error: + + if (netif_msg_rx_err(skge)) + printk(KERN_DEBUG PFX "%s: rx err, slot %td control 0x%x status 0x%x\n", + skge->netdev->name, e - skge->rx_ring.start, + control, status); + + if (skge->hw->chip_id == CHIP_ID_GENESIS) { + if (status & (XMR_FS_RUNT|XMR_FS_LNG_ERR)) + skge->net_stats.rx_length_errors++; + if (status & XMR_FS_FRA_ERR) + skge->net_stats.rx_frame_errors++; + if (status & XMR_FS_FCS_ERR) + skge->net_stats.rx_crc_errors++; + } else { + if (status & (GMR_FS_LONG_ERR|GMR_FS_UN_SIZE)) + skge->net_stats.rx_length_errors++; + if (status & GMR_FS_FRAGMENT) + skge->net_stats.rx_frame_errors++; + if (status & GMR_FS_CRC_ERR) + skge->net_stats.rx_crc_errors++; + } + +resubmit: + skge_rx_reuse(e, skge->rx_buf_size); + return NULL; } @@ -2530,37 +2559,19 @@ static int skge_poll(struct net_device *dev, int *budget) unsigned int to_do = min(dev->quota, *budget); unsigned int work_done = 0; - pr_debug("skge_poll\n"); - for (e = ring->to_clean; work_done < to_do; e = e->next) { struct skge_rx_desc *rd = e->desc; struct sk_buff *skb; - u32 control, len, status; + u32 control; rmb(); control = rd->control; if (control & BMU_OWN) break; - len = control & BMU_BBC; - status = rd->status; - - if (unlikely((control & (BMU_EOF|BMU_STF)) != (BMU_STF|BMU_EOF) - || bad_phy_status(hw, status))) { - skge_rx_error(skge, e - ring->start, control, status); - skge_rx_reuse(e, skge->rx_buf_size); - continue; - } - - if (netif_msg_rx_status(skge)) - printk(KERN_DEBUG PFX "%s: rx slot %td status 0x%x len %d\n", - dev->name, e - ring->start, rd->status, len); - - skb = skge_rx_get(skge, e, len); + skb = skge_rx_get(skge, e, control, rd->status, + le16_to_cpu(rd->csum2)); if (likely(skb)) { - skb_put(skb, len); - skb->protocol = eth_type_trans(skb, dev); - dev->last_rx = jiffies; netif_receive_skb(skb); @@ -2672,9 +2683,9 @@ static void skge_error_irq(struct skge_hw *hw) if (hw->chip_id == CHIP_ID_GENESIS) { /* clear xmac errors */ if (hwstatus & (IS_NO_STAT_M1|IS_NO_TIST_M1)) - skge_write16(hw, SK_REG(0, RX_MFF_CTRL1), MFF_CLR_INSTAT); + skge_write16(hw, RX_MFF_CTRL1, MFF_CLR_INSTAT); if (hwstatus & (IS_NO_STAT_M2|IS_NO_TIST_M2)) - skge_write16(hw, SK_REG(0, RX_MFF_CTRL2), MFF_CLR_INSTAT); + skge_write16(hw, RX_MFF_CTRL2, MFF_CLR_INSTAT); } else { /* Timestamp (unused) overflow */ if (hwstatus & IS_IRQ_TIST_OV) @@ -3000,9 +3011,6 @@ static int skge_reset(struct skge_hw *hw) skge_write32(hw, B0_IMSK, hw->intr_mask); - if (hw->chip_id != CHIP_ID_GENESIS) - skge_write8(hw, GMAC_IRQ_MSK, 0); - spin_lock_bh(&hw->phy_lock); for (i = 0; i < hw->ports; i++) { if (hw->chip_id == CHIP_ID_GENESIS) @@ -3230,6 +3238,11 @@ static void __devexit skge_remove(struct pci_dev *pdev) dev0 = hw->dev[0]; unregister_netdev(dev0); + skge_write32(hw, B0_IMSK, 0); + skge_write16(hw, B0_LED, LED_STAT_OFF); + skge_pci_clear(hw); + skge_write8(hw, B0_CTST, CS_RST_SET); + tasklet_kill(&hw->ext_tasklet); free_irq(pdev->irq, hw); @@ -3238,7 +3251,7 @@ static void __devexit skge_remove(struct pci_dev *pdev) if (dev1) free_netdev(dev1); free_netdev(dev0); - skge_write16(hw, B0_LED, LED_STAT_OFF); + iounmap(hw->regs); kfree(hw); pci_set_drvdata(pdev, NULL); @@ -3257,7 +3270,10 @@ static int skge_suspend(struct pci_dev *pdev, pm_message_t state) struct skge_port *skge = netdev_priv(dev); if (netif_running(dev)) { netif_carrier_off(dev); - skge_down(dev); + if (skge->wol) + netif_stop_queue(dev); + else + skge_down(dev); } netif_device_detach(dev); wol |= skge->wol; diff --git a/drivers/net/skge.h b/drivers/net/skge.h index f1680be..72c175b 100644 --- a/drivers/net/skge.h +++ b/drivers/net/skge.h @@ -953,6 +953,7 @@ enum { */ enum { XMR_FS_LEN = 0x3fff<<18, /* Bit 31..18: Rx Frame Length */ + XMR_FS_LEN_SHIFT = 18, XMR_FS_2L_VLAN = 1<<17, /* Bit 17: tagged wh 2Lev VLAN ID*/ XMR_FS_1_VLAN = 1<<16, /* Bit 16: tagged wh 1ev VLAN ID*/ XMR_FS_BC = 1<<15, /* Bit 15: Broadcast Frame */ @@ -1868,6 +1869,7 @@ enum { /* Receive Frame Status Encoding */ enum { GMR_FS_LEN = 0xffff<<16, /* Bit 31..16: Rx Frame Length */ + GMR_FS_LEN_SHIFT = 16, GMR_FS_VLAN = 1<<13, /* Bit 13: VLAN Packet */ GMR_FS_JABBER = 1<<12, /* Bit 12: Jabber Packet */ GMR_FS_UN_SIZE = 1<<11, /* Bit 11: Undersize Packet */ @@ -2008,7 +2010,7 @@ enum { GM_IS_RX_FF_OR = 1<<1, /* Receive FIFO Overrun */ GM_IS_RX_COMPL = 1<<0, /* Frame Reception Complete */ -#define GMAC_DEF_MSK (GM_IS_TX_CO_OV | GM_IS_RX_CO_OV | GM_IS_TX_FF_UR) +#define GMAC_DEF_MSK (GM_IS_RX_FF_OR | GM_IS_TX_FF_UR) /* GMAC_LINK_CTRL 16 bit GMAC Link Control Reg (YUKON only) */ /* Bits 15.. 2: reserved */ diff --git a/drivers/net/spider_net.c b/drivers/net/spider_net.c index 4e19220..c796f41 100644 --- a/drivers/net/spider_net.c +++ b/drivers/net/spider_net.c @@ -1817,6 +1817,10 @@ spider_net_setup_phy(struct spider_net_card *card) /* LEDs active in both modes, autosense prio = fiber */ spider_net_write_phy(card->netdev, 1, MII_NCONFIG, 0x945f); + /* switch off fibre autoneg */ + spider_net_write_phy(card->netdev, 1, MII_NCONFIG, 0xfc01); + spider_net_write_phy(card->netdev, 1, 0x0b, 0x0004); + phy->def->ops->read_link(phy); pr_info("Found %s with %i Mbps, %s-duplex.\n", phy->def->name, phy->speed, phy->duplex==1 ? "Full" : "Half"); diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index 7599f52..81f4aed 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -67,8 +67,8 @@ #define DRV_MODULE_NAME "tg3" #define PFX DRV_MODULE_NAME ": " -#define DRV_MODULE_VERSION "3.39" -#define DRV_MODULE_RELDATE "September 5, 2005" +#define DRV_MODULE_VERSION "3.40" +#define DRV_MODULE_RELDATE "September 15, 2005" #define TG3_DEF_MAC_MODE 0 #define TG3_DEF_RX_MODE 0 @@ -3442,31 +3442,47 @@ static void tg3_tx_timeout(struct net_device *dev) schedule_work(&tp->reset_task); } +/* Test for DMA buffers crossing any 4GB boundaries: 4G, 8G, etc */ +static inline int tg3_4g_overflow_test(dma_addr_t mapping, int len) +{ + u32 base = (u32) mapping & 0xffffffff; + + return ((base > 0xffffdcc0) && + (base + len + 8 < base)); +} + static void tg3_set_txd(struct tg3 *, int, dma_addr_t, int, u32, u32); static int tigon3_4gb_hwbug_workaround(struct tg3 *tp, struct sk_buff *skb, - u32 guilty_entry, int guilty_len, - u32 last_plus_one, u32 *start, u32 mss) + u32 last_plus_one, u32 *start, + u32 base_flags, u32 mss) { struct sk_buff *new_skb = skb_copy(skb, GFP_ATOMIC); - dma_addr_t new_addr; + dma_addr_t new_addr = 0; u32 entry = *start; - int i; + int i, ret = 0; if (!new_skb) { - dev_kfree_skb(skb); - return -1; + ret = -1; + } else { + /* New SKB is guaranteed to be linear. */ + entry = *start; + new_addr = pci_map_single(tp->pdev, new_skb->data, new_skb->len, + PCI_DMA_TODEVICE); + /* Make sure new skb does not cross any 4G boundaries. + * Drop the packet if it does. + */ + if (tg3_4g_overflow_test(new_addr, new_skb->len)) { + ret = -1; + dev_kfree_skb(new_skb); + new_skb = NULL; + } else { + tg3_set_txd(tp, entry, new_addr, new_skb->len, + base_flags, 1 | (mss << 1)); + *start = NEXT_TX(entry); + } } - /* New SKB is guaranteed to be linear. */ - entry = *start; - new_addr = pci_map_single(tp->pdev, new_skb->data, new_skb->len, - PCI_DMA_TODEVICE); - tg3_set_txd(tp, entry, new_addr, new_skb->len, - (skb->ip_summed == CHECKSUM_HW) ? - TXD_FLAG_TCPUDP_CSUM : 0, 1 | (mss << 1)); - *start = NEXT_TX(entry); - /* Now clean up the sw ring entries. */ i = 0; while (entry != last_plus_one) { @@ -3491,7 +3507,7 @@ static int tigon3_4gb_hwbug_workaround(struct tg3 *tp, struct sk_buff *skb, dev_kfree_skb(skb); - return 0; + return ret; } static void tg3_set_txd(struct tg3 *tp, int entry, @@ -3517,19 +3533,10 @@ static void tg3_set_txd(struct tg3 *tp, int entry, txd->vlan_tag = vlan_tag << TXD_VLAN_TAG_SHIFT; } -static inline int tg3_4g_overflow_test(dma_addr_t mapping, int len) -{ - u32 base = (u32) mapping & 0xffffffff; - - return ((base > 0xffffdcc0) && - (base + len + 8 < base)); -} - static int tg3_start_xmit(struct sk_buff *skb, struct net_device *dev) { struct tg3 *tp = netdev_priv(dev); dma_addr_t mapping; - unsigned int i; u32 len, entry, base_flags, mss; int would_hit_hwbug; @@ -3624,7 +3631,7 @@ static int tg3_start_xmit(struct sk_buff *skb, struct net_device *dev) would_hit_hwbug = 0; if (tg3_4g_overflow_test(mapping, len)) - would_hit_hwbug = entry + 1; + would_hit_hwbug = 1; tg3_set_txd(tp, entry, mapping, len, base_flags, (skb_shinfo(skb)->nr_frags == 0) | (mss << 1)); @@ -3648,12 +3655,8 @@ static int tg3_start_xmit(struct sk_buff *skb, struct net_device *dev) tp->tx_buffers[entry].skb = NULL; pci_unmap_addr_set(&tp->tx_buffers[entry], mapping, mapping); - if (tg3_4g_overflow_test(mapping, len)) { - /* Only one should match. */ - if (would_hit_hwbug) - BUG(); - would_hit_hwbug = entry + 1; - } + if (tg3_4g_overflow_test(mapping, len)) + would_hit_hwbug = 1; if (tp->tg3_flags2 & TG3_FLG2_HW_TSO) tg3_set_txd(tp, entry, mapping, len, @@ -3669,34 +3672,15 @@ static int tg3_start_xmit(struct sk_buff *skb, struct net_device *dev) if (would_hit_hwbug) { u32 last_plus_one = entry; u32 start; - unsigned int len = 0; - - would_hit_hwbug -= 1; - entry = entry - 1 - skb_shinfo(skb)->nr_frags; - entry &= (TG3_TX_RING_SIZE - 1); - start = entry; - i = 0; - while (entry != last_plus_one) { - if (i == 0) - len = skb_headlen(skb); - else - len = skb_shinfo(skb)->frags[i-1].size; - if (entry == would_hit_hwbug) - break; - - i++; - entry = NEXT_TX(entry); - - } + start = entry - 1 - skb_shinfo(skb)->nr_frags; + start &= (TG3_TX_RING_SIZE - 1); /* If the workaround fails due to memory/mapping * failure, silently drop this packet. */ - if (tigon3_4gb_hwbug_workaround(tp, skb, - entry, len, - last_plus_one, - &start, mss)) + if (tigon3_4gb_hwbug_workaround(tp, skb, last_plus_one, + &start, base_flags, mss)) goto out_unlock; entry = start; @@ -9271,6 +9255,8 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) static struct pci_device_id write_reorder_chipsets[] = { { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_FE_GATE_700C) }, + { PCI_DEVICE(PCI_VENDOR_ID_AMD, + PCI_DEVICE_ID_AMD_K8_NB) }, { }, }; u32 misc_ctrl_reg; @@ -9285,7 +9271,7 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) tp->tg3_flags2 |= TG3_FLG2_SUN_570X; #endif - /* If we have an AMD 762 chipset, write + /* If we have an AMD 762 or K8 chipset, write * reordering to the mailbox registers done by the host * controller can cause major troubles. We read back from * every mailbox register write to force the writes to be @@ -9532,7 +9518,7 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) tp->write32_rx_mbox = tg3_write_indirect_mbox; iounmap(tp->regs); - tp->regs = 0; + tp->regs = NULL; pci_read_config_word(tp->pdev, PCI_COMMAND, &pci_cmd); pci_cmd &= ~PCI_COMMAND_MEMORY; @@ -10680,7 +10666,7 @@ static int __devinit tg3_init_one(struct pci_dev *pdev, err_out_iounmap: if (tp->regs) { iounmap(tp->regs); - tp->regs = 0; + tp->regs = NULL; } err_out_free_dev: @@ -10705,7 +10691,7 @@ static void __devexit tg3_remove_one(struct pci_dev *pdev) unregister_netdev(dev); if (tp->regs) { iounmap(tp->regs); - tp->regs = 0; + tp->regs = NULL; } free_netdev(dev); pci_release_regions(pdev); diff --git a/drivers/net/tulip/xircom_cb.c b/drivers/net/tulip/xircom_cb.c index 26cc4f6..60d1e05 100644 --- a/drivers/net/tulip/xircom_cb.c +++ b/drivers/net/tulip/xircom_cb.c @@ -117,7 +117,7 @@ static int xircom_open(struct net_device *dev); static int xircom_close(struct net_device *dev); static void xircom_up(struct xircom_private *card); static struct net_device_stats *xircom_get_stats(struct net_device *dev); -#if CONFIG_NET_POLL_CONTROLLER +#ifdef CONFIG_NET_POLL_CONTROLLER static void xircom_poll_controller(struct net_device *dev); #endif diff --git a/drivers/net/wan/hdlc_cisco.c b/drivers/net/wan/hdlc_cisco.c index 48c03c1..a01efa6 100644 --- a/drivers/net/wan/hdlc_cisco.c +++ b/drivers/net/wan/hdlc_cisco.c @@ -72,7 +72,7 @@ static void cisco_keepalive_send(struct net_device *dev, u32 type, } skb_reserve(skb, 4); cisco_hard_header(skb, dev, CISCO_KEEPALIVE, NULL, NULL, 0); - data = (cisco_packet*)skb->data; + data = (cisco_packet*)(skb->data + 4); data->type = htonl(type); data->par1 = htonl(par1); diff --git a/drivers/net/wireless/airo.c b/drivers/net/wireless/airo.c index 2be65d3..06998c2 100644 --- a/drivers/net/wireless/airo.c +++ b/drivers/net/wireless/airo.c @@ -6852,7 +6852,10 @@ static inline char *airo_translate_scan(struct net_device *dev, /* Add frequency */ iwe.cmd = SIOCGIWFREQ; iwe.u.freq.m = le16_to_cpu(bss->dsChannel); - iwe.u.freq.m = frequency_list[iwe.u.freq.m] * 100000; + /* iwe.u.freq.m containt the channel (starting 1), our + * frequency_list array start at index 0... + */ + iwe.u.freq.m = frequency_list[iwe.u.freq.m - 1] * 100000; iwe.u.freq.e = 1; current_ev = iwe_stream_add_event(current_ev, end_buf, &iwe, IW_EV_FREQ_LEN); diff --git a/drivers/net/wireless/orinoco_cs.c b/drivers/net/wireless/orinoco_cs.c index d1fb1ba..bedd7f9f 100644 --- a/drivers/net/wireless/orinoco_cs.c +++ b/drivers/net/wireless/orinoco_cs.c @@ -629,6 +629,7 @@ static struct pcmcia_device_id orinoco_cs_ids[] = { PCMCIA_DEVICE_PROD_ID12("Cabletron", "RoamAbout 802.11 DS", 0x32d445f5, 0xedeffd90), PCMCIA_DEVICE_PROD_ID12("corega K.K.", "Wireless LAN PCC-11", 0x5261440f, 0xa6405584), PCMCIA_DEVICE_PROD_ID12("corega K.K.", "Wireless LAN PCCA-11", 0x5261440f, 0xdf6115f9), + PCMCIA_DEVICE_PROD_ID12("corega_K.K.", "Wireless_LAN_PCCB-11", 0x29e33311, 0xee7a27ae), PCMCIA_DEVICE_PROD_ID12("D", "Link DRC-650 11Mbps WLAN Card", 0x71b18589, 0xf144e3ac), PCMCIA_DEVICE_PROD_ID12("D", "Link DWL-650 11Mbps WLAN Card", 0x71b18589, 0xb6f1b0ab), PCMCIA_DEVICE_PROD_ID12("ELSA", "AirLancer MC-11", 0x4507a33a, 0xef54f0e3), diff --git a/drivers/pci/hotplug.c b/drivers/pci/hotplug.c index 1044498..e1743be 100644 --- a/drivers/pci/hotplug.c +++ b/drivers/pci/hotplug.c @@ -7,7 +7,6 @@ int pci_hotplug (struct device *dev, char **envp, int num_envp, char *buffer, int buffer_size) { struct pci_dev *pdev; - char *scratch; int i = 0; int length = 0; @@ -18,9 +17,6 @@ int pci_hotplug (struct device *dev, char **envp, int num_envp, if (!pdev) return -ENODEV; - scratch = buffer; - - if (add_hotplug_env_var(envp, num_envp, &i, buffer, buffer_size, &length, "PCI_CLASS=%04X", pdev->class)) diff --git a/drivers/pci/hotplug/ibmphp_pci.c b/drivers/pci/hotplug/ibmphp_pci.c index 8122fe7..b1ba429 100644 --- a/drivers/pci/hotplug/ibmphp_pci.c +++ b/drivers/pci/hotplug/ibmphp_pci.c @@ -558,7 +558,7 @@ static int configure_device (struct pci_func *func) pci_bus_write_config_byte (ibmphp_pci_bus, devfn, PCI_CACHE_LINE_SIZE, CACHE); pci_bus_write_config_byte (ibmphp_pci_bus, devfn, PCI_LATENCY_TIMER, LATENCY); - pci_bus_write_config_word (ibmphp_pci_bus, devfn, PCI_ROM_ADDRESS, 0x00L); + pci_bus_write_config_dword (ibmphp_pci_bus, devfn, PCI_ROM_ADDRESS, 0x00L); pci_bus_write_config_word (ibmphp_pci_bus, devfn, PCI_COMMAND, DEVICEENABLE); return 0; diff --git a/drivers/pci/hotplug/pciehp_ctrl.c b/drivers/pci/hotplug/pciehp_ctrl.c index 0e09476..898f6da 100644 --- a/drivers/pci/hotplug/pciehp_ctrl.c +++ b/drivers/pci/hotplug/pciehp_ctrl.c @@ -2526,7 +2526,6 @@ configure_new_function(struct controller *ctrl, struct pci_func *func, int cloop; u8 temp_byte; u8 class_code; - u16 temp_word; u32 rc; u32 temp_register; u32 base; @@ -2682,8 +2681,7 @@ configure_new_function(struct controller *ctrl, struct pci_func *func, } /* End of base register loop */ /* disable ROM base Address */ - temp_word = 0x00L; - rc = pci_bus_write_config_word (pci_bus, devfn, PCI_ROM_ADDRESS, temp_word); + rc = pci_bus_write_config_dword (pci_bus, devfn, PCI_ROM_ADDRESS, 0x00); /* Set HP parameters (Cache Line Size, Latency Timer) */ rc = pciehprm_set_hpp(ctrl, func, PCI_HEADER_TYPE_NORMAL); diff --git a/drivers/pci/hotplug/rpadlpar_sysfs.c b/drivers/pci/hotplug/rpadlpar_sysfs.c index 752e651..db69be8 100644 --- a/drivers/pci/hotplug/rpadlpar_sysfs.c +++ b/drivers/pci/hotplug/rpadlpar_sysfs.c @@ -62,7 +62,7 @@ static ssize_t add_slot_store(struct dlpar_io_attr *dlpar_attr, char drc_name[MAX_DRC_NAME_LEN]; char *end; - if (nbytes > MAX_DRC_NAME_LEN) + if (nbytes >= MAX_DRC_NAME_LEN) return 0; memcpy(drc_name, buf, nbytes); @@ -83,7 +83,7 @@ static ssize_t remove_slot_store(struct dlpar_io_attr *dlpar_attr, char drc_name[MAX_DRC_NAME_LEN]; char *end; - if (nbytes > MAX_DRC_NAME_LEN) + if (nbytes >= MAX_DRC_NAME_LEN) return 0; memcpy(drc_name, buf, nbytes); diff --git a/drivers/pci/hotplug/sgi_hotplug.c b/drivers/pci/hotplug/sgi_hotplug.c index b140944..a32ae82 100644 --- a/drivers/pci/hotplug/sgi_hotplug.c +++ b/drivers/pci/hotplug/sgi_hotplug.c @@ -159,7 +159,7 @@ static int sn_hp_slot_private_alloc(struct hotplug_slot *bss_hotplug_slot, pcibus_info = SN_PCIBUS_BUSSOFT_INFO(pci_bus); - slot = kcalloc(1, sizeof(*slot), GFP_KERNEL); + slot = kzalloc(sizeof(*slot), GFP_KERNEL); if (!slot) return -ENOMEM; bss_hotplug_slot->private = slot; @@ -491,7 +491,7 @@ static int sn_hotplug_slot_register(struct pci_bus *pci_bus) if (sn_pci_slot_valid(pci_bus, device) != 1) continue; - bss_hotplug_slot = kcalloc(1, sizeof(*bss_hotplug_slot), + bss_hotplug_slot = kzalloc(sizeof(*bss_hotplug_slot), GFP_KERNEL); if (!bss_hotplug_slot) { rc = -ENOMEM; @@ -499,7 +499,7 @@ static int sn_hotplug_slot_register(struct pci_bus *pci_bus) } bss_hotplug_slot->info = - kcalloc(1, sizeof(struct hotplug_slot_info), + kzalloc(sizeof(struct hotplug_slot_info), GFP_KERNEL); if (!bss_hotplug_slot->info) { rc = -ENOMEM; diff --git a/drivers/pci/hotplug/shpchp_ctrl.c b/drivers/pci/hotplug/shpchp_ctrl.c index 783b5ab..91c9903 100644 --- a/drivers/pci/hotplug/shpchp_ctrl.c +++ b/drivers/pci/hotplug/shpchp_ctrl.c @@ -2824,8 +2824,7 @@ static int configure_new_function (struct controller * ctrl, struct pci_func * f } #endif /* Disable ROM base Address */ - temp_word = 0x00L; - rc = pci_bus_write_config_word (pci_bus, devfn, PCI_ROM_ADDRESS, temp_word); + rc = pci_bus_write_config_dword (pci_bus, devfn, PCI_ROM_ADDRESS, 0x00); /* Set HP parameters (Cache Line Size, Latency Timer) */ rc = shpchprm_set_hpp(ctrl, func, PCI_HEADER_TYPE_NORMAL); diff --git a/drivers/pci/pci-sysfs.c b/drivers/pci/pci-sysfs.c index 56a3b39..2898830 100644 --- a/drivers/pci/pci-sysfs.c +++ b/drivers/pci/pci-sysfs.c @@ -360,7 +360,7 @@ pci_create_resource_files(struct pci_dev *pdev) continue; /* allocate attribute structure, piggyback attribute name */ - res_attr = kcalloc(1, sizeof(*res_attr) + 10, GFP_ATOMIC); + res_attr = kzalloc(sizeof(*res_attr) + 10, GFP_ATOMIC); if (res_attr) { char *res_attr_name = (char *)(res_attr + 1); diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index 992db89..259d247 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -309,17 +309,25 @@ pci_set_power_state(struct pci_dev *dev, pci_power_t state) pci_read_config_word(dev, pm + PCI_PM_CTRL, &pmcsr); - /* If we're in D3, force entire word to 0. + /* If we're (effectively) in D3, force entire word to 0. * This doesn't affect PME_Status, disables PME_En, and * sets PowerState to 0. */ - if (dev->current_state >= PCI_D3hot) { - if (!(pmcsr & PCI_PM_CTRL_NO_SOFT_RESET)) + switch (dev->current_state) { + case PCI_UNKNOWN: /* Boot-up */ + if ((pmcsr & PCI_PM_CTRL_STATE_MASK) == PCI_D3hot + && !(pmcsr & PCI_PM_CTRL_NO_SOFT_RESET)) need_restore = 1; + /* Fall-through: force to D0 */ + case PCI_D3hot: + case PCI_D3cold: + case PCI_POWER_ERROR: pmcsr = 0; - } else { + break; + default: pmcsr &= ~PCI_PM_CTRL_STATE_MASK; pmcsr |= state; + break; } /* enter specified state */ diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c index 26a55d0..0057864 100644 --- a/drivers/pci/probe.c +++ b/drivers/pci/probe.c @@ -165,7 +165,7 @@ static void pci_read_bases(struct pci_dev *dev, unsigned int howmany, int rom) if (l == 0xffffffff) l = 0; if ((l & PCI_BASE_ADDRESS_SPACE) == PCI_BASE_ADDRESS_SPACE_MEMORY) { - sz = pci_size(l, sz, PCI_BASE_ADDRESS_MEM_MASK); + sz = pci_size(l, sz, (u32)PCI_BASE_ADDRESS_MEM_MASK); if (!sz) continue; res->start = l & PCI_BASE_ADDRESS_MEM_MASK; @@ -215,7 +215,7 @@ static void pci_read_bases(struct pci_dev *dev, unsigned int howmany, int rom) if (l == 0xffffffff) l = 0; if (sz && sz != 0xffffffff) { - sz = pci_size(l, sz, PCI_ROM_ADDRESS_MASK); + sz = pci_size(l, sz, (u32)PCI_ROM_ADDRESS_MASK); if (sz) { res->flags = (l & IORESOURCE_ROM_ENABLE) | IORESOURCE_MEM | IORESOURCE_PREFETCH | @@ -402,6 +402,12 @@ static void pci_enable_crs(struct pci_dev *dev) static void __devinit pci_fixup_parent_subordinate_busnr(struct pci_bus *child, int max) { struct pci_bus *parent = child->parent; + + /* Attempts to fix that up are really dangerous unless + we're going to re-assign all bus numbers. */ + if (!pcibios_assign_all_busses()) + return; + while (parent->parent && parent->subordinate < max) { parent->subordinate = max; pci_write_config_byte(parent->self, PCI_SUBORDINATE_BUS, max); @@ -478,8 +484,18 @@ int __devinit pci_scan_bridge(struct pci_bus *bus, struct pci_dev * dev, int max * We need to assign a number to this bus which we always * do in the second pass. */ - if (!pass) + if (!pass) { + if (pcibios_assign_all_busses()) + /* Temporarily disable forwarding of the + configuration cycles on all bridges in + this bus segment to avoid possible + conflicts in the second pass between two + bridges programmed with overlapping + bus ranges. */ + pci_write_config_dword(dev, PCI_PRIMARY_BUS, + buses & ~0xffffff); return max; + } /* Clear errors */ pci_write_config_word(dev, PCI_STATUS, 0xffff); diff --git a/drivers/pcmcia/pcmcia_ioctl.c b/drivers/pcmcia/pcmcia_ioctl.c index 39ba640..80969f7 100644 --- a/drivers/pcmcia/pcmcia_ioctl.c +++ b/drivers/pcmcia/pcmcia_ioctl.c @@ -376,6 +376,7 @@ static int ds_open(struct inode *inode, struct file *file) socket_t i = iminor(inode); struct pcmcia_socket *s; user_info_t *user; + static int warning_printed = 0; ds_dbg(0, "ds_open(socket %d)\n", i); @@ -407,6 +408,17 @@ static int ds_open(struct inode *inode, struct file *file) s->user = user; file->private_data = user; + if (!warning_printed) { + printk(KERN_INFO "pcmcia: Detected deprecated PCMCIA ioctl " + "usage.\n"); + printk(KERN_INFO "pcmcia: This interface will soon be removed from " + "the kernel; please expect breakage unless you upgrade " + "to new tools.\n"); + printk(KERN_INFO "pcmcia: see http://www.kernel.org/pub/linux/" + "utils/kernel/pcmcia/pcmcia.html for details.\n"); + warning_printed = 1; + } + if (s->pcmcia_state.present) queue_event(user, CS_EVENT_CARD_INSERTION); return 0; diff --git a/drivers/pcmcia/yenta_socket.c b/drivers/pcmcia/yenta_socket.c index f0997c3..ba4d78e 100644 --- a/drivers/pcmcia/yenta_socket.c +++ b/drivers/pcmcia/yenta_socket.c @@ -1045,7 +1045,18 @@ static int __devinit yenta_probe (struct pci_dev *dev, const struct pci_device_i { struct yenta_socket *socket; int ret; - + + /* + * If we failed to assign proper bus numbers for this cardbus + * controller during PCI probe, its subordinate pci_bus is NULL. + * Bail out if so. + */ + if (!dev->subordinate) { + printk(KERN_ERR "Yenta: no bus associated with %s! " + "(try 'pci=assign-busses')\n", pci_name(dev)); + return -ENODEV; + } + socket = kmalloc(sizeof(struct yenta_socket), GFP_KERNEL); if (!socket) return -ENOMEM; diff --git a/drivers/s390/cio/blacklist.c b/drivers/s390/cio/blacklist.c index aac83ce..a1c52a6 100644 --- a/drivers/s390/cio/blacklist.c +++ b/drivers/s390/cio/blacklist.c @@ -1,7 +1,7 @@ /* * drivers/s390/cio/blacklist.c * S/390 common I/O routines -- blacklisting of specific devices - * $Revision: 1.34 $ + * $Revision: 1.35 $ * * Copyright (C) 1999-2002 IBM Deutschland Entwicklung GmbH, * IBM Corporation @@ -35,7 +35,7 @@ */ /* 65536 bits to indicate if a devno is blacklisted or not */ -#define __BL_DEV_WORDS (__MAX_SUBCHANNELS + (8*sizeof(long) - 1) / \ +#define __BL_DEV_WORDS ((__MAX_SUBCHANNELS + (8*sizeof(long) - 1)) / \ (8*sizeof(long))) static unsigned long bl_dev[__BL_DEV_WORDS]; typedef enum {add, free} range_action; diff --git a/drivers/s390/cio/ccwgroup.c b/drivers/s390/cio/ccwgroup.c index 91ea8e4..dbb3eb0 100644 --- a/drivers/s390/cio/ccwgroup.c +++ b/drivers/s390/cio/ccwgroup.c @@ -437,7 +437,7 @@ __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)) { - if (klist_node_attached(&gdev->dev.knode_bus)) + if (device_is_registered(&gdev->dev)) return gdev; put_device(&gdev->dev); } diff --git a/drivers/s390/crypto/z90main.c b/drivers/s390/crypto/z90main.c index 6aeef3b..0cb47ec 100644 --- a/drivers/s390/crypto/z90main.c +++ b/drivers/s390/crypto/z90main.c @@ -682,9 +682,6 @@ z90crypt_cleanup_module(void) del_timer(&config_timer); del_timer(&cleanup_timer); - if (z90_device_work) - destroy_workqueue(z90_device_work); - destroy_z90crypt(); PRINTKN("Unloaded.\n"); diff --git a/drivers/s390/net/ctcmain.c b/drivers/s390/net/ctcmain.c index 96ca863..0db4f57 100644 --- a/drivers/s390/net/ctcmain.c +++ b/drivers/s390/net/ctcmain.c @@ -1,5 +1,5 @@ /* - * $Id: ctcmain.c,v 1.74 2005/03/24 09:04:17 mschwide Exp $ + * $Id: ctcmain.c,v 1.78 2005/09/07 12:18:02 pavlic Exp $ * * CTC / ESCON network driver * @@ -37,10 +37,9 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * - * RELEASE-TAG: CTC/ESCON network driver $Revision: 1.74 $ + * RELEASE-TAG: CTC/ESCON network driver $Revision: 1.78 $ * */ - #undef DEBUG #include <linux/module.h> #include <linux/init.h> @@ -135,7 +134,7 @@ static const char *dev_event_names[] = { "TX down", "Restart", }; - + /** * Events of the channel statemachine */ @@ -249,7 +248,7 @@ static void print_banner(void) { static int printed = 0; - char vbuf[] = "$Revision: 1.74 $"; + char vbuf[] = "$Revision: 1.78 $"; char *version = vbuf; if (printed) @@ -334,7 +333,7 @@ static const char *ch_state_names[] = { "Restarting", "Not operational", }; - + #ifdef DEBUG /** * Dump header and first 16 bytes of an sk_buff for debugging purposes. @@ -671,7 +670,7 @@ static void fsm_action_nop(fsm_instance * fi, int event, void *arg) { } - + /** * Actions for channel - statemachines. *****************************************************************************/ @@ -1514,7 +1513,6 @@ ch_action_reinit(fsm_instance *fi, int event, void *arg) fsm_addtimer(&privptr->restart_timer, 1000, DEV_EVENT_RESTART, dev); } - /** * The statemachine for a channel. */ @@ -1625,7 +1623,7 @@ static const fsm_node ch_fsm[] = { }; static const int CH_FSM_LEN = sizeof (ch_fsm) / sizeof (fsm_node); - + /** * Functions related to setup and device detection. *****************************************************************************/ @@ -1976,7 +1974,7 @@ ctc_irq_handler(struct ccw_device *cdev, unsigned long intparm, struct irb *irb) fsm_event(ch->fsm, CH_EVENT_IRQ, ch); } - + /** * Actions for interface - statemachine. *****************************************************************************/ @@ -2209,13 +2207,18 @@ transmit_skb(struct channel *ch, struct sk_buff *skb) int rc = 0; DBF_TEXT(trace, 5, __FUNCTION__); + /* we need to acquire the lock for testing the state + * otherwise we can have an IRQ changing the state to + * TXIDLE after the test but before acquiring the lock. + */ + spin_lock_irqsave(&ch->collect_lock, saveflags); if (fsm_getstate(ch->fsm) != CH_STATE_TXIDLE) { int l = skb->len + LL_HEADER_LENGTH; - spin_lock_irqsave(&ch->collect_lock, saveflags); - if (ch->collect_len + l > ch->max_bufsize - 2) - rc = -EBUSY; - else { + if (ch->collect_len + l > ch->max_bufsize - 2) { + spin_unlock_irqrestore(&ch->collect_lock, saveflags); + return -EBUSY; + } else { atomic_inc(&skb->users); header.length = l; header.type = skb->protocol; @@ -2231,7 +2234,7 @@ transmit_skb(struct channel *ch, struct sk_buff *skb) int ccw_idx; struct sk_buff *nskb; unsigned long hi; - + spin_unlock_irqrestore(&ch->collect_lock, saveflags); /** * Protect skb against beeing free'd by upper * layers. @@ -2256,6 +2259,7 @@ transmit_skb(struct channel *ch, struct sk_buff *skb) if (!nskb) { atomic_dec(&skb->users); skb_pull(skb, LL_HEADER_LENGTH + 2); + ctc_clear_busy(ch->netdev); return -ENOMEM; } else { memcpy(skb_put(nskb, skb->len), @@ -2281,6 +2285,7 @@ transmit_skb(struct channel *ch, struct sk_buff *skb) */ atomic_dec(&skb->users); skb_pull(skb, LL_HEADER_LENGTH + 2); + ctc_clear_busy(ch->netdev); return -EBUSY; } @@ -2327,9 +2332,10 @@ transmit_skb(struct channel *ch, struct sk_buff *skb) } } + ctc_clear_busy(ch->netdev); return rc; } - + /** * Interface API for upper network layers *****************************************************************************/ @@ -2421,7 +2427,6 @@ ctc_tx(struct sk_buff *skb, struct net_device * dev) dev->trans_start = jiffies; if (transmit_skb(privptr->channel[WRITE], skb) != 0) rc = 1; - ctc_clear_busy(dev); return rc; } @@ -2610,7 +2615,6 @@ stats_write(struct device *dev, struct device_attribute *attr, const char *buf, return count; } - static void ctc_netdev_unregister(struct net_device * dev) { @@ -2685,7 +2689,6 @@ ctc_proto_store(struct device *dev, struct device_attribute *attr, const char *b return count; } - static ssize_t ctc_type_show(struct device *dev, struct device_attribute *attr, char *buf) { diff --git a/drivers/s390/net/qeth.h b/drivers/s390/net/qeth.h index 3a02856..2ad4797 100644 --- a/drivers/s390/net/qeth.h +++ b/drivers/s390/net/qeth.h @@ -24,7 +24,7 @@ #include "qeth_mpc.h" -#define VERSION_QETH_H "$Revision: 1.139 $" +#define VERSION_QETH_H "$Revision: 1.142 $" #ifdef CONFIG_QETH_IPV6 #define QETH_VERSION_IPV6 ":IPv6" @@ -1172,7 +1172,7 @@ extern int qeth_realloc_buffer_pool(struct qeth_card *, int); extern int -qeth_set_large_send(struct qeth_card *); +qeth_set_large_send(struct qeth_card *, enum qeth_large_send_types); extern void qeth_fill_header(struct qeth_card *, struct qeth_hdr *, diff --git a/drivers/s390/net/qeth_main.c b/drivers/s390/net/qeth_main.c index 79c74f3..86582cf 100644 --- a/drivers/s390/net/qeth_main.c +++ b/drivers/s390/net/qeth_main.c @@ -1,6 +1,6 @@ /* * - * linux/drivers/s390/net/qeth_main.c ($Revision: 1.214 $) + * linux/drivers/s390/net/qeth_main.c ($Revision: 1.224 $) * * Linux on zSeries OSA Express and HiperSockets support * @@ -12,7 +12,7 @@ * Frank Pavlic (pavlic@de.ibm.com) and * Thomas Spatzier <tspat@de.ibm.com> * - * $Revision: 1.214 $ $Date: 2005/05/04 20:19:18 $ + * $Revision: 1.224 $ $Date: 2005/05/04 20:19:18 $ * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -29,14 +29,6 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -/*** - * eye catcher; just for debugging purposes - */ -void volatile -qeth_eyecatcher(void) -{ - return; -} #include <linux/config.h> #include <linux/module.h> @@ -80,7 +72,7 @@ qeth_eyecatcher(void) #include "qeth_eddp.h" #include "qeth_tso.h" -#define VERSION_QETH_C "$Revision: 1.214 $" +#define VERSION_QETH_C "$Revision: 1.224 $" static const char *version = "qeth S/390 OSA-Express driver"; /** @@ -2759,11 +2751,9 @@ qeth_flush_buffers(struct qeth_qdio_out_q *queue, int under_int, queue->card->perf_stats.outbound_do_qdio_start_time; #endif if (rc){ - QETH_DBF_SPRINTF(trace, 0, "qeth_flush_buffers: do_QDIO " - "returned error (%i) on device %s.", - rc, CARD_DDEV_ID(queue->card)); QETH_DBF_TEXT(trace, 2, "flushbuf"); QETH_DBF_TEXT_(trace, 2, " err%d", rc); + QETH_DBF_TEXT_(trace, 2, "%s", CARD_DDEV_ID(queue->card)); queue->card->stats.tx_errors += count; /* this must not happen under normal circumstances. if it * happens something is really wrong -> recover */ @@ -2909,11 +2899,8 @@ qeth_qdio_output_handler(struct ccw_device * ccwdev, unsigned int status, QETH_DBF_TEXT(trace, 6, "qdouhdl"); if (status & QDIO_STATUS_LOOK_FOR_ERROR) { if (status & QDIO_STATUS_ACTIVATE_CHECK_CONDITION){ - QETH_DBF_SPRINTF(trace, 2, "On device %s: " - "received active check " - "condition (0x%08x).", - CARD_BUS_ID(card), status); - QETH_DBF_TEXT(trace, 2, "chkcond"); + QETH_DBF_TEXT(trace, 2, "achkcond"); + QETH_DBF_TEXT_(trace, 2, "%s", CARD_BUS_ID(card)); QETH_DBF_TEXT_(trace, 2, "%08x", status); netif_stop_queue(card->dev); qeth_schedule_recovery(card); @@ -3356,26 +3343,32 @@ qeth_halt_channel(struct qeth_channel *channel) static int qeth_halt_channels(struct qeth_card *card) { - int rc = 0; + int rc1 = 0, rc2=0, rc3 = 0; QETH_DBF_TEXT(trace,3,"haltchs"); - if ((rc = qeth_halt_channel(&card->read))) - return rc; - if ((rc = qeth_halt_channel(&card->write))) - return rc; - return qeth_halt_channel(&card->data); + rc1 = qeth_halt_channel(&card->read); + rc2 = qeth_halt_channel(&card->write); + rc3 = qeth_halt_channel(&card->data); + if (rc1) + return rc1; + if (rc2) + return rc2; + return rc3; } static int qeth_clear_channels(struct qeth_card *card) { - int rc = 0; + int rc1 = 0, rc2=0, rc3 = 0; QETH_DBF_TEXT(trace,3,"clearchs"); - if ((rc = qeth_clear_channel(&card->read))) - return rc; - if ((rc = qeth_clear_channel(&card->write))) - return rc; - return qeth_clear_channel(&card->data); + rc1 = qeth_clear_channel(&card->read); + rc2 = qeth_clear_channel(&card->write); + rc3 = qeth_clear_channel(&card->data); + if (rc1) + return rc1; + if (rc2) + return rc2; + return rc3; } static int @@ -3445,23 +3438,23 @@ qeth_mpc_initialize(struct qeth_card *card) } if ((rc = qeth_cm_enable(card))){ QETH_DBF_TEXT_(setup, 2, "2err%d", rc); - return rc; + goto out_qdio; } if ((rc = qeth_cm_setup(card))){ QETH_DBF_TEXT_(setup, 2, "3err%d", rc); - return rc; + goto out_qdio; } if ((rc = qeth_ulp_enable(card))){ QETH_DBF_TEXT_(setup, 2, "4err%d", rc); - return rc; + goto out_qdio; } if ((rc = qeth_ulp_setup(card))){ QETH_DBF_TEXT_(setup, 2, "5err%d", rc); - return rc; + goto out_qdio; } if ((rc = qeth_alloc_qdio_buffers(card))){ QETH_DBF_TEXT_(setup, 2, "5err%d", rc); - return rc; + goto out_qdio; } if ((rc = qeth_qdio_establish(card))){ QETH_DBF_TEXT_(setup, 2, "6err%d", rc); @@ -3795,12 +3788,16 @@ static inline int qeth_prepare_skb(struct qeth_card *card, struct sk_buff **skb, struct qeth_hdr **hdr, int ipv) { + int rc; #ifdef CONFIG_QETH_VLAN u16 *tag; #endif QETH_DBF_TEXT(trace, 6, "prepskb"); + rc = qeth_realloc_headroom(card, skb, sizeof(struct qeth_hdr)); + if (rc) + return rc; #ifdef CONFIG_QETH_VLAN if (card->vlangrp && vlan_tx_tag_present(*skb) && ((ipv == 6) || card->options.layer2) ) { @@ -4251,7 +4248,8 @@ out: } static inline int -qeth_get_elements_no(struct qeth_card *card, void *hdr, struct sk_buff *skb) +qeth_get_elements_no(struct qeth_card *card, void *hdr, + struct sk_buff *skb, int elems) { int elements_needed = 0; @@ -4261,9 +4259,10 @@ qeth_get_elements_no(struct qeth_card *card, void *hdr, struct sk_buff *skb) if (elements_needed == 0 ) elements_needed = 1 + (((((unsigned long) hdr) % PAGE_SIZE) + skb->len) >> PAGE_SHIFT); - if (elements_needed > QETH_MAX_BUFFER_ELEMENTS(card)){ + if ((elements_needed + elems) > QETH_MAX_BUFFER_ELEMENTS(card)){ PRINT_ERR("qeth_do_send_packet: invalid size of " - "IP packet. Discarded."); + "IP packet (Number=%d / Length=%d). Discarded.\n", + (elements_needed+elems), skb->len); return 0; } return elements_needed; @@ -4275,7 +4274,7 @@ qeth_send_packet(struct qeth_card *card, struct sk_buff *skb) int ipv = 0; int cast_type; struct qeth_qdio_out_q *queue; - struct qeth_hdr *hdr; + struct qeth_hdr *hdr = NULL; int elements_needed = 0; enum qeth_large_send_types large_send = QETH_LARGE_SEND_NO; struct qeth_eddp_context *ctx = NULL; @@ -4337,9 +4336,11 @@ qeth_send_packet(struct qeth_card *card, struct sk_buff *skb) return -EINVAL; } } else { - elements_needed += qeth_get_elements_no(card,(void*) hdr, skb); - if (!elements_needed) + int elems = qeth_get_elements_no(card,(void*) hdr, skb, + elements_needed); + if (!elems) return -EINVAL; + elements_needed += elems; } if (card->info.type != QETH_CARD_TYPE_IQD) @@ -4504,7 +4505,11 @@ qeth_arp_set_no_entries(struct qeth_card *card, int no_entries) QETH_DBF_TEXT(trace,3,"arpstnoe"); - /* TODO: really not supported by GuestLAN? */ + /* + * currently GuestLAN only supports the ARP assist function + * IPA_CMD_ASS_ARP_QUERY_INFO, but not IPA_CMD_ASS_ARP_SET_NO_ENTRIES; + * thus we say EOPNOTSUPP for this ARP function + */ if (card->info.guestlan) return -EOPNOTSUPP; if (!qeth_is_supported(card,IPA_ARP_PROCESSING)) { @@ -4681,14 +4686,6 @@ qeth_arp_query(struct qeth_card *card, char *udata) QETH_DBF_TEXT(trace,3,"arpquery"); - /* - * currently GuestLAN does only deliver all zeros on query arp, - * even though arp processing is supported (according to IPA supp. - * funcs flags); since all zeros is no valueable information, - * we say EOPNOTSUPP for all ARP functions - */ - /*if (card->info.guestlan) - return -EOPNOTSUPP; */ if (!qeth_is_supported(card,/*IPA_QUERY_ARP_ADDR_INFO*/ IPA_ARP_PROCESSING)) { PRINT_WARN("ARP processing not supported " @@ -4894,10 +4891,9 @@ qeth_arp_add_entry(struct qeth_card *card, struct qeth_arp_cache_entry *entry) QETH_DBF_TEXT(trace,3,"arpadent"); /* - * currently GuestLAN does only deliver all zeros on query arp, - * even though arp processing is supported (according to IPA supp. - * funcs flags); since all zeros is no valueable information, - * we say EOPNOTSUPP for all ARP functions + * currently GuestLAN only supports the ARP assist function + * IPA_CMD_ASS_ARP_QUERY_INFO, but not IPA_CMD_ASS_ARP_ADD_ENTRY; + * thus we say EOPNOTSUPP for this ARP function */ if (card->info.guestlan) return -EOPNOTSUPP; @@ -4937,10 +4933,9 @@ qeth_arp_remove_entry(struct qeth_card *card, struct qeth_arp_cache_entry *entry QETH_DBF_TEXT(trace,3,"arprment"); /* - * currently GuestLAN does only deliver all zeros on query arp, - * even though arp processing is supported (according to IPA supp. - * funcs flags); since all zeros is no valueable information, - * we say EOPNOTSUPP for all ARP functions + * currently GuestLAN only supports the ARP assist function + * IPA_CMD_ASS_ARP_QUERY_INFO, but not IPA_CMD_ASS_ARP_REMOVE_ENTRY; + * thus we say EOPNOTSUPP for this ARP function */ if (card->info.guestlan) return -EOPNOTSUPP; @@ -4978,11 +4973,10 @@ qeth_arp_flush_cache(struct qeth_card *card) QETH_DBF_TEXT(trace,3,"arpflush"); /* - * currently GuestLAN does only deliver all zeros on query arp, - * even though arp processing is supported (according to IPA supp. - * funcs flags); since all zeros is no valueable information, - * we say EOPNOTSUPP for all ARP functions - */ + * currently GuestLAN only supports the ARP assist function + * IPA_CMD_ASS_ARP_QUERY_INFO, but not IPA_CMD_ASS_ARP_FLUSH_CACHE; + * thus we say EOPNOTSUPP for this ARP function + */ if (card->info.guestlan || (card->info.type == QETH_CARD_TYPE_IQD)) return -EOPNOTSUPP; if (!qeth_is_supported(card,IPA_ARP_PROCESSING)) { @@ -7038,14 +7032,16 @@ qeth_setrouting_v6(struct qeth_card *card) } int -qeth_set_large_send(struct qeth_card *card) +qeth_set_large_send(struct qeth_card *card, enum qeth_large_send_types type) { int rc = 0; - if (card->dev == NULL) + if (card->dev == NULL) { + card->options.large_send = type; return 0; - + } netif_stop_queue(card->dev); + card->options.large_send = type; switch (card->options.large_send) { case QETH_LARGE_SEND_EDDP: card->dev->features |= NETIF_F_TSO | NETIF_F_SG; @@ -7066,7 +7062,6 @@ qeth_set_large_send(struct qeth_card *card) card->dev->features &= ~(NETIF_F_TSO | NETIF_F_SG); break; } - netif_wake_queue(card->dev); return rc; } @@ -8257,7 +8252,6 @@ qeth_init(void) { int rc=0; - qeth_eyecatcher(); PRINT_INFO("loading %s (%s/%s/%s/%s/%s/%s/%s %s %s)\n", version, VERSION_QETH_C, VERSION_QETH_H, VERSION_QETH_MPC_H, VERSION_QETH_MPC_C, @@ -8338,7 +8332,6 @@ again: printk("qeth: removed\n"); } -EXPORT_SYMBOL(qeth_eyecatcher); module_init(qeth_init); module_exit(qeth_exit); MODULE_AUTHOR("Frank Pavlic <pavlic@de.ibm.com>"); diff --git a/drivers/s390/net/qeth_sys.c b/drivers/s390/net/qeth_sys.c index 98bedb0..dda105b 100644 --- a/drivers/s390/net/qeth_sys.c +++ b/drivers/s390/net/qeth_sys.c @@ -1,6 +1,6 @@ /* * - * linux/drivers/s390/net/qeth_sys.c ($Revision: 1.51 $) + * linux/drivers/s390/net/qeth_sys.c ($Revision: 1.54 $) * * Linux on zSeries OSA Express and HiperSockets support * This file contains code related to sysfs. @@ -20,7 +20,7 @@ #include "qeth_mpc.h" #include "qeth_fs.h" -const char *VERSION_QETH_SYS_C = "$Revision: 1.51 $"; +const char *VERSION_QETH_SYS_C = "$Revision: 1.54 $"; /*****************************************************************************/ /* */ @@ -722,10 +722,13 @@ qeth_dev_layer2_store(struct device *dev, struct device_attribute *attr, const c if (!card) return -EINVAL; + if (card->info.type == QETH_CARD_TYPE_IQD) { + PRINT_WARN("Layer2 on Hipersockets is not supported! \n"); + return -EPERM; + } if (((card->state != CARD_STATE_DOWN) && - (card->state != CARD_STATE_RECOVER)) || - (card->info.type != QETH_CARD_TYPE_OSAE)) + (card->state != CARD_STATE_RECOVER))) return -EPERM; i = simple_strtoul(buf, &tmp, 16); @@ -771,9 +774,7 @@ qeth_dev_large_send_store(struct device *dev, struct device_attribute *attr, con if (!card) return -EINVAL; - tmp = strsep((char **) &buf, "\n"); - if (!strcmp(tmp, "no")){ type = QETH_LARGE_SEND_NO; } else if (!strcmp(tmp, "EDDP")) { @@ -786,10 +787,8 @@ qeth_dev_large_send_store(struct device *dev, struct device_attribute *attr, con } if (card->options.large_send == type) return count; - card->options.large_send = type; - if ((rc = qeth_set_large_send(card))) + if ((rc = qeth_set_large_send(card, type))) return rc; - return count; } diff --git a/drivers/s390/scsi/Makefile b/drivers/s390/scsi/Makefile index fc14530..d6a78f1 100644 --- a/drivers/s390/scsi/Makefile +++ b/drivers/s390/scsi/Makefile @@ -3,7 +3,7 @@ # zfcp-objs := zfcp_aux.o zfcp_ccw.o zfcp_scsi.o zfcp_erp.o zfcp_qdio.o \ - zfcp_fsf.o zfcp_sysfs_adapter.o zfcp_sysfs_port.o \ + zfcp_fsf.o zfcp_dbf.o zfcp_sysfs_adapter.o zfcp_sysfs_port.o \ zfcp_sysfs_unit.o zfcp_sysfs_driver.o obj-$(CONFIG_ZFCP) += zfcp.o diff --git a/drivers/s390/scsi/zfcp_aux.c b/drivers/s390/scsi/zfcp_aux.c index bfe3ba7..0b5087f 100644 --- a/drivers/s390/scsi/zfcp_aux.c +++ b/drivers/s390/scsi/zfcp_aux.c @@ -122,95 +122,6 @@ _zfcp_hex_dump(char *addr, int count) #define ZFCP_LOG_AREA ZFCP_LOG_AREA_OTHER -static inline int -zfcp_fsf_req_is_scsi_cmnd(struct zfcp_fsf_req *fsf_req) -{ - return ((fsf_req->fsf_command == FSF_QTCB_FCP_CMND) && - !(fsf_req->status & ZFCP_STATUS_FSFREQ_TASK_MANAGEMENT)); -} - -void -zfcp_cmd_dbf_event_fsf(const char *text, struct zfcp_fsf_req *fsf_req, - void *add_data, int add_length) -{ - struct zfcp_adapter *adapter = fsf_req->adapter; - struct scsi_cmnd *scsi_cmnd; - int level = 3; - int i; - unsigned long flags; - - spin_lock_irqsave(&adapter->dbf_lock, flags); - if (zfcp_fsf_req_is_scsi_cmnd(fsf_req)) { - scsi_cmnd = fsf_req->data.send_fcp_command_task.scsi_cmnd; - debug_text_event(adapter->cmd_dbf, level, "fsferror"); - debug_text_event(adapter->cmd_dbf, level, text); - debug_event(adapter->cmd_dbf, level, &fsf_req, - sizeof (unsigned long)); - debug_event(adapter->cmd_dbf, level, &fsf_req->seq_no, - sizeof (u32)); - debug_event(adapter->cmd_dbf, level, &scsi_cmnd, - sizeof (unsigned long)); - debug_event(adapter->cmd_dbf, level, &scsi_cmnd->cmnd, - min(ZFCP_CMD_DBF_LENGTH, (int)scsi_cmnd->cmd_len)); - for (i = 0; i < add_length; i += ZFCP_CMD_DBF_LENGTH) - debug_event(adapter->cmd_dbf, - level, - (char *) add_data + i, - min(ZFCP_CMD_DBF_LENGTH, add_length - i)); - } - spin_unlock_irqrestore(&adapter->dbf_lock, flags); -} - -/* XXX additionally log unit if available */ -/* ---> introduce new parameter for unit, see 2.4 code */ -void -zfcp_cmd_dbf_event_scsi(const char *text, struct scsi_cmnd *scsi_cmnd) -{ - struct zfcp_adapter *adapter; - union zfcp_req_data *req_data; - struct zfcp_fsf_req *fsf_req; - int level = ((host_byte(scsi_cmnd->result) != 0) ? 1 : 5); - unsigned long flags; - - adapter = (struct zfcp_adapter *) scsi_cmnd->device->host->hostdata[0]; - req_data = (union zfcp_req_data *) scsi_cmnd->host_scribble; - fsf_req = (req_data ? req_data->send_fcp_command_task.fsf_req : NULL); - spin_lock_irqsave(&adapter->dbf_lock, flags); - debug_text_event(adapter->cmd_dbf, level, "hostbyte"); - debug_text_event(adapter->cmd_dbf, level, text); - debug_event(adapter->cmd_dbf, level, &scsi_cmnd->result, sizeof (u32)); - debug_event(adapter->cmd_dbf, level, &scsi_cmnd, - sizeof (unsigned long)); - debug_event(adapter->cmd_dbf, level, &scsi_cmnd->cmnd, - min(ZFCP_CMD_DBF_LENGTH, (int)scsi_cmnd->cmd_len)); - if (likely(fsf_req)) { - debug_event(adapter->cmd_dbf, level, &fsf_req, - sizeof (unsigned long)); - debug_event(adapter->cmd_dbf, level, &fsf_req->seq_no, - sizeof (u32)); - } else { - debug_text_event(adapter->cmd_dbf, level, ""); - debug_text_event(adapter->cmd_dbf, level, ""); - } - spin_unlock_irqrestore(&adapter->dbf_lock, flags); -} - -void -zfcp_in_els_dbf_event(struct zfcp_adapter *adapter, const char *text, - struct fsf_status_read_buffer *status_buffer, int length) -{ - int level = 1; - int i; - - debug_text_event(adapter->in_els_dbf, level, text); - debug_event(adapter->in_els_dbf, level, &status_buffer->d_id, 8); - for (i = 0; i < length; i += ZFCP_IN_ELS_DBF_LENGTH) - debug_event(adapter->in_els_dbf, - level, - (char *) status_buffer->payload + i, - min(ZFCP_IN_ELS_DBF_LENGTH, length - i)); -} - /** * zfcp_device_setup - setup function * @str: pointer to parameter string @@ -1017,81 +928,6 @@ zfcp_free_low_mem_buffers(struct zfcp_adapter *adapter) mempool_destroy(adapter->pool.data_gid_pn); } -/** - * zfcp_adapter_debug_register - registers debug feature for an adapter - * @adapter: pointer to adapter for which debug features should be registered - * return: -ENOMEM on error, 0 otherwise - */ -int -zfcp_adapter_debug_register(struct zfcp_adapter *adapter) -{ - char dbf_name[20]; - - /* debug feature area which records SCSI command failures (hostbyte) */ - spin_lock_init(&adapter->dbf_lock); - - sprintf(dbf_name, ZFCP_CMD_DBF_NAME "%s", - zfcp_get_busid_by_adapter(adapter)); - adapter->cmd_dbf = debug_register(dbf_name, ZFCP_CMD_DBF_INDEX, - ZFCP_CMD_DBF_AREAS, - ZFCP_CMD_DBF_LENGTH); - debug_register_view(adapter->cmd_dbf, &debug_hex_ascii_view); - debug_set_level(adapter->cmd_dbf, ZFCP_CMD_DBF_LEVEL); - - /* debug feature area which records SCSI command aborts */ - sprintf(dbf_name, ZFCP_ABORT_DBF_NAME "%s", - zfcp_get_busid_by_adapter(adapter)); - adapter->abort_dbf = debug_register(dbf_name, ZFCP_ABORT_DBF_INDEX, - ZFCP_ABORT_DBF_AREAS, - ZFCP_ABORT_DBF_LENGTH); - debug_register_view(adapter->abort_dbf, &debug_hex_ascii_view); - debug_set_level(adapter->abort_dbf, ZFCP_ABORT_DBF_LEVEL); - - /* debug feature area which records incoming ELS commands */ - sprintf(dbf_name, ZFCP_IN_ELS_DBF_NAME "%s", - zfcp_get_busid_by_adapter(adapter)); - adapter->in_els_dbf = debug_register(dbf_name, ZFCP_IN_ELS_DBF_INDEX, - ZFCP_IN_ELS_DBF_AREAS, - ZFCP_IN_ELS_DBF_LENGTH); - debug_register_view(adapter->in_els_dbf, &debug_hex_ascii_view); - debug_set_level(adapter->in_els_dbf, ZFCP_IN_ELS_DBF_LEVEL); - - /* debug feature area which records erp events */ - sprintf(dbf_name, ZFCP_ERP_DBF_NAME "%s", - zfcp_get_busid_by_adapter(adapter)); - adapter->erp_dbf = debug_register(dbf_name, ZFCP_ERP_DBF_INDEX, - ZFCP_ERP_DBF_AREAS, - ZFCP_ERP_DBF_LENGTH); - debug_register_view(adapter->erp_dbf, &debug_hex_ascii_view); - debug_set_level(adapter->erp_dbf, ZFCP_ERP_DBF_LEVEL); - - if (!(adapter->cmd_dbf && adapter->abort_dbf && - adapter->in_els_dbf && adapter->erp_dbf)) { - zfcp_adapter_debug_unregister(adapter); - return -ENOMEM; - } - - return 0; - -} - -/** - * zfcp_adapter_debug_unregister - unregisters debug feature for an adapter - * @adapter: pointer to adapter for which debug features should be unregistered - */ -void -zfcp_adapter_debug_unregister(struct zfcp_adapter *adapter) -{ - debug_unregister(adapter->abort_dbf); - debug_unregister(adapter->cmd_dbf); - debug_unregister(adapter->erp_dbf); - debug_unregister(adapter->in_els_dbf); - adapter->abort_dbf = NULL; - adapter->cmd_dbf = NULL; - adapter->erp_dbf = NULL; - adapter->in_els_dbf = NULL; -} - void zfcp_dummy_release(struct device *dev) { @@ -1462,10 +1298,6 @@ zfcp_fsf_incoming_els_rscn(struct zfcp_adapter *adapter, /* see FC-FS */ no_entries = (fcp_rscn_head->payload_len / 4); - zfcp_in_els_dbf_event(adapter, "##rscn", status_buffer, - fcp_rscn_head->payload_len); - - debug_text_event(adapter->erp_dbf, 1, "unsol_els_rscn:"); for (i = 1; i < no_entries; i++) { /* skip head and start with 1st element */ fcp_rscn_element++; @@ -1497,8 +1329,6 @@ zfcp_fsf_incoming_els_rscn(struct zfcp_adapter *adapter, (ZFCP_STATUS_PORT_DID_DID, &port->status)) { ZFCP_LOG_INFO("incoming RSCN, trying to open " "port 0x%016Lx\n", port->wwpn); - debug_text_event(adapter->erp_dbf, 1, - "unsol_els_rscnu:"); zfcp_erp_port_reopen(port, ZFCP_STATUS_COMMON_ERP_FAILED); continue; @@ -1524,8 +1354,6 @@ zfcp_fsf_incoming_els_rscn(struct zfcp_adapter *adapter, */ ZFCP_LOG_INFO("incoming RSCN, trying to open " "port 0x%016Lx\n", port->wwpn); - debug_text_event(adapter->erp_dbf, 1, - "unsol_els_rscnk:"); zfcp_test_link(port); } } @@ -1541,8 +1369,6 @@ zfcp_fsf_incoming_els_plogi(struct zfcp_adapter *adapter, struct zfcp_port *port; unsigned long flags; - zfcp_in_els_dbf_event(adapter, "##plogi", status_buffer, 28); - read_lock_irqsave(&zfcp_data.config_lock, flags); list_for_each_entry(port, &adapter->port_list_head, list) { if (port->wwpn == (*(wwn_t *) & els_logi->nport_wwn)) @@ -1556,8 +1382,6 @@ zfcp_fsf_incoming_els_plogi(struct zfcp_adapter *adapter, status_buffer->d_id, zfcp_get_busid_by_adapter(adapter)); } else { - debug_text_event(adapter->erp_dbf, 1, "unsol_els_plogi:"); - debug_event(adapter->erp_dbf, 1, &els_logi->nport_wwn, 8); zfcp_erp_port_forced_reopen(port, 0); } } @@ -1570,8 +1394,6 @@ zfcp_fsf_incoming_els_logo(struct zfcp_adapter *adapter, struct zfcp_port *port; unsigned long flags; - zfcp_in_els_dbf_event(adapter, "##logo", status_buffer, 16); - read_lock_irqsave(&zfcp_data.config_lock, flags); list_for_each_entry(port, &adapter->port_list_head, list) { if (port->wwpn == els_logo->nport_wwpn) @@ -1585,8 +1407,6 @@ zfcp_fsf_incoming_els_logo(struct zfcp_adapter *adapter, status_buffer->d_id, zfcp_get_busid_by_adapter(adapter)); } else { - debug_text_event(adapter->erp_dbf, 1, "unsol_els_logo:"); - debug_event(adapter->erp_dbf, 1, &els_logo->nport_wwpn, 8); zfcp_erp_port_forced_reopen(port, 0); } } @@ -1595,7 +1415,6 @@ static void zfcp_fsf_incoming_els_unknown(struct zfcp_adapter *adapter, struct fsf_status_read_buffer *status_buffer) { - zfcp_in_els_dbf_event(adapter, "##undef", status_buffer, 24); ZFCP_LOG_NORMAL("warning: unknown incoming ELS 0x%08x " "for adapter %s\n", *(u32 *) (status_buffer->payload), zfcp_get_busid_by_adapter(adapter)); @@ -1609,10 +1428,11 @@ zfcp_fsf_incoming_els(struct zfcp_fsf_req *fsf_req) u32 els_type; struct zfcp_adapter *adapter; - status_buffer = fsf_req->data.status_read.buffer; + status_buffer = (struct fsf_status_read_buffer *) fsf_req->data; els_type = *(u32 *) (status_buffer->payload); adapter = fsf_req->adapter; + zfcp_san_dbf_event_incoming_els(fsf_req); if (els_type == LS_PLOGI) zfcp_fsf_incoming_els_plogi(adapter, status_buffer); else if (els_type == LS_LOGO) diff --git a/drivers/s390/scsi/zfcp_ccw.c b/drivers/s390/scsi/zfcp_ccw.c index b30abab..0fc4638 100644 --- a/drivers/s390/scsi/zfcp_ccw.c +++ b/drivers/s390/scsi/zfcp_ccw.c @@ -202,19 +202,9 @@ static int zfcp_ccw_set_offline(struct ccw_device *ccw_device) { struct zfcp_adapter *adapter; - struct zfcp_port *port; - struct fc_rport *rport; down(&zfcp_data.config_sema); adapter = dev_get_drvdata(&ccw_device->dev); - /* might be racy, but we cannot take config_lock due to the fact that - fc_remote_port_delete might sleep */ - list_for_each_entry(port, &adapter->port_list_head, list) - if (port->rport) { - rport = port->rport; - port->rport = NULL; - fc_remote_port_delete(rport); - } zfcp_erp_adapter_shutdown(adapter, 0); zfcp_erp_wait(adapter); zfcp_adapter_scsi_unregister(adapter); diff --git a/drivers/s390/scsi/zfcp_dbf.c b/drivers/s390/scsi/zfcp_dbf.c new file mode 100644 index 0000000..826fb3b --- /dev/null +++ b/drivers/s390/scsi/zfcp_dbf.c @@ -0,0 +1,995 @@ +/* + * + * linux/drivers/s390/scsi/zfcp_dbf.c + * + * FCP adapter driver for IBM eServer zSeries + * + * Debugging facilities + * + * (C) Copyright IBM Corp. 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. + */ + +#define ZFCP_DBF_REVISION "$Revision$" + +#include <asm/debug.h> +#include <linux/ctype.h> +#include "zfcp_ext.h" + +static u32 dbfsize = 4; + +module_param(dbfsize, uint, 0400); +MODULE_PARM_DESC(dbfsize, + "number of pages for each debug feature area (default 4)"); + +#define ZFCP_LOG_AREA ZFCP_LOG_AREA_OTHER + +static inline int +zfcp_dbf_stck(char *out_buf, const char *label, unsigned long long stck) +{ + unsigned long long sec; + struct timespec xtime; + int len = 0; + + stck -= 0x8126d60e46000000LL - (0x3c26700LL * 1000000 * 4096); + sec = stck >> 12; + do_div(sec, 1000000); + xtime.tv_sec = sec; + stck -= (sec * 1000000) << 12; + xtime.tv_nsec = ((stck * 1000) >> 12); + len += sprintf(out_buf + len, "%-24s%011lu:%06lu\n", + label, xtime.tv_sec, xtime.tv_nsec); + + return len; +} + +static int zfcp_dbf_tag(char *out_buf, const char *label, const char *tag) +{ + int len = 0, i; + + len += sprintf(out_buf + len, "%-24s", label); + for (i = 0; i < ZFCP_DBF_TAG_SIZE; i++) + len += sprintf(out_buf + len, "%c", tag[i]); + len += sprintf(out_buf + len, "\n"); + + return len; +} + +static int +zfcp_dbf_view(char *out_buf, const char *label, const char *format, ...) +{ + va_list arg; + int len = 0; + + len += sprintf(out_buf + len, "%-24s", label); + va_start(arg, format); + len += vsprintf(out_buf + len, format, arg); + va_end(arg); + len += sprintf(out_buf + len, "\n"); + + return len; +} + +static int +zfcp_dbf_view_dump(char *out_buf, const char *label, + char *buffer, int buflen, int offset, int total_size) +{ + int len = 0; + + if (offset == 0) + len += sprintf(out_buf + len, "%-24s ", label); + + while (buflen--) { + if (offset > 0) { + if ((offset % 32) == 0) + len += sprintf(out_buf + len, "\n%-24c ", ' '); + else if ((offset % 4) == 0) + len += sprintf(out_buf + len, " "); + } + len += sprintf(out_buf + len, "%02x", *buffer++); + if (++offset == total_size) { + len += sprintf(out_buf + len, "\n"); + break; + } + } + + if (total_size == 0) + len += sprintf(out_buf + len, "\n"); + + return len; +} + +static inline int +zfcp_dbf_view_header(debug_info_t * id, struct debug_view *view, int area, + debug_entry_t * entry, char *out_buf) +{ + struct zfcp_dbf_dump *dump = (struct zfcp_dbf_dump *)DEBUG_DATA(entry); + int len = 0; + + if (strncmp(dump->tag, "dump", ZFCP_DBF_TAG_SIZE) != 0) { + len += zfcp_dbf_stck(out_buf + len, "timestamp", + entry->id.stck); + len += zfcp_dbf_view(out_buf + len, "cpu", "%02i", + entry->id.fields.cpuid); + } else { + len += zfcp_dbf_view_dump(out_buf + len, NULL, + dump->data, + dump->size, + dump->offset, dump->total_size); + if ((dump->offset + dump->size) == dump->total_size) + len += sprintf(out_buf + len, "\n"); + } + + return len; +} + +inline void zfcp_hba_dbf_event_fsf_response(struct zfcp_fsf_req *fsf_req) +{ + struct zfcp_adapter *adapter = fsf_req->adapter; + struct fsf_qtcb *qtcb = fsf_req->qtcb; + union fsf_prot_status_qual *prot_status_qual = + &qtcb->prefix.prot_status_qual; + union fsf_status_qual *fsf_status_qual = &qtcb->header.fsf_status_qual; + struct scsi_cmnd *scsi_cmnd; + struct zfcp_port *port; + struct zfcp_unit *unit; + struct zfcp_send_els *send_els; + struct zfcp_hba_dbf_record *rec = &adapter->hba_dbf_buf; + struct zfcp_hba_dbf_record_response *response = &rec->type.response; + int level; + unsigned long flags; + + spin_lock_irqsave(&adapter->hba_dbf_lock, flags); + memset(rec, 0, sizeof(struct zfcp_hba_dbf_record)); + strncpy(rec->tag, "resp", ZFCP_DBF_TAG_SIZE); + + if ((qtcb->prefix.prot_status != FSF_PROT_GOOD) && + (qtcb->prefix.prot_status != FSF_PROT_FSF_STATUS_PRESENTED)) { + strncpy(rec->tag2, "perr", ZFCP_DBF_TAG_SIZE); + level = 1; + } else if (qtcb->header.fsf_status != FSF_GOOD) { + strncpy(rec->tag2, "ferr", ZFCP_DBF_TAG_SIZE); + level = 1; + } else if ((fsf_req->fsf_command == FSF_QTCB_OPEN_PORT_WITH_DID) || + (fsf_req->fsf_command == FSF_QTCB_OPEN_LUN)) { + strncpy(rec->tag2, "open", ZFCP_DBF_TAG_SIZE); + level = 4; + } else if ((prot_status_qual->doubleword[0] != 0) || + (prot_status_qual->doubleword[1] != 0) || + (fsf_status_qual->doubleword[0] != 0) || + (fsf_status_qual->doubleword[1] != 0)) { + strncpy(rec->tag2, "qual", ZFCP_DBF_TAG_SIZE); + level = 3; + } else { + strncpy(rec->tag2, "norm", ZFCP_DBF_TAG_SIZE); + level = 6; + } + + response->fsf_command = fsf_req->fsf_command; + response->fsf_reqid = (unsigned long)fsf_req; + response->fsf_seqno = fsf_req->seq_no; + response->fsf_issued = fsf_req->issued; + response->fsf_prot_status = qtcb->prefix.prot_status; + response->fsf_status = qtcb->header.fsf_status; + memcpy(response->fsf_prot_status_qual, + prot_status_qual, FSF_PROT_STATUS_QUAL_SIZE); + memcpy(response->fsf_status_qual, + fsf_status_qual, FSF_STATUS_QUALIFIER_SIZE); + response->fsf_req_status = fsf_req->status; + response->sbal_first = fsf_req->sbal_first; + response->sbal_curr = fsf_req->sbal_curr; + response->sbal_last = fsf_req->sbal_last; + response->pool = fsf_req->pool != NULL; + response->erp_action = (unsigned long)fsf_req->erp_action; + + switch (fsf_req->fsf_command) { + case FSF_QTCB_FCP_CMND: + if (fsf_req->status & ZFCP_STATUS_FSFREQ_TASK_MANAGEMENT) + break; + scsi_cmnd = (struct scsi_cmnd *)fsf_req->data; + if (scsi_cmnd != NULL) { + response->data.send_fcp.scsi_cmnd + = (unsigned long)scsi_cmnd; + response->data.send_fcp.scsi_serial + = scsi_cmnd->serial_number; + } + break; + + case FSF_QTCB_OPEN_PORT_WITH_DID: + case FSF_QTCB_CLOSE_PORT: + case FSF_QTCB_CLOSE_PHYSICAL_PORT: + port = (struct zfcp_port *)fsf_req->data; + response->data.port.wwpn = port->wwpn; + response->data.port.d_id = port->d_id; + response->data.port.port_handle = qtcb->header.port_handle; + break; + + case FSF_QTCB_OPEN_LUN: + case FSF_QTCB_CLOSE_LUN: + unit = (struct zfcp_unit *)fsf_req->data; + port = unit->port; + response->data.unit.wwpn = port->wwpn; + response->data.unit.fcp_lun = unit->fcp_lun; + response->data.unit.port_handle = qtcb->header.port_handle; + response->data.unit.lun_handle = qtcb->header.lun_handle; + break; + + case FSF_QTCB_SEND_ELS: + send_els = (struct zfcp_send_els *)fsf_req->data; + response->data.send_els.d_id = qtcb->bottom.support.d_id; + response->data.send_els.ls_code = send_els->ls_code >> 24; + break; + + case FSF_QTCB_ABORT_FCP_CMND: + case FSF_QTCB_SEND_GENERIC: + case FSF_QTCB_EXCHANGE_CONFIG_DATA: + case FSF_QTCB_EXCHANGE_PORT_DATA: + case FSF_QTCB_DOWNLOAD_CONTROL_FILE: + case FSF_QTCB_UPLOAD_CONTROL_FILE: + break; + } + + debug_event(adapter->hba_dbf, level, + rec, sizeof(struct zfcp_hba_dbf_record)); + spin_unlock_irqrestore(&adapter->hba_dbf_lock, flags); +} + +inline void +zfcp_hba_dbf_event_fsf_unsol(const char *tag, struct zfcp_adapter *adapter, + struct fsf_status_read_buffer *status_buffer) +{ + struct zfcp_hba_dbf_record *rec = &adapter->hba_dbf_buf; + unsigned long flags; + + spin_lock_irqsave(&adapter->hba_dbf_lock, flags); + memset(rec, 0, sizeof(struct zfcp_hba_dbf_record)); + strncpy(rec->tag, "stat", ZFCP_DBF_TAG_SIZE); + strncpy(rec->tag2, tag, ZFCP_DBF_TAG_SIZE); + + rec->type.status.failed = adapter->status_read_failed; + if (status_buffer != NULL) { + rec->type.status.status_type = status_buffer->status_type; + rec->type.status.status_subtype = status_buffer->status_subtype; + memcpy(&rec->type.status.queue_designator, + &status_buffer->queue_designator, + sizeof(struct fsf_queue_designator)); + + switch (status_buffer->status_type) { + case FSF_STATUS_READ_SENSE_DATA_AVAIL: + rec->type.status.payload_size = + ZFCP_DBF_UNSOL_PAYLOAD_SENSE_DATA_AVAIL; + break; + + case FSF_STATUS_READ_BIT_ERROR_THRESHOLD: + rec->type.status.payload_size = + ZFCP_DBF_UNSOL_PAYLOAD_BIT_ERROR_THRESHOLD; + break; + + case FSF_STATUS_READ_LINK_DOWN: + switch (status_buffer->status_subtype) { + case FSF_STATUS_READ_SUB_NO_PHYSICAL_LINK: + case FSF_STATUS_READ_SUB_FDISC_FAILED: + rec->type.status.payload_size = + sizeof(struct fsf_link_down_info); + } + break; + + case FSF_STATUS_READ_FEATURE_UPDATE_ALERT: + rec->type.status.payload_size = + ZFCP_DBF_UNSOL_PAYLOAD_FEATURE_UPDATE_ALERT; + break; + } + memcpy(&rec->type.status.payload, + &status_buffer->payload, rec->type.status.payload_size); + } + + debug_event(adapter->hba_dbf, 2, + rec, sizeof(struct zfcp_hba_dbf_record)); + spin_unlock_irqrestore(&adapter->hba_dbf_lock, flags); +} + +inline void +zfcp_hba_dbf_event_qdio(struct zfcp_adapter *adapter, unsigned int status, + unsigned int qdio_error, unsigned int siga_error, + int sbal_index, int sbal_count) +{ + struct zfcp_hba_dbf_record *rec = &adapter->hba_dbf_buf; + unsigned long flags; + + spin_lock_irqsave(&adapter->hba_dbf_lock, flags); + memset(rec, 0, sizeof(struct zfcp_hba_dbf_record)); + strncpy(rec->tag, "qdio", ZFCP_DBF_TAG_SIZE); + rec->type.qdio.status = status; + rec->type.qdio.qdio_error = qdio_error; + rec->type.qdio.siga_error = siga_error; + rec->type.qdio.sbal_index = sbal_index; + rec->type.qdio.sbal_count = sbal_count; + debug_event(adapter->hba_dbf, 0, + rec, sizeof(struct zfcp_hba_dbf_record)); + spin_unlock_irqrestore(&adapter->hba_dbf_lock, flags); +} + +static inline int +zfcp_hba_dbf_view_response(char *out_buf, + struct zfcp_hba_dbf_record_response *rec) +{ + int len = 0; + + len += zfcp_dbf_view(out_buf + len, "fsf_command", "0x%08x", + rec->fsf_command); + len += zfcp_dbf_view(out_buf + len, "fsf_reqid", "0x%0Lx", + rec->fsf_reqid); + len += zfcp_dbf_view(out_buf + len, "fsf_seqno", "0x%08x", + rec->fsf_seqno); + len += zfcp_dbf_stck(out_buf + len, "fsf_issued", rec->fsf_issued); + len += zfcp_dbf_view(out_buf + len, "fsf_prot_status", "0x%08x", + rec->fsf_prot_status); + len += zfcp_dbf_view(out_buf + len, "fsf_status", "0x%08x", + rec->fsf_status); + len += zfcp_dbf_view_dump(out_buf + len, "fsf_prot_status_qual", + rec->fsf_prot_status_qual, + FSF_PROT_STATUS_QUAL_SIZE, + 0, FSF_PROT_STATUS_QUAL_SIZE); + len += zfcp_dbf_view_dump(out_buf + len, "fsf_status_qual", + rec->fsf_status_qual, + FSF_STATUS_QUALIFIER_SIZE, + 0, FSF_STATUS_QUALIFIER_SIZE); + len += zfcp_dbf_view(out_buf + len, "fsf_req_status", "0x%08x", + rec->fsf_req_status); + len += zfcp_dbf_view(out_buf + len, "sbal_first", "0x%02x", + rec->sbal_first); + len += zfcp_dbf_view(out_buf + len, "sbal_curr", "0x%02x", + rec->sbal_curr); + len += zfcp_dbf_view(out_buf + len, "sbal_last", "0x%02x", + rec->sbal_last); + len += zfcp_dbf_view(out_buf + len, "pool", "0x%02x", rec->pool); + + switch (rec->fsf_command) { + case FSF_QTCB_FCP_CMND: + if (rec->fsf_req_status & ZFCP_STATUS_FSFREQ_TASK_MANAGEMENT) + break; + len += zfcp_dbf_view(out_buf + len, "scsi_cmnd", "0x%0Lx", + rec->data.send_fcp.scsi_cmnd); + len += zfcp_dbf_view(out_buf + len, "scsi_serial", "0x%016Lx", + rec->data.send_fcp.scsi_serial); + break; + + case FSF_QTCB_OPEN_PORT_WITH_DID: + case FSF_QTCB_CLOSE_PORT: + case FSF_QTCB_CLOSE_PHYSICAL_PORT: + len += zfcp_dbf_view(out_buf + len, "wwpn", "0x%016Lx", + rec->data.port.wwpn); + len += zfcp_dbf_view(out_buf + len, "d_id", "0x%06x", + rec->data.port.d_id); + len += zfcp_dbf_view(out_buf + len, "port_handle", "0x%08x", + rec->data.port.port_handle); + break; + + case FSF_QTCB_OPEN_LUN: + case FSF_QTCB_CLOSE_LUN: + len += zfcp_dbf_view(out_buf + len, "wwpn", "0x%016Lx", + rec->data.unit.wwpn); + len += zfcp_dbf_view(out_buf + len, "fcp_lun", "0x%016Lx", + rec->data.unit.fcp_lun); + len += zfcp_dbf_view(out_buf + len, "port_handle", "0x%08x", + rec->data.unit.port_handle); + len += zfcp_dbf_view(out_buf + len, "lun_handle", "0x%08x", + rec->data.unit.lun_handle); + break; + + case FSF_QTCB_SEND_ELS: + len += zfcp_dbf_view(out_buf + len, "d_id", "0x%06x", + rec->data.send_els.d_id); + len += zfcp_dbf_view(out_buf + len, "ls_code", "0x%02x", + rec->data.send_els.ls_code); + break; + + case FSF_QTCB_ABORT_FCP_CMND: + case FSF_QTCB_SEND_GENERIC: + case FSF_QTCB_EXCHANGE_CONFIG_DATA: + case FSF_QTCB_EXCHANGE_PORT_DATA: + case FSF_QTCB_DOWNLOAD_CONTROL_FILE: + case FSF_QTCB_UPLOAD_CONTROL_FILE: + break; + } + + return len; +} + +static inline int +zfcp_hba_dbf_view_status(char *out_buf, struct zfcp_hba_dbf_record_status *rec) +{ + int len = 0; + + len += zfcp_dbf_view(out_buf + len, "failed", "0x%02x", rec->failed); + len += zfcp_dbf_view(out_buf + len, "status_type", "0x%08x", + rec->status_type); + len += zfcp_dbf_view(out_buf + len, "status_subtype", "0x%08x", + rec->status_subtype); + len += zfcp_dbf_view_dump(out_buf + len, "queue_designator", + (char *)&rec->queue_designator, + sizeof(struct fsf_queue_designator), + 0, sizeof(struct fsf_queue_designator)); + len += zfcp_dbf_view_dump(out_buf + len, "payload", + (char *)&rec->payload, + rec->payload_size, 0, rec->payload_size); + + return len; +} + +static inline int +zfcp_hba_dbf_view_qdio(char *out_buf, struct zfcp_hba_dbf_record_qdio *rec) +{ + int len = 0; + + len += zfcp_dbf_view(out_buf + len, "status", "0x%08x", rec->status); + len += zfcp_dbf_view(out_buf + len, "qdio_error", "0x%08x", + rec->qdio_error); + len += zfcp_dbf_view(out_buf + len, "siga_error", "0x%08x", + rec->siga_error); + len += zfcp_dbf_view(out_buf + len, "sbal_index", "0x%02x", + rec->sbal_index); + len += zfcp_dbf_view(out_buf + len, "sbal_count", "0x%02x", + rec->sbal_count); + + return len; +} + +static int +zfcp_hba_dbf_view_format(debug_info_t * id, struct debug_view *view, + char *out_buf, const char *in_buf) +{ + struct zfcp_hba_dbf_record *rec = (struct zfcp_hba_dbf_record *)in_buf; + int len = 0; + + if (strncmp(rec->tag, "dump", ZFCP_DBF_TAG_SIZE) == 0) + return 0; + + len += zfcp_dbf_tag(out_buf + len, "tag", rec->tag); + if (isalpha(rec->tag2[0])) + len += zfcp_dbf_tag(out_buf + len, "tag2", rec->tag2); + if (strncmp(rec->tag, "resp", ZFCP_DBF_TAG_SIZE) == 0) + len += zfcp_hba_dbf_view_response(out_buf + len, + &rec->type.response); + else if (strncmp(rec->tag, "stat", ZFCP_DBF_TAG_SIZE) == 0) + len += zfcp_hba_dbf_view_status(out_buf + len, + &rec->type.status); + else if (strncmp(rec->tag, "qdio", ZFCP_DBF_TAG_SIZE) == 0) + len += zfcp_hba_dbf_view_qdio(out_buf + len, &rec->type.qdio); + + len += sprintf(out_buf + len, "\n"); + + return len; +} + +struct debug_view zfcp_hba_dbf_view = { + "structured", + NULL, + &zfcp_dbf_view_header, + &zfcp_hba_dbf_view_format, + NULL, + NULL +}; + +inline void +_zfcp_san_dbf_event_common_ct(const char *tag, struct zfcp_fsf_req *fsf_req, + u32 s_id, u32 d_id, void *buffer, int buflen) +{ + struct zfcp_send_ct *send_ct = (struct zfcp_send_ct *)fsf_req->data; + struct zfcp_port *port = send_ct->port; + struct zfcp_adapter *adapter = port->adapter; + struct ct_hdr *header = (struct ct_hdr *)buffer; + struct zfcp_san_dbf_record *rec = &adapter->san_dbf_buf; + struct zfcp_san_dbf_record_ct *ct = &rec->type.ct; + unsigned long flags; + + spin_lock_irqsave(&adapter->san_dbf_lock, flags); + memset(rec, 0, sizeof(struct zfcp_san_dbf_record)); + strncpy(rec->tag, tag, ZFCP_DBF_TAG_SIZE); + rec->fsf_reqid = (unsigned long)fsf_req; + rec->fsf_seqno = fsf_req->seq_no; + rec->s_id = s_id; + rec->d_id = d_id; + if (strncmp(tag, "octc", ZFCP_DBF_TAG_SIZE) == 0) { + ct->type.request.cmd_req_code = header->cmd_rsp_code; + ct->type.request.revision = header->revision; + ct->type.request.gs_type = header->gs_type; + ct->type.request.gs_subtype = header->gs_subtype; + ct->type.request.options = header->options; + ct->type.request.max_res_size = header->max_res_size; + } else if (strncmp(tag, "rctc", ZFCP_DBF_TAG_SIZE) == 0) { + ct->type.response.cmd_rsp_code = header->cmd_rsp_code; + ct->type.response.revision = header->revision; + ct->type.response.reason_code = header->reason_code; + ct->type.response.reason_code_expl = header->reason_code_expl; + ct->type.response.vendor_unique = header->vendor_unique; + } + ct->payload_size = + min(buflen - (int)sizeof(struct ct_hdr), ZFCP_DBF_CT_PAYLOAD); + memcpy(ct->payload, buffer + sizeof(struct ct_hdr), ct->payload_size); + debug_event(adapter->san_dbf, 3, + rec, sizeof(struct zfcp_san_dbf_record)); + spin_unlock_irqrestore(&adapter->san_dbf_lock, flags); +} + +inline void zfcp_san_dbf_event_ct_request(struct zfcp_fsf_req *fsf_req) +{ + struct zfcp_send_ct *ct = (struct zfcp_send_ct *)fsf_req->data; + struct zfcp_port *port = ct->port; + struct zfcp_adapter *adapter = port->adapter; + + _zfcp_san_dbf_event_common_ct("octc", fsf_req, + fc_host_port_id(adapter->scsi_host), + port->d_id, zfcp_sg_to_address(ct->req), + ct->req->length); +} + +inline void zfcp_san_dbf_event_ct_response(struct zfcp_fsf_req *fsf_req) +{ + struct zfcp_send_ct *ct = (struct zfcp_send_ct *)fsf_req->data; + struct zfcp_port *port = ct->port; + struct zfcp_adapter *adapter = port->adapter; + + _zfcp_san_dbf_event_common_ct("rctc", fsf_req, port->d_id, + fc_host_port_id(adapter->scsi_host), + zfcp_sg_to_address(ct->resp), + ct->resp->length); +} + +static inline void +_zfcp_san_dbf_event_common_els(const char *tag, int level, + struct zfcp_fsf_req *fsf_req, u32 s_id, + u32 d_id, u8 ls_code, void *buffer, int buflen) +{ + struct zfcp_adapter *adapter = fsf_req->adapter; + struct zfcp_san_dbf_record *rec = &adapter->san_dbf_buf; + struct zfcp_dbf_dump *dump = (struct zfcp_dbf_dump *)rec; + unsigned long flags; + int offset = 0; + + spin_lock_irqsave(&adapter->san_dbf_lock, flags); + do { + memset(rec, 0, sizeof(struct zfcp_san_dbf_record)); + if (offset == 0) { + strncpy(rec->tag, tag, ZFCP_DBF_TAG_SIZE); + rec->fsf_reqid = (unsigned long)fsf_req; + rec->fsf_seqno = fsf_req->seq_no; + rec->s_id = s_id; + rec->d_id = d_id; + rec->type.els.ls_code = ls_code; + buflen = min(buflen, ZFCP_DBF_ELS_MAX_PAYLOAD); + rec->type.els.payload_size = buflen; + memcpy(rec->type.els.payload, + buffer, min(buflen, ZFCP_DBF_ELS_PAYLOAD)); + offset += min(buflen, ZFCP_DBF_ELS_PAYLOAD); + } else { + strncpy(dump->tag, "dump", ZFCP_DBF_TAG_SIZE); + dump->total_size = buflen; + dump->offset = offset; + dump->size = min(buflen - offset, + (int)sizeof(struct zfcp_san_dbf_record) + - (int)sizeof(struct zfcp_dbf_dump)); + memcpy(dump->data, buffer + offset, dump->size); + offset += dump->size; + } + debug_event(adapter->san_dbf, level, + rec, sizeof(struct zfcp_san_dbf_record)); + } while (offset < buflen); + spin_unlock_irqrestore(&adapter->san_dbf_lock, flags); +} + +inline void zfcp_san_dbf_event_els_request(struct zfcp_fsf_req *fsf_req) +{ + struct zfcp_send_els *els = (struct zfcp_send_els *)fsf_req->data; + + _zfcp_san_dbf_event_common_els("oels", 2, fsf_req, + fc_host_port_id(els->adapter->scsi_host), + els->d_id, + *(u8 *) zfcp_sg_to_address(els->req), + zfcp_sg_to_address(els->req), + els->req->length); +} + +inline void zfcp_san_dbf_event_els_response(struct zfcp_fsf_req *fsf_req) +{ + struct zfcp_send_els *els = (struct zfcp_send_els *)fsf_req->data; + + _zfcp_san_dbf_event_common_els("rels", 2, fsf_req, els->d_id, + fc_host_port_id(els->adapter->scsi_host), + *(u8 *) zfcp_sg_to_address(els->req), + zfcp_sg_to_address(els->resp), + els->resp->length); +} + +inline void zfcp_san_dbf_event_incoming_els(struct zfcp_fsf_req *fsf_req) +{ + struct zfcp_adapter *adapter = fsf_req->adapter; + struct fsf_status_read_buffer *status_buffer = + (struct fsf_status_read_buffer *)fsf_req->data; + int length = (int)status_buffer->length - + (int)((void *)&status_buffer->payload - (void *)status_buffer); + + _zfcp_san_dbf_event_common_els("iels", 1, fsf_req, status_buffer->d_id, + fc_host_port_id(adapter->scsi_host), + *(u8 *) status_buffer->payload, + (void *)status_buffer->payload, length); +} + +static int +zfcp_san_dbf_view_format(debug_info_t * id, struct debug_view *view, + char *out_buf, const char *in_buf) +{ + struct zfcp_san_dbf_record *rec = (struct zfcp_san_dbf_record *)in_buf; + char *buffer = NULL; + int buflen = 0, total = 0; + int len = 0; + + if (strncmp(rec->tag, "dump", ZFCP_DBF_TAG_SIZE) == 0) + return 0; + + len += zfcp_dbf_tag(out_buf + len, "tag", rec->tag); + len += zfcp_dbf_view(out_buf + len, "fsf_reqid", "0x%0Lx", + rec->fsf_reqid); + len += zfcp_dbf_view(out_buf + len, "fsf_seqno", "0x%08x", + rec->fsf_seqno); + len += zfcp_dbf_view(out_buf + len, "s_id", "0x%06x", rec->s_id); + len += zfcp_dbf_view(out_buf + len, "d_id", "0x%06x", rec->d_id); + + if (strncmp(rec->tag, "octc", ZFCP_DBF_TAG_SIZE) == 0) { + len += zfcp_dbf_view(out_buf + len, "cmd_req_code", "0x%04x", + rec->type.ct.type.request.cmd_req_code); + len += zfcp_dbf_view(out_buf + len, "revision", "0x%02x", + rec->type.ct.type.request.revision); + len += zfcp_dbf_view(out_buf + len, "gs_type", "0x%02x", + rec->type.ct.type.request.gs_type); + len += zfcp_dbf_view(out_buf + len, "gs_subtype", "0x%02x", + rec->type.ct.type.request.gs_subtype); + len += zfcp_dbf_view(out_buf + len, "options", "0x%02x", + rec->type.ct.type.request.options); + len += zfcp_dbf_view(out_buf + len, "max_res_size", "0x%04x", + rec->type.ct.type.request.max_res_size); + total = rec->type.ct.payload_size; + buffer = rec->type.ct.payload; + buflen = min(total, ZFCP_DBF_CT_PAYLOAD); + } else if (strncmp(rec->tag, "rctc", ZFCP_DBF_TAG_SIZE) == 0) { + len += zfcp_dbf_view(out_buf + len, "cmd_rsp_code", "0x%04x", + rec->type.ct.type.response.cmd_rsp_code); + len += zfcp_dbf_view(out_buf + len, "revision", "0x%02x", + rec->type.ct.type.response.revision); + len += zfcp_dbf_view(out_buf + len, "reason_code", "0x%02x", + rec->type.ct.type.response.reason_code); + len += + zfcp_dbf_view(out_buf + len, "reason_code_expl", "0x%02x", + rec->type.ct.type.response.reason_code_expl); + len += + zfcp_dbf_view(out_buf + len, "vendor_unique", "0x%02x", + rec->type.ct.type.response.vendor_unique); + total = rec->type.ct.payload_size; + buffer = rec->type.ct.payload; + buflen = min(total, ZFCP_DBF_CT_PAYLOAD); + } else if (strncmp(rec->tag, "oels", ZFCP_DBF_TAG_SIZE) == 0 || + strncmp(rec->tag, "rels", ZFCP_DBF_TAG_SIZE) == 0 || + strncmp(rec->tag, "iels", ZFCP_DBF_TAG_SIZE) == 0) { + len += zfcp_dbf_view(out_buf + len, "ls_code", "0x%02x", + rec->type.els.ls_code); + total = rec->type.els.payload_size; + buffer = rec->type.els.payload; + buflen = min(total, ZFCP_DBF_ELS_PAYLOAD); + } + + len += zfcp_dbf_view_dump(out_buf + len, "payload", + buffer, buflen, 0, total); + + if (buflen == total) + len += sprintf(out_buf + len, "\n"); + + return len; +} + +struct debug_view zfcp_san_dbf_view = { + "structured", + NULL, + &zfcp_dbf_view_header, + &zfcp_san_dbf_view_format, + NULL, + NULL +}; + +static inline void +_zfcp_scsi_dbf_event_common(const char *tag, const char *tag2, int level, + struct zfcp_adapter *adapter, + struct scsi_cmnd *scsi_cmnd, + struct zfcp_fsf_req *new_fsf_req) +{ + struct zfcp_fsf_req *fsf_req = + (struct zfcp_fsf_req *)scsi_cmnd->host_scribble; + struct zfcp_scsi_dbf_record *rec = &adapter->scsi_dbf_buf; + struct zfcp_dbf_dump *dump = (struct zfcp_dbf_dump *)rec; + unsigned long flags; + struct fcp_rsp_iu *fcp_rsp; + char *fcp_rsp_info = NULL, *fcp_sns_info = NULL; + int offset = 0, buflen = 0; + + spin_lock_irqsave(&adapter->scsi_dbf_lock, flags); + do { + memset(rec, 0, sizeof(struct zfcp_scsi_dbf_record)); + if (offset == 0) { + strncpy(rec->tag, tag, ZFCP_DBF_TAG_SIZE); + strncpy(rec->tag2, tag2, ZFCP_DBF_TAG_SIZE); + if (scsi_cmnd->device) { + rec->scsi_id = scsi_cmnd->device->id; + rec->scsi_lun = scsi_cmnd->device->lun; + } + rec->scsi_result = scsi_cmnd->result; + rec->scsi_cmnd = (unsigned long)scsi_cmnd; + rec->scsi_serial = scsi_cmnd->serial_number; + memcpy(rec->scsi_opcode, + &scsi_cmnd->cmnd, + min((int)scsi_cmnd->cmd_len, + ZFCP_DBF_SCSI_OPCODE)); + rec->scsi_retries = scsi_cmnd->retries; + rec->scsi_allowed = scsi_cmnd->allowed; + if (fsf_req != NULL) { + fcp_rsp = (struct fcp_rsp_iu *) + &(fsf_req->qtcb->bottom.io.fcp_rsp); + fcp_rsp_info = + zfcp_get_fcp_rsp_info_ptr(fcp_rsp); + fcp_sns_info = + zfcp_get_fcp_sns_info_ptr(fcp_rsp); + + rec->type.fcp.rsp_validity = + fcp_rsp->validity.value; + rec->type.fcp.rsp_scsi_status = + fcp_rsp->scsi_status; + rec->type.fcp.rsp_resid = fcp_rsp->fcp_resid; + if (fcp_rsp->validity.bits.fcp_rsp_len_valid) + rec->type.fcp.rsp_code = + *(fcp_rsp_info + 3); + if (fcp_rsp->validity.bits.fcp_sns_len_valid) { + buflen = min((int)fcp_rsp->fcp_sns_len, + ZFCP_DBF_SCSI_MAX_FCP_SNS_INFO); + rec->type.fcp.sns_info_len = buflen; + memcpy(rec->type.fcp.sns_info, + fcp_sns_info, + min(buflen, + ZFCP_DBF_SCSI_FCP_SNS_INFO)); + offset += min(buflen, + ZFCP_DBF_SCSI_FCP_SNS_INFO); + } + + rec->fsf_reqid = (unsigned long)fsf_req; + rec->fsf_seqno = fsf_req->seq_no; + rec->fsf_issued = fsf_req->issued; + } + if (new_fsf_req != NULL) { + rec->type.new_fsf_req.fsf_reqid = + (unsigned long) + new_fsf_req; + rec->type.new_fsf_req.fsf_seqno = + new_fsf_req->seq_no; + rec->type.new_fsf_req.fsf_issued = + new_fsf_req->issued; + } + } else { + strncpy(dump->tag, "dump", ZFCP_DBF_TAG_SIZE); + dump->total_size = buflen; + dump->offset = offset; + dump->size = min(buflen - offset, + (int)sizeof(struct + zfcp_scsi_dbf_record) - + (int)sizeof(struct zfcp_dbf_dump)); + memcpy(dump->data, fcp_sns_info + offset, dump->size); + offset += dump->size; + } + debug_event(adapter->scsi_dbf, level, + rec, sizeof(struct zfcp_scsi_dbf_record)); + } while (offset < buflen); + spin_unlock_irqrestore(&adapter->scsi_dbf_lock, flags); +} + +inline void +zfcp_scsi_dbf_event_result(const char *tag, int level, + struct zfcp_adapter *adapter, + struct scsi_cmnd *scsi_cmnd) +{ + _zfcp_scsi_dbf_event_common("rslt", + tag, level, adapter, scsi_cmnd, NULL); +} + +inline void +zfcp_scsi_dbf_event_abort(const char *tag, struct zfcp_adapter *adapter, + struct scsi_cmnd *scsi_cmnd, + struct zfcp_fsf_req *new_fsf_req) +{ + _zfcp_scsi_dbf_event_common("abrt", + tag, 1, adapter, scsi_cmnd, new_fsf_req); +} + +inline void +zfcp_scsi_dbf_event_devreset(const char *tag, u8 flag, struct zfcp_unit *unit, + struct scsi_cmnd *scsi_cmnd) +{ + struct zfcp_adapter *adapter = unit->port->adapter; + + _zfcp_scsi_dbf_event_common(flag == FCP_TARGET_RESET ? "trst" : "lrst", + tag, 1, adapter, scsi_cmnd, NULL); +} + +static int +zfcp_scsi_dbf_view_format(debug_info_t * id, struct debug_view *view, + char *out_buf, const char *in_buf) +{ + struct zfcp_scsi_dbf_record *rec = + (struct zfcp_scsi_dbf_record *)in_buf; + int len = 0; + + if (strncmp(rec->tag, "dump", ZFCP_DBF_TAG_SIZE) == 0) + return 0; + + len += zfcp_dbf_tag(out_buf + len, "tag", rec->tag); + len += zfcp_dbf_tag(out_buf + len, "tag2", rec->tag2); + len += zfcp_dbf_view(out_buf + len, "scsi_id", "0x%08x", rec->scsi_id); + len += zfcp_dbf_view(out_buf + len, "scsi_lun", "0x%08x", + rec->scsi_lun); + len += zfcp_dbf_view(out_buf + len, "scsi_result", "0x%08x", + rec->scsi_result); + len += zfcp_dbf_view(out_buf + len, "scsi_cmnd", "0x%0Lx", + rec->scsi_cmnd); + len += zfcp_dbf_view(out_buf + len, "scsi_serial", "0x%016Lx", + rec->scsi_serial); + len += zfcp_dbf_view_dump(out_buf + len, "scsi_opcode", + rec->scsi_opcode, + ZFCP_DBF_SCSI_OPCODE, + 0, ZFCP_DBF_SCSI_OPCODE); + len += zfcp_dbf_view(out_buf + len, "scsi_retries", "0x%02x", + rec->scsi_retries); + len += zfcp_dbf_view(out_buf + len, "scsi_allowed", "0x%02x", + rec->scsi_allowed); + len += zfcp_dbf_view(out_buf + len, "fsf_reqid", "0x%0Lx", + rec->fsf_reqid); + len += zfcp_dbf_view(out_buf + len, "fsf_seqno", "0x%08x", + rec->fsf_seqno); + len += zfcp_dbf_stck(out_buf + len, "fsf_issued", rec->fsf_issued); + if (strncmp(rec->tag, "rslt", ZFCP_DBF_TAG_SIZE) == 0) { + len += + zfcp_dbf_view(out_buf + len, "fcp_rsp_validity", "0x%02x", + rec->type.fcp.rsp_validity); + len += + zfcp_dbf_view(out_buf + len, "fcp_rsp_scsi_status", + "0x%02x", rec->type.fcp.rsp_scsi_status); + len += + zfcp_dbf_view(out_buf + len, "fcp_rsp_resid", "0x%08x", + rec->type.fcp.rsp_resid); + len += + zfcp_dbf_view(out_buf + len, "fcp_rsp_code", "0x%08x", + rec->type.fcp.rsp_code); + len += + zfcp_dbf_view(out_buf + len, "fcp_sns_info_len", "0x%08x", + rec->type.fcp.sns_info_len); + len += + zfcp_dbf_view_dump(out_buf + len, "fcp_sns_info", + rec->type.fcp.sns_info, + min((int)rec->type.fcp.sns_info_len, + ZFCP_DBF_SCSI_FCP_SNS_INFO), 0, + rec->type.fcp.sns_info_len); + } else if (strncmp(rec->tag, "abrt", ZFCP_DBF_TAG_SIZE) == 0) { + len += zfcp_dbf_view(out_buf + len, "fsf_reqid_abort", "0x%0Lx", + rec->type.new_fsf_req.fsf_reqid); + len += zfcp_dbf_view(out_buf + len, "fsf_seqno_abort", "0x%08x", + rec->type.new_fsf_req.fsf_seqno); + len += zfcp_dbf_stck(out_buf + len, "fsf_issued", + rec->type.new_fsf_req.fsf_issued); + } else if ((strncmp(rec->tag, "trst", ZFCP_DBF_TAG_SIZE) == 0) || + (strncmp(rec->tag, "lrst", ZFCP_DBF_TAG_SIZE) == 0)) { + len += zfcp_dbf_view(out_buf + len, "fsf_reqid_reset", "0x%0Lx", + rec->type.new_fsf_req.fsf_reqid); + len += zfcp_dbf_view(out_buf + len, "fsf_seqno_reset", "0x%08x", + rec->type.new_fsf_req.fsf_seqno); + len += zfcp_dbf_stck(out_buf + len, "fsf_issued", + rec->type.new_fsf_req.fsf_issued); + } + + len += sprintf(out_buf + len, "\n"); + + return len; +} + +struct debug_view zfcp_scsi_dbf_view = { + "structured", + NULL, + &zfcp_dbf_view_header, + &zfcp_scsi_dbf_view_format, + NULL, + NULL +}; + +/** + * zfcp_adapter_debug_register - registers debug feature for an adapter + * @adapter: pointer to adapter for which debug features should be registered + * return: -ENOMEM on error, 0 otherwise + */ +int zfcp_adapter_debug_register(struct zfcp_adapter *adapter) +{ + char dbf_name[DEBUG_MAX_NAME_LEN]; + + /* debug feature area which records recovery activity */ + spin_lock_init(&adapter->erp_dbf_lock); + sprintf(dbf_name, "zfcp_%s_erp", zfcp_get_busid_by_adapter(adapter)); + adapter->erp_dbf = debug_register(dbf_name, dbfsize, 2, + sizeof(struct zfcp_erp_dbf_record)); + if (!adapter->erp_dbf) + goto failed; + debug_register_view(adapter->erp_dbf, &debug_hex_ascii_view); + debug_set_level(adapter->erp_dbf, 3); + + /* debug feature area which records HBA (FSF and QDIO) conditions */ + spin_lock_init(&adapter->hba_dbf_lock); + sprintf(dbf_name, "zfcp_%s_hba", zfcp_get_busid_by_adapter(adapter)); + adapter->hba_dbf = debug_register(dbf_name, dbfsize, 1, + sizeof(struct zfcp_hba_dbf_record)); + if (!adapter->hba_dbf) + goto failed; + debug_register_view(adapter->hba_dbf, &debug_hex_ascii_view); + debug_register_view(adapter->hba_dbf, &zfcp_hba_dbf_view); + debug_set_level(adapter->hba_dbf, 3); + + /* debug feature area which records SAN command failures and recovery */ + spin_lock_init(&adapter->san_dbf_lock); + sprintf(dbf_name, "zfcp_%s_san", zfcp_get_busid_by_adapter(adapter)); + adapter->san_dbf = debug_register(dbf_name, dbfsize, 1, + sizeof(struct zfcp_san_dbf_record)); + if (!adapter->san_dbf) + goto failed; + debug_register_view(adapter->san_dbf, &debug_hex_ascii_view); + debug_register_view(adapter->san_dbf, &zfcp_san_dbf_view); + debug_set_level(adapter->san_dbf, 6); + + /* debug feature area which records SCSI command failures and recovery */ + spin_lock_init(&adapter->scsi_dbf_lock); + sprintf(dbf_name, "zfcp_%s_scsi", zfcp_get_busid_by_adapter(adapter)); + adapter->scsi_dbf = debug_register(dbf_name, dbfsize, 1, + sizeof(struct zfcp_scsi_dbf_record)); + if (!adapter->scsi_dbf) + goto failed; + debug_register_view(adapter->scsi_dbf, &debug_hex_ascii_view); + debug_register_view(adapter->scsi_dbf, &zfcp_scsi_dbf_view); + debug_set_level(adapter->scsi_dbf, 3); + + return 0; + + failed: + zfcp_adapter_debug_unregister(adapter); + + return -ENOMEM; +} + +/** + * zfcp_adapter_debug_unregister - unregisters debug feature for an adapter + * @adapter: pointer to adapter for which debug features should be unregistered + */ +void zfcp_adapter_debug_unregister(struct zfcp_adapter *adapter) +{ + debug_unregister(adapter->scsi_dbf); + debug_unregister(adapter->san_dbf); + debug_unregister(adapter->hba_dbf); + debug_unregister(adapter->erp_dbf); + adapter->scsi_dbf = NULL; + adapter->san_dbf = NULL; + adapter->hba_dbf = NULL; + adapter->erp_dbf = NULL; +} + +#undef ZFCP_LOG_AREA diff --git a/drivers/s390/scsi/zfcp_def.h b/drivers/s390/scsi/zfcp_def.h index 455e902..d81b737 100644 --- a/drivers/s390/scsi/zfcp_def.h +++ b/drivers/s390/scsi/zfcp_def.h @@ -66,7 +66,7 @@ /********************* GENERAL DEFINES *********************************/ /* zfcp version number, it consists of major, minor, and patch-level number */ -#define ZFCP_VERSION "4.3.0" +#define ZFCP_VERSION "4.5.0" /** * zfcp_sg_to_address - determine kernel address from struct scatterlist @@ -154,13 +154,17 @@ typedef u32 scsi_lun_t; #define ZFCP_EXCHANGE_CONFIG_DATA_FIRST_SLEEP 100 #define ZFCP_EXCHANGE_CONFIG_DATA_RETRIES 7 +/* Retry 5 times every 2 second, then every minute */ +#define ZFCP_EXCHANGE_PORT_DATA_SHORT_RETRIES 5 +#define ZFCP_EXCHANGE_PORT_DATA_SHORT_SLEEP 200 +#define ZFCP_EXCHANGE_PORT_DATA_LONG_SLEEP 6000 + /* timeout value for "default timer" for fsf requests */ #define ZFCP_FSF_REQUEST_TIMEOUT (60*HZ); /*************** FIBRE CHANNEL PROTOCOL SPECIFIC DEFINES ********************/ typedef unsigned long long wwn_t; -typedef unsigned int fc_id_t; typedef unsigned long long fcp_lun_t; /* data length field may be at variable position in FCP-2 FCP_CMND IU */ typedef unsigned int fcp_dl_t; @@ -281,6 +285,171 @@ struct fcp_logo { } __attribute__((packed)); /* + * DBF stuff + */ +#define ZFCP_DBF_TAG_SIZE 4 + +struct zfcp_dbf_dump { + u8 tag[ZFCP_DBF_TAG_SIZE]; + u32 total_size; /* size of total dump data */ + u32 offset; /* how much data has being already dumped */ + u32 size; /* how much data comes with this record */ + u8 data[]; /* dump data */ +} __attribute__ ((packed)); + +/* FIXME: to be inflated when reworking the erp dbf */ +struct zfcp_erp_dbf_record { + u8 dummy[16]; +} __attribute__ ((packed)); + +struct zfcp_hba_dbf_record_response { + u32 fsf_command; + u64 fsf_reqid; + u32 fsf_seqno; + u64 fsf_issued; + u32 fsf_prot_status; + u32 fsf_status; + u8 fsf_prot_status_qual[FSF_PROT_STATUS_QUAL_SIZE]; + u8 fsf_status_qual[FSF_STATUS_QUALIFIER_SIZE]; + u32 fsf_req_status; + u8 sbal_first; + u8 sbal_curr; + u8 sbal_last; + u8 pool; + u64 erp_action; + union { + struct { + u64 scsi_cmnd; + u64 scsi_serial; + } send_fcp; + struct { + u64 wwpn; + u32 d_id; + u32 port_handle; + } port; + struct { + u64 wwpn; + u64 fcp_lun; + u32 port_handle; + u32 lun_handle; + } unit; + struct { + u32 d_id; + u8 ls_code; + } send_els; + } data; +} __attribute__ ((packed)); + +struct zfcp_hba_dbf_record_status { + u8 failed; + u32 status_type; + u32 status_subtype; + struct fsf_queue_designator + queue_designator; + u32 payload_size; +#define ZFCP_DBF_UNSOL_PAYLOAD 80 +#define ZFCP_DBF_UNSOL_PAYLOAD_SENSE_DATA_AVAIL 32 +#define ZFCP_DBF_UNSOL_PAYLOAD_BIT_ERROR_THRESHOLD 56 +#define ZFCP_DBF_UNSOL_PAYLOAD_FEATURE_UPDATE_ALERT 2 * sizeof(u32) + u8 payload[ZFCP_DBF_UNSOL_PAYLOAD]; +} __attribute__ ((packed)); + +struct zfcp_hba_dbf_record_qdio { + u32 status; + u32 qdio_error; + u32 siga_error; + u8 sbal_index; + u8 sbal_count; +} __attribute__ ((packed)); + +struct zfcp_hba_dbf_record { + u8 tag[ZFCP_DBF_TAG_SIZE]; + u8 tag2[ZFCP_DBF_TAG_SIZE]; + union { + struct zfcp_hba_dbf_record_response response; + struct zfcp_hba_dbf_record_status status; + struct zfcp_hba_dbf_record_qdio qdio; + } type; +} __attribute__ ((packed)); + +struct zfcp_san_dbf_record_ct { + union { + struct { + u16 cmd_req_code; + u8 revision; + u8 gs_type; + u8 gs_subtype; + u8 options; + u16 max_res_size; + } request; + struct { + u16 cmd_rsp_code; + u8 revision; + u8 reason_code; + u8 reason_code_expl; + u8 vendor_unique; + } response; + } type; + u32 payload_size; +#define ZFCP_DBF_CT_PAYLOAD 24 + u8 payload[ZFCP_DBF_CT_PAYLOAD]; +} __attribute__ ((packed)); + +struct zfcp_san_dbf_record_els { + u8 ls_code; + u32 payload_size; +#define ZFCP_DBF_ELS_PAYLOAD 32 +#define ZFCP_DBF_ELS_MAX_PAYLOAD 1024 + u8 payload[ZFCP_DBF_ELS_PAYLOAD]; +} __attribute__ ((packed)); + +struct zfcp_san_dbf_record { + u8 tag[ZFCP_DBF_TAG_SIZE]; + u64 fsf_reqid; + u32 fsf_seqno; + u32 s_id; + u32 d_id; + union { + struct zfcp_san_dbf_record_ct ct; + struct zfcp_san_dbf_record_els els; + } type; +} __attribute__ ((packed)); + +struct zfcp_scsi_dbf_record { + u8 tag[ZFCP_DBF_TAG_SIZE]; + u8 tag2[ZFCP_DBF_TAG_SIZE]; + u32 scsi_id; + u32 scsi_lun; + u32 scsi_result; + u64 scsi_cmnd; + u64 scsi_serial; +#define ZFCP_DBF_SCSI_OPCODE 16 + u8 scsi_opcode[ZFCP_DBF_SCSI_OPCODE]; + u8 scsi_retries; + u8 scsi_allowed; + u64 fsf_reqid; + u32 fsf_seqno; + u64 fsf_issued; + union { + struct { + u64 fsf_reqid; + u32 fsf_seqno; + u64 fsf_issued; + } new_fsf_req; + struct { + u8 rsp_validity; + u8 rsp_scsi_status; + u32 rsp_resid; + u8 rsp_code; +#define ZFCP_DBF_SCSI_FCP_SNS_INFO 16 +#define ZFCP_DBF_SCSI_MAX_FCP_SNS_INFO 256 + u32 sns_info_len; + u8 sns_info[ZFCP_DBF_SCSI_FCP_SNS_INFO]; + } fcp; + } type; +} __attribute__ ((packed)); + +/* * FC-FS stuff */ #define R_A_TOV 10 /* seconds */ @@ -339,34 +508,6 @@ struct zfcp_rc_entry { */ #define ZFCP_CT_TIMEOUT (3 * R_A_TOV) - -/***************** S390 DEBUG FEATURE SPECIFIC DEFINES ***********************/ - -/* debug feature entries per adapter */ -#define ZFCP_ERP_DBF_INDEX 1 -#define ZFCP_ERP_DBF_AREAS 2 -#define ZFCP_ERP_DBF_LENGTH 16 -#define ZFCP_ERP_DBF_LEVEL 3 -#define ZFCP_ERP_DBF_NAME "zfcperp" - -#define ZFCP_CMD_DBF_INDEX 2 -#define ZFCP_CMD_DBF_AREAS 1 -#define ZFCP_CMD_DBF_LENGTH 8 -#define ZFCP_CMD_DBF_LEVEL 3 -#define ZFCP_CMD_DBF_NAME "zfcpcmd" - -#define ZFCP_ABORT_DBF_INDEX 2 -#define ZFCP_ABORT_DBF_AREAS 1 -#define ZFCP_ABORT_DBF_LENGTH 8 -#define ZFCP_ABORT_DBF_LEVEL 6 -#define ZFCP_ABORT_DBF_NAME "zfcpabt" - -#define ZFCP_IN_ELS_DBF_INDEX 2 -#define ZFCP_IN_ELS_DBF_AREAS 1 -#define ZFCP_IN_ELS_DBF_LENGTH 8 -#define ZFCP_IN_ELS_DBF_LEVEL 6 -#define ZFCP_IN_ELS_DBF_NAME "zfcpels" - /******************** LOGGING MACROS AND DEFINES *****************************/ /* @@ -501,6 +642,7 @@ do { \ #define ZFCP_STATUS_ADAPTER_ERP_THREAD_KILL 0x00000080 #define ZFCP_STATUS_ADAPTER_ERP_PENDING 0x00000100 #define ZFCP_STATUS_ADAPTER_LINK_UNPLUGGED 0x00000200 +#define ZFCP_STATUS_ADAPTER_XPORT_OK 0x00000800 #define ZFCP_STATUS_ADAPTER_SCSI_UP \ (ZFCP_STATUS_COMMON_UNBLOCKED | \ @@ -635,45 +777,6 @@ struct zfcp_adapter_mempool { mempool_t *data_gid_pn; }; -struct zfcp_exchange_config_data{ -}; - -struct zfcp_open_port { - struct zfcp_port *port; -}; - -struct zfcp_close_port { - struct zfcp_port *port; -}; - -struct zfcp_open_unit { - struct zfcp_unit *unit; -}; - -struct zfcp_close_unit { - struct zfcp_unit *unit; -}; - -struct zfcp_close_physical_port { - struct zfcp_port *port; -}; - -struct zfcp_send_fcp_command_task { - struct zfcp_fsf_req *fsf_req; - struct zfcp_unit *unit; - struct scsi_cmnd *scsi_cmnd; - unsigned long start_jiffies; -}; - -struct zfcp_send_fcp_command_task_management { - struct zfcp_unit *unit; -}; - -struct zfcp_abort_fcp_command { - struct zfcp_fsf_req *fsf_req; - struct zfcp_unit *unit; -}; - /* * header for CT_IU */ @@ -702,7 +805,7 @@ struct ct_iu_gid_pn_req { /* FS_ACC IU and data unit for GID_PN nameserver request */ struct ct_iu_gid_pn_resp { struct ct_hdr header; - fc_id_t d_id; + u32 d_id; } __attribute__ ((packed)); typedef void (*zfcp_send_ct_handler_t)(unsigned long); @@ -768,7 +871,7 @@ typedef void (*zfcp_send_els_handler_t)(unsigned long); struct zfcp_send_els { struct zfcp_adapter *adapter; struct zfcp_port *port; - fc_id_t d_id; + u32 d_id; struct scatterlist *req; struct scatterlist *resp; unsigned int req_count; @@ -781,33 +884,6 @@ struct zfcp_send_els { int status; }; -struct zfcp_status_read { - struct fsf_status_read_buffer *buffer; -}; - -struct zfcp_fsf_done { - struct completion *complete; - int status; -}; - -/* request specific data */ -union zfcp_req_data { - struct zfcp_exchange_config_data exchange_config_data; - struct zfcp_open_port open_port; - struct zfcp_close_port close_port; - struct zfcp_open_unit open_unit; - struct zfcp_close_unit close_unit; - struct zfcp_close_physical_port close_physical_port; - struct zfcp_send_fcp_command_task send_fcp_command_task; - struct zfcp_send_fcp_command_task_management - send_fcp_command_task_management; - struct zfcp_abort_fcp_command abort_fcp_command; - struct zfcp_send_ct *send_ct; - struct zfcp_send_els *send_els; - struct zfcp_status_read status_read; - struct fsf_qtcb_bottom_port *port_data; -}; - struct zfcp_qdio_queue { struct qdio_buffer *buffer[QDIO_MAX_BUFFERS_PER_Q]; /* SBALs */ u8 free_index; /* index of next free bfr @@ -838,21 +914,19 @@ struct zfcp_adapter { atomic_t refcount; /* reference count */ wait_queue_head_t remove_wq; /* can be used to wait for refcount drop to zero */ - wwn_t wwnn; /* WWNN */ - wwn_t wwpn; /* WWPN */ - fc_id_t s_id; /* N_Port ID */ wwn_t peer_wwnn; /* P2P peer WWNN */ wwn_t peer_wwpn; /* P2P peer WWPN */ - fc_id_t peer_d_id; /* P2P peer D_ID */ + u32 peer_d_id; /* P2P peer D_ID */ + wwn_t physical_wwpn; /* WWPN of physical port */ + u32 physical_s_id; /* local FC port ID */ struct ccw_device *ccw_device; /* S/390 ccw device */ u8 fc_service_class; u32 fc_topology; /* FC topology */ - u32 fc_link_speed; /* FC interface speed */ u32 hydra_version; /* Hydra version */ u32 fsf_lic_version; - u32 supported_features;/* of FCP channel */ + u32 adapter_features; /* FCP channel features */ + u32 connection_features; /* host connection features */ u32 hardware_version; /* of FCP channel */ - u8 serial_number[32]; /* of hardware */ struct Scsi_Host *scsi_host; /* Pointer to mid-layer */ unsigned short scsi_host_no; /* Assigned host number */ unsigned char name[9]; @@ -889,11 +963,18 @@ struct zfcp_adapter { u32 erp_low_mem_count; /* nr of erp actions waiting for memory */ struct zfcp_port *nameserver_port; /* adapter's nameserver */ - debug_info_t *erp_dbf; /* S/390 debug features */ - debug_info_t *abort_dbf; - debug_info_t *in_els_dbf; - debug_info_t *cmd_dbf; - spinlock_t dbf_lock; + debug_info_t *erp_dbf; + debug_info_t *hba_dbf; + debug_info_t *san_dbf; /* debug feature areas */ + debug_info_t *scsi_dbf; + spinlock_t erp_dbf_lock; + spinlock_t hba_dbf_lock; + spinlock_t san_dbf_lock; + spinlock_t scsi_dbf_lock; + struct zfcp_erp_dbf_record erp_dbf_buf; + struct zfcp_hba_dbf_record hba_dbf_buf; + struct zfcp_san_dbf_record san_dbf_buf; + struct zfcp_scsi_dbf_record scsi_dbf_buf; struct zfcp_adapter_mempool pool; /* Adapter memory pools */ struct qdio_initialize qdio_init_data; /* for qdio_establish */ struct device generic_services; /* directory for WKA ports */ @@ -919,7 +1000,7 @@ struct zfcp_port { atomic_t status; /* status of this remote port */ wwn_t wwnn; /* WWNN if known */ wwn_t wwpn; /* WWPN */ - fc_id_t d_id; /* D_ID */ + u32 d_id; /* D_ID */ u32 handle; /* handle assigned by FSF */ struct zfcp_erp_action erp_action; /* pending error recovery */ atomic_t erp_counter; @@ -963,11 +1044,13 @@ struct zfcp_fsf_req { u32 fsf_command; /* FSF Command copy */ struct fsf_qtcb *qtcb; /* address of associated QTCB */ u32 seq_no; /* Sequence number of request */ - union zfcp_req_data data; /* Info fields of request */ + unsigned long data; /* private data of request */ struct zfcp_erp_action *erp_action; /* used if this request is issued on behalf of erp */ mempool_t *pool; /* used if request was alloacted from emergency pool */ + unsigned long long issued; /* request sent time (STCK) */ + struct zfcp_unit *unit; }; typedef void zfcp_fsf_req_handler_t(struct zfcp_fsf_req*); diff --git a/drivers/s390/scsi/zfcp_erp.c b/drivers/s390/scsi/zfcp_erp.c index cb4f612..023f4e5 100644 --- a/drivers/s390/scsi/zfcp_erp.c +++ b/drivers/s390/scsi/zfcp_erp.c @@ -82,6 +82,7 @@ static int zfcp_erp_adapter_strategy_open(struct zfcp_erp_action *); static int zfcp_erp_adapter_strategy_open_qdio(struct zfcp_erp_action *); static int zfcp_erp_adapter_strategy_open_fsf(struct zfcp_erp_action *); static int zfcp_erp_adapter_strategy_open_fsf_xconfig(struct zfcp_erp_action *); +static int zfcp_erp_adapter_strategy_open_fsf_xport(struct zfcp_erp_action *); static int zfcp_erp_adapter_strategy_open_fsf_statusread( struct zfcp_erp_action *); @@ -345,13 +346,13 @@ zfcp_erp_adisc(struct zfcp_port *port) /* acc. to FC-FS, hard_nport_id in ADISC should not be set for ports without FC-AL-2 capability, so we don't set it */ - adisc->wwpn = adapter->wwpn; - adisc->wwnn = adapter->wwnn; - adisc->nport_id = adapter->s_id; + adisc->wwpn = fc_host_port_name(adapter->scsi_host); + adisc->wwnn = fc_host_node_name(adapter->scsi_host); + adisc->nport_id = fc_host_port_id(adapter->scsi_host); ZFCP_LOG_INFO("ADISC request from s_id 0x%08x to d_id 0x%08x " "(wwpn=0x%016Lx, wwnn=0x%016Lx, " "hard_nport_id=0x%08x, nport_id=0x%08x)\n", - adapter->s_id, send_els->d_id, (wwn_t) adisc->wwpn, + adisc->nport_id, send_els->d_id, (wwn_t) adisc->wwpn, (wwn_t) adisc->wwnn, adisc->hard_nport_id, adisc->nport_id); @@ -404,7 +405,7 @@ zfcp_erp_adisc_handler(unsigned long data) struct zfcp_send_els *send_els; struct zfcp_port *port; struct zfcp_adapter *adapter; - fc_id_t d_id; + u32 d_id; struct zfcp_ls_adisc_acc *adisc; send_els = (struct zfcp_send_els *) data; @@ -435,9 +436,9 @@ zfcp_erp_adisc_handler(unsigned long data) ZFCP_LOG_INFO("ADISC response from d_id 0x%08x to s_id " "0x%08x (wwpn=0x%016Lx, wwnn=0x%016Lx, " "hard_nport_id=0x%08x, nport_id=0x%08x)\n", - d_id, adapter->s_id, (wwn_t) adisc->wwpn, - (wwn_t) adisc->wwnn, adisc->hard_nport_id, - adisc->nport_id); + d_id, fc_host_port_id(adapter->scsi_host), + (wwn_t) adisc->wwpn, (wwn_t) adisc->wwnn, + adisc->hard_nport_id, adisc->nport_id); /* set wwnn for port */ if (port->wwnn == 0) @@ -886,7 +887,7 @@ static int zfcp_erp_strategy_check_fsfreq(struct zfcp_erp_action *erp_action) { int retval = 0; - struct zfcp_fsf_req *fsf_req; + struct zfcp_fsf_req *fsf_req = NULL; struct zfcp_adapter *adapter = erp_action->adapter; if (erp_action->fsf_req) { @@ -896,7 +897,7 @@ zfcp_erp_strategy_check_fsfreq(struct zfcp_erp_action *erp_action) list_for_each_entry(fsf_req, &adapter->fsf_req_list_head, list) if (fsf_req == erp_action->fsf_req) break; - if (fsf_req == erp_action->fsf_req) { + if (fsf_req && (fsf_req->erp_action == erp_action)) { /* fsf_req still exists */ debug_text_event(adapter->erp_dbf, 3, "a_ca_req"); debug_event(adapter->erp_dbf, 3, &fsf_req, @@ -2258,16 +2259,21 @@ zfcp_erp_adapter_strategy_close_qdio(struct zfcp_erp_action *erp_action) static int zfcp_erp_adapter_strategy_open_fsf(struct zfcp_erp_action *erp_action) { - int retval; + int xconfig, xport; + + if (atomic_test_mask(ZFCP_STATUS_ADAPTER_LINK_UNPLUGGED, + &erp_action->adapter->status)) { + zfcp_erp_adapter_strategy_open_fsf_xport(erp_action); + atomic_set(&erp_action->adapter->erp_counter, 0); + return ZFCP_ERP_FAILED; + } - /* do 'exchange configuration data' */ - retval = zfcp_erp_adapter_strategy_open_fsf_xconfig(erp_action); - if (retval == ZFCP_ERP_FAILED) - return retval; + xconfig = zfcp_erp_adapter_strategy_open_fsf_xconfig(erp_action); + xport = zfcp_erp_adapter_strategy_open_fsf_xport(erp_action); + if ((xconfig == ZFCP_ERP_FAILED) || (xport == ZFCP_ERP_FAILED)) + return ZFCP_ERP_FAILED; - /* start the desired number of Status Reads */ - retval = zfcp_erp_adapter_strategy_open_fsf_statusread(erp_action); - return retval; + return zfcp_erp_adapter_strategy_open_fsf_statusread(erp_action); } /* @@ -2291,7 +2297,9 @@ zfcp_erp_adapter_strategy_open_fsf_xconfig(struct zfcp_erp_action *erp_action) atomic_clear_mask(ZFCP_STATUS_ADAPTER_HOST_CON_INIT, &adapter->status); ZFCP_LOG_DEBUG("Doing exchange config data\n"); + write_lock(&adapter->erp_lock); zfcp_erp_action_to_running(erp_action); + write_unlock(&adapter->erp_lock); zfcp_erp_timeout_init(erp_action); if (zfcp_fsf_exchange_config_data(erp_action)) { retval = ZFCP_ERP_FAILED; @@ -2348,6 +2356,76 @@ zfcp_erp_adapter_strategy_open_fsf_xconfig(struct zfcp_erp_action *erp_action) return retval; } +static int +zfcp_erp_adapter_strategy_open_fsf_xport(struct zfcp_erp_action *erp_action) +{ + int retval = ZFCP_ERP_SUCCEEDED; + int retries; + int sleep; + struct zfcp_adapter *adapter = erp_action->adapter; + + atomic_clear_mask(ZFCP_STATUS_ADAPTER_XPORT_OK, &adapter->status); + + for (retries = 0; ; retries++) { + ZFCP_LOG_DEBUG("Doing exchange port data\n"); + zfcp_erp_action_to_running(erp_action); + zfcp_erp_timeout_init(erp_action); + if (zfcp_fsf_exchange_port_data(erp_action, adapter, NULL)) { + retval = ZFCP_ERP_FAILED; + debug_text_event(adapter->erp_dbf, 5, "a_fstx_xf"); + ZFCP_LOG_INFO("error: initiation of exchange of " + "port data failed for adapter %s\n", + zfcp_get_busid_by_adapter(adapter)); + break; + } + debug_text_event(adapter->erp_dbf, 6, "a_fstx_xok"); + ZFCP_LOG_DEBUG("Xchange underway\n"); + + /* + * Why this works: + * Both the normal completion handler as well as the timeout + * handler will do an 'up' when the 'exchange port data' + * request completes or times out. Thus, the signal to go on + * won't be lost utilizing this semaphore. + * Furthermore, this 'adapter_reopen' action is + * guaranteed to be the only action being there (highest action + * which prevents other actions from being created). + * Resulting from that, the wake signal recognized here + * _must_ be the one belonging to the 'exchange port + * data' request. + */ + down(&adapter->erp_ready_sem); + if (erp_action->status & ZFCP_STATUS_ERP_TIMEDOUT) { + ZFCP_LOG_INFO("error: exchange of port data " + "for adapter %s timed out\n", + zfcp_get_busid_by_adapter(adapter)); + break; + } + + if (!atomic_test_mask(ZFCP_STATUS_ADAPTER_LINK_UNPLUGGED, + &adapter->status)) + break; + + ZFCP_LOG_DEBUG("host connection still initialising... " + "waiting and retrying...\n"); + /* sleep a little bit before retry */ + sleep = retries < ZFCP_EXCHANGE_PORT_DATA_SHORT_RETRIES ? + ZFCP_EXCHANGE_PORT_DATA_SHORT_SLEEP : + ZFCP_EXCHANGE_PORT_DATA_LONG_SLEEP; + msleep(jiffies_to_msecs(sleep)); + } + + if (atomic_test_mask(ZFCP_STATUS_ADAPTER_LINK_UNPLUGGED, + &adapter->status)) { + ZFCP_LOG_INFO("error: exchange of port data for " + "adapter %s failed\n", + zfcp_get_busid_by_adapter(adapter)); + retval = ZFCP_ERP_FAILED; + } + + return retval; +} + /* * function: * @@ -3194,11 +3272,19 @@ zfcp_erp_action_enqueue(int action, /* fall through !!! */ case ZFCP_ERP_ACTION_REOPEN_PORT_FORCED: - if (atomic_test_mask - (ZFCP_STATUS_COMMON_ERP_INUSE, &port->status) - && port->erp_action.action == - ZFCP_ERP_ACTION_REOPEN_PORT_FORCED) { - debug_text_event(adapter->erp_dbf, 4, "pf_actenq_drp"); + if (atomic_test_mask(ZFCP_STATUS_COMMON_ERP_INUSE, + &port->status)) { + if (port->erp_action.action != + ZFCP_ERP_ACTION_REOPEN_PORT_FORCED) { + ZFCP_LOG_INFO("dropped erp action %i (port " + "0x%016Lx, action in use: %i)\n", + action, port->wwpn, + port->erp_action.action); + debug_text_event(adapter->erp_dbf, 4, + "pf_actenq_drp"); + } else + debug_text_event(adapter->erp_dbf, 4, + "pf_actenq_drpcp"); debug_event(adapter->erp_dbf, 4, &port->wwpn, sizeof (wwn_t)); goto out; @@ -3589,6 +3675,9 @@ zfcp_erp_adapter_access_changed(struct zfcp_adapter *adapter) struct zfcp_port *port; unsigned long flags; + if (adapter->connection_features & FSF_FEATURE_NPIV_MODE) + return; + debug_text_event(adapter->erp_dbf, 3, "a_access_recover"); debug_event(adapter->erp_dbf, 3, &adapter->name, 8); diff --git a/drivers/s390/scsi/zfcp_ext.h b/drivers/s390/scsi/zfcp_ext.h index cd98a2d..c378226 100644 --- a/drivers/s390/scsi/zfcp_ext.h +++ b/drivers/s390/scsi/zfcp_ext.h @@ -96,7 +96,8 @@ extern int zfcp_fsf_open_unit(struct zfcp_erp_action *); extern int zfcp_fsf_close_unit(struct zfcp_erp_action *); extern int zfcp_fsf_exchange_config_data(struct zfcp_erp_action *); -extern int zfcp_fsf_exchange_port_data(struct zfcp_adapter *, +extern int zfcp_fsf_exchange_port_data(struct zfcp_erp_action *, + struct zfcp_adapter *, struct fsf_qtcb_bottom_port *); extern int zfcp_fsf_control_file(struct zfcp_adapter *, struct zfcp_fsf_req **, u32, u32, struct zfcp_sg_list *); @@ -109,7 +110,6 @@ extern int zfcp_fsf_req_create(struct zfcp_adapter *, u32, int, mempool_t *, extern int zfcp_fsf_send_ct(struct zfcp_send_ct *, mempool_t *, struct zfcp_erp_action *); extern int zfcp_fsf_send_els(struct zfcp_send_els *); -extern int zfcp_fsf_req_wait_and_cleanup(struct zfcp_fsf_req *, int, u32 *); extern int zfcp_fsf_send_fcp_command_task(struct zfcp_adapter *, struct zfcp_unit *, struct scsi_cmnd *, @@ -182,9 +182,25 @@ extern void zfcp_erp_port_access_changed(struct zfcp_port *); extern void zfcp_erp_unit_access_changed(struct zfcp_unit *); /******************************** AUX ****************************************/ -extern void zfcp_cmd_dbf_event_fsf(const char *, struct zfcp_fsf_req *, - void *, int); -extern void zfcp_cmd_dbf_event_scsi(const char *, struct scsi_cmnd *); -extern void zfcp_in_els_dbf_event(struct zfcp_adapter *, const char *, - struct fsf_status_read_buffer *, int); +extern void zfcp_hba_dbf_event_fsf_response(struct zfcp_fsf_req *); +extern void zfcp_hba_dbf_event_fsf_unsol(const char *, struct zfcp_adapter *, + struct fsf_status_read_buffer *); +extern void zfcp_hba_dbf_event_qdio(struct zfcp_adapter *, + unsigned int, unsigned int, unsigned int, + int, int); + +extern void zfcp_san_dbf_event_ct_request(struct zfcp_fsf_req *); +extern void zfcp_san_dbf_event_ct_response(struct zfcp_fsf_req *); +extern void zfcp_san_dbf_event_els_request(struct zfcp_fsf_req *); +extern void zfcp_san_dbf_event_els_response(struct zfcp_fsf_req *); +extern void zfcp_san_dbf_event_incoming_els(struct zfcp_fsf_req *); + +extern void zfcp_scsi_dbf_event_result(const char *, int, struct zfcp_adapter *, + struct scsi_cmnd *); +extern void zfcp_scsi_dbf_event_abort(const char *, struct zfcp_adapter *, + struct scsi_cmnd *, + struct zfcp_fsf_req *); +extern void zfcp_scsi_dbf_event_devreset(const char *, u8, struct zfcp_unit *, + struct scsi_cmnd *); + #endif /* ZFCP_EXT_H */ diff --git a/drivers/s390/scsi/zfcp_fsf.c b/drivers/s390/scsi/zfcp_fsf.c index c007b64..3b0fc11 100644 --- a/drivers/s390/scsi/zfcp_fsf.c +++ b/drivers/s390/scsi/zfcp_fsf.c @@ -59,6 +59,8 @@ static int zfcp_fsf_req_send(struct zfcp_fsf_req *, struct timer_list *); static int zfcp_fsf_protstatus_eval(struct zfcp_fsf_req *); static int zfcp_fsf_fsfstatus_eval(struct zfcp_fsf_req *); static int zfcp_fsf_fsfstatus_qual_eval(struct zfcp_fsf_req *); +static void zfcp_fsf_link_down_info_eval(struct zfcp_adapter *, + struct fsf_link_down_info *); static int zfcp_fsf_req_dispatch(struct zfcp_fsf_req *); static void zfcp_fsf_req_dismiss(struct zfcp_fsf_req *); @@ -285,51 +287,51 @@ zfcp_fsf_protstatus_eval(struct zfcp_fsf_req *fsf_req) { int retval = 0; struct zfcp_adapter *adapter = fsf_req->adapter; + struct fsf_qtcb *qtcb = fsf_req->qtcb; + union fsf_prot_status_qual *prot_status_qual = + &qtcb->prefix.prot_status_qual; - ZFCP_LOG_DEBUG("QTCB is at %p\n", fsf_req->qtcb); + zfcp_hba_dbf_event_fsf_response(fsf_req); if (fsf_req->status & ZFCP_STATUS_FSFREQ_DISMISSED) { ZFCP_LOG_DEBUG("fsf_req 0x%lx has been dismissed\n", (unsigned long) fsf_req); fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR | ZFCP_STATUS_FSFREQ_RETRY; /* only for SCSI cmnds. */ - zfcp_cmd_dbf_event_fsf("dismiss", fsf_req, NULL, 0); goto skip_protstatus; } /* log additional information provided by FSF (if any) */ - if (unlikely(fsf_req->qtcb->header.log_length)) { + if (unlikely(qtcb->header.log_length)) { /* do not trust them ;-) */ - if (fsf_req->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. " "(start=%i, size=%li)\n", - fsf_req->qtcb->header.log_start, + qtcb->header.log_start, sizeof(struct fsf_qtcb)); goto forget_log; } - if ((size_t) (fsf_req->qtcb->header.log_start + - fsf_req->qtcb->header.log_length) + 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", - fsf_req->qtcb->header.log_start, - fsf_req->qtcb->header.log_length, + qtcb->header.log_start, + qtcb->header.log_length, sizeof(struct fsf_qtcb)); goto forget_log; } ZFCP_LOG_TRACE("ULP log data: \n"); ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_TRACE, - (char *) fsf_req->qtcb + - fsf_req->qtcb->header.log_start, - fsf_req->qtcb->header.log_length); + (char *) qtcb + qtcb->header.log_start, + qtcb->header.log_length); } forget_log: /* evaluate FSF Protocol Status */ - switch (fsf_req->qtcb->prefix.prot_status) { + switch (qtcb->prefix.prot_status) { case FSF_PROT_GOOD: case FSF_PROT_FSF_STATUS_PRESENTED: @@ -340,14 +342,9 @@ zfcp_fsf_protstatus_eval(struct zfcp_fsf_req *fsf_req) "microcode of version 0x%x, the device driver " "only supports 0x%x. Aborting.\n", zfcp_get_busid_by_adapter(adapter), - fsf_req->qtcb->prefix.prot_status_qual. - version_error.fsf_version, ZFCP_QTCB_VERSION); - /* stop operation for this adapter */ - debug_text_exception(adapter->erp_dbf, 0, "prot_ver_err"); + prot_status_qual->version_error.fsf_version, + ZFCP_QTCB_VERSION); zfcp_erp_adapter_shutdown(adapter, 0); - zfcp_cmd_dbf_event_fsf("qverserr", fsf_req, - &fsf_req->qtcb->prefix.prot_status_qual, - sizeof (union fsf_prot_status_qual)); fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; break; @@ -355,16 +352,10 @@ zfcp_fsf_protstatus_eval(struct zfcp_fsf_req *fsf_req) ZFCP_LOG_NORMAL("bug: Sequence number mismatch between " "driver (0x%x) and adapter %s (0x%x). " "Restarting all operations on this adapter.\n", - fsf_req->qtcb->prefix.req_seq_no, + qtcb->prefix.req_seq_no, zfcp_get_busid_by_adapter(adapter), - fsf_req->qtcb->prefix.prot_status_qual. - sequence_error.exp_req_seq_no); - debug_text_exception(adapter->erp_dbf, 0, "prot_seq_err"); - /* restart operation on this adapter */ + prot_status_qual->sequence_error.exp_req_seq_no); zfcp_erp_adapter_reopen(adapter, 0); - zfcp_cmd_dbf_event_fsf("seqnoerr", fsf_req, - &fsf_req->qtcb->prefix.prot_status_qual, - sizeof (union fsf_prot_status_qual)); fsf_req->status |= ZFCP_STATUS_FSFREQ_RETRY; fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; break; @@ -375,116 +366,35 @@ zfcp_fsf_protstatus_eval(struct zfcp_fsf_req *fsf_req) "that used on adapter %s. " "Stopping all operations on this adapter.\n", zfcp_get_busid_by_adapter(adapter)); - debug_text_exception(adapter->erp_dbf, 0, "prot_unsup_qtcb"); zfcp_erp_adapter_shutdown(adapter, 0); - zfcp_cmd_dbf_event_fsf("unsqtcbt", fsf_req, - &fsf_req->qtcb->prefix.prot_status_qual, - sizeof (union fsf_prot_status_qual)); fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; break; case FSF_PROT_HOST_CONNECTION_INITIALIZING: - zfcp_cmd_dbf_event_fsf("hconinit", fsf_req, - &fsf_req->qtcb->prefix.prot_status_qual, - sizeof (union fsf_prot_status_qual)); fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; atomic_set_mask(ZFCP_STATUS_ADAPTER_HOST_CON_INIT, &(adapter->status)); - debug_text_event(adapter->erp_dbf, 3, "prot_con_init"); break; case FSF_PROT_DUPLICATE_REQUEST_ID: - if (fsf_req->qtcb) { ZFCP_LOG_NORMAL("bug: The request identifier 0x%Lx " "to the adapter %s is ambiguous. " - "Stopping all operations on this " - "adapter.\n", - *(unsigned long long *) - (&fsf_req->qtcb->bottom.support. - req_handle), - zfcp_get_busid_by_adapter(adapter)); - } else { - ZFCP_LOG_NORMAL("bug: The request identifier %p " - "to the adapter %s is ambiguous. " - "Stopping all operations on this " - "adapter. " - "(bug: got this for an unsolicited " - "status read request)\n", - fsf_req, + "Stopping all operations on this adapter.\n", + *(unsigned long long*) + (&qtcb->bottom.support.req_handle), zfcp_get_busid_by_adapter(adapter)); - } - debug_text_exception(adapter->erp_dbf, 0, "prot_dup_id"); zfcp_erp_adapter_shutdown(adapter, 0); - zfcp_cmd_dbf_event_fsf("dupreqid", fsf_req, - &fsf_req->qtcb->prefix.prot_status_qual, - sizeof (union fsf_prot_status_qual)); fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; break; case FSF_PROT_LINK_DOWN: - /* - * 'test and set' is not atomic here - - * it's ok as long as calls to our response queue handler - * (and thus execution of this code here) are serialized - * by the qdio module - */ - if (!atomic_test_mask(ZFCP_STATUS_ADAPTER_LINK_UNPLUGGED, - &adapter->status)) { - switch (fsf_req->qtcb->prefix.prot_status_qual. - locallink_error.code) { - case FSF_PSQ_LINK_NOLIGHT: - ZFCP_LOG_INFO("The local link to adapter %s " - "is down (no light detected).\n", - zfcp_get_busid_by_adapter( - adapter)); - break; - case FSF_PSQ_LINK_WRAPPLUG: - ZFCP_LOG_INFO("The local link to adapter %s " - "is down (wrap plug detected).\n", - zfcp_get_busid_by_adapter( - adapter)); - break; - case FSF_PSQ_LINK_NOFCP: - ZFCP_LOG_INFO("The local link to adapter %s " - "is down (adjacent node on " - "link does not support FCP).\n", - zfcp_get_busid_by_adapter( - adapter)); - break; - default: - ZFCP_LOG_INFO("The local link to adapter %s " - "is down " - "(warning: unknown reason " - "code).\n", - zfcp_get_busid_by_adapter( - adapter)); - break; - - } - /* - * Due to the 'erp failed' flag the adapter won't - * be recovered but will be just set to 'blocked' - * state. All subordinary devices will have state - * 'blocked' and 'erp failed', too. - * Thus the adapter is still able to provide - * 'link up' status without being flooded with - * requests. - * (note: even 'close port' is not permitted) - */ - ZFCP_LOG_INFO("Stopping all operations for adapter " - "%s.\n", - zfcp_get_busid_by_adapter(adapter)); - atomic_set_mask(ZFCP_STATUS_ADAPTER_LINK_UNPLUGGED | - ZFCP_STATUS_COMMON_ERP_FAILED, - &adapter->status); - zfcp_erp_adapter_reopen(adapter, 0); - } + zfcp_fsf_link_down_info_eval(adapter, + &prot_status_qual->link_down_info); fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; break; case FSF_PROT_REEST_QUEUE: - debug_text_event(adapter->erp_dbf, 1, "prot_reest_queue"); - ZFCP_LOG_INFO("The local link to adapter with " + ZFCP_LOG_NORMAL("The local link to adapter with " "%s was re-plugged. " "Re-starting operations on this adapter.\n", zfcp_get_busid_by_adapter(adapter)); @@ -495,9 +405,6 @@ zfcp_fsf_protstatus_eval(struct zfcp_fsf_req *fsf_req) zfcp_erp_adapter_reopen(adapter, ZFCP_STATUS_ADAPTER_LINK_UNPLUGGED | ZFCP_STATUS_COMMON_ERP_FAILED); - zfcp_cmd_dbf_event_fsf("reestque", fsf_req, - &fsf_req->qtcb->prefix.prot_status_qual, - sizeof (union fsf_prot_status_qual)); fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; break; @@ -507,12 +414,7 @@ zfcp_fsf_protstatus_eval(struct zfcp_fsf_req *fsf_req) "Restarting all operations on this " "adapter.\n", zfcp_get_busid_by_adapter(adapter)); - debug_text_event(adapter->erp_dbf, 0, "prot_err_sta"); - /* restart operation on this adapter */ zfcp_erp_adapter_reopen(adapter, 0); - zfcp_cmd_dbf_event_fsf("proterrs", fsf_req, - &fsf_req->qtcb->prefix.prot_status_qual, - sizeof (union fsf_prot_status_qual)); fsf_req->status |= ZFCP_STATUS_FSFREQ_RETRY; fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; break; @@ -524,11 +426,7 @@ zfcp_fsf_protstatus_eval(struct zfcp_fsf_req *fsf_req) "Stopping all operations on this adapter. " "(debug info 0x%x).\n", zfcp_get_busid_by_adapter(adapter), - fsf_req->qtcb->prefix.prot_status); - debug_text_event(adapter->erp_dbf, 0, "prot_inval:"); - debug_exception(adapter->erp_dbf, 0, - &fsf_req->qtcb->prefix.prot_status, - sizeof (u32)); + qtcb->prefix.prot_status); zfcp_erp_adapter_shutdown(adapter, 0); fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; } @@ -568,28 +466,18 @@ zfcp_fsf_fsfstatus_eval(struct zfcp_fsf_req *fsf_req) "(debug info 0x%x).\n", zfcp_get_busid_by_adapter(fsf_req->adapter), fsf_req->qtcb->header.fsf_command); - debug_text_exception(fsf_req->adapter->erp_dbf, 0, - "fsf_s_unknown"); zfcp_erp_adapter_shutdown(fsf_req->adapter, 0); - zfcp_cmd_dbf_event_fsf("unknownc", fsf_req, - &fsf_req->qtcb->header.fsf_status_qual, - sizeof (union fsf_status_qual)); fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; break; case FSF_FCP_RSP_AVAILABLE: ZFCP_LOG_DEBUG("FCP Sense data will be presented to the " "SCSI stack.\n"); - debug_text_event(fsf_req->adapter->erp_dbf, 3, "fsf_s_rsp"); break; case FSF_ADAPTER_STATUS_AVAILABLE: - debug_text_event(fsf_req->adapter->erp_dbf, 2, "fsf_s_astatus"); zfcp_fsf_fsfstatus_qual_eval(fsf_req); break; - - default: - break; } skip_fsfstatus: @@ -617,44 +505,28 @@ zfcp_fsf_fsfstatus_qual_eval(struct zfcp_fsf_req *fsf_req) switch (fsf_req->qtcb->header.fsf_status_qual.word[0]) { case FSF_SQ_FCP_RSP_AVAILABLE: - debug_text_event(fsf_req->adapter->erp_dbf, 4, "fsf_sq_rsp"); break; case FSF_SQ_RETRY_IF_POSSIBLE: /* The SCSI-stack may now issue retries or escalate */ - debug_text_event(fsf_req->adapter->erp_dbf, 2, "fsf_sq_retry"); - zfcp_cmd_dbf_event_fsf("sqretry", fsf_req, - &fsf_req->qtcb->header.fsf_status_qual, - sizeof (union fsf_status_qual)); fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; break; case FSF_SQ_COMMAND_ABORTED: /* Carry the aborted state on to upper layer */ - debug_text_event(fsf_req->adapter->erp_dbf, 2, "fsf_sq_abort"); - zfcp_cmd_dbf_event_fsf("sqabort", fsf_req, - &fsf_req->qtcb->header.fsf_status_qual, - sizeof (union fsf_status_qual)); fsf_req->status |= ZFCP_STATUS_FSFREQ_ABORTED; fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; break; case FSF_SQ_NO_RECOM: - debug_text_exception(fsf_req->adapter->erp_dbf, 0, - "fsf_sq_no_rec"); ZFCP_LOG_NORMAL("bug: No recommendation could be given for a" "problem on the adapter %s " "Stopping all operations on this adapter. ", zfcp_get_busid_by_adapter(fsf_req->adapter)); zfcp_erp_adapter_shutdown(fsf_req->adapter, 0); - zfcp_cmd_dbf_event_fsf("sqnrecom", fsf_req, - &fsf_req->qtcb->header.fsf_status_qual, - sizeof (union fsf_status_qual)); fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; break; case FSF_SQ_ULP_PROGRAMMING_ERROR: ZFCP_LOG_NORMAL("error: not enough SBALs for data transfer " "(adapter %s)\n", zfcp_get_busid_by_adapter(fsf_req->adapter)); - debug_text_exception(fsf_req->adapter->erp_dbf, 0, - "fsf_sq_ulp_err"); fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; break; case FSF_SQ_INVOKE_LINK_TEST_PROCEDURE: @@ -668,13 +540,6 @@ zfcp_fsf_fsfstatus_qual_eval(struct zfcp_fsf_req *fsf_req) ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_NORMAL, (char *) &fsf_req->qtcb->header.fsf_status_qual, sizeof (union fsf_status_qual)); - debug_text_event(fsf_req->adapter->erp_dbf, 0, "fsf_sq_inval:"); - debug_exception(fsf_req->adapter->erp_dbf, 0, - &fsf_req->qtcb->header.fsf_status_qual.word[0], - sizeof (u32)); - zfcp_cmd_dbf_event_fsf("squndef", fsf_req, - &fsf_req->qtcb->header.fsf_status_qual, - sizeof (union fsf_status_qual)); fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; break; } @@ -682,6 +547,110 @@ zfcp_fsf_fsfstatus_qual_eval(struct zfcp_fsf_req *fsf_req) return retval; } +/** + * zfcp_fsf_link_down_info_eval - evaluate link down information block + */ +static void +zfcp_fsf_link_down_info_eval(struct zfcp_adapter *adapter, + struct fsf_link_down_info *link_down) +{ + switch (link_down->error_code) { + case FSF_PSQ_LINK_NO_LIGHT: + ZFCP_LOG_NORMAL("The local link to adapter %s is down " + "(no light detected)\n", + zfcp_get_busid_by_adapter(adapter)); + break; + case FSF_PSQ_LINK_WRAP_PLUG: + ZFCP_LOG_NORMAL("The local link to adapter %s is down " + "(wrap plug detected)\n", + zfcp_get_busid_by_adapter(adapter)); + break; + case FSF_PSQ_LINK_NO_FCP: + ZFCP_LOG_NORMAL("The local link to adapter %s is down " + "(adjacent node on link does not support FCP)\n", + zfcp_get_busid_by_adapter(adapter)); + break; + case FSF_PSQ_LINK_FIRMWARE_UPDATE: + ZFCP_LOG_NORMAL("The local link to adapter %s is down " + "(firmware update in progress)\n", + zfcp_get_busid_by_adapter(adapter)); + break; + case FSF_PSQ_LINK_INVALID_WWPN: + ZFCP_LOG_NORMAL("The local link to adapter %s is down " + "(duplicate or invalid WWPN detected)\n", + zfcp_get_busid_by_adapter(adapter)); + break; + case FSF_PSQ_LINK_NO_NPIV_SUPPORT: + ZFCP_LOG_NORMAL("The local link to adapter %s is down " + "(no support for NPIV by Fabric)\n", + zfcp_get_busid_by_adapter(adapter)); + break; + case FSF_PSQ_LINK_NO_FCP_RESOURCES: + ZFCP_LOG_NORMAL("The local link to adapter %s is down " + "(out of resource in FCP daughtercard)\n", + zfcp_get_busid_by_adapter(adapter)); + break; + case FSF_PSQ_LINK_NO_FABRIC_RESOURCES: + ZFCP_LOG_NORMAL("The local link to adapter %s is down " + "(out of resource in Fabric)\n", + zfcp_get_busid_by_adapter(adapter)); + break; + case FSF_PSQ_LINK_FABRIC_LOGIN_UNABLE: + ZFCP_LOG_NORMAL("The local link to adapter %s is down " + "(unable to Fabric login)\n", + zfcp_get_busid_by_adapter(adapter)); + break; + case FSF_PSQ_LINK_WWPN_ASSIGNMENT_CORRUPTED: + ZFCP_LOG_NORMAL("WWPN assignment file corrupted on adapter %s\n", + zfcp_get_busid_by_adapter(adapter)); + break; + case FSF_PSQ_LINK_MODE_TABLE_CURRUPTED: + ZFCP_LOG_NORMAL("Mode table corrupted on adapter %s\n", + zfcp_get_busid_by_adapter(adapter)); + break; + case FSF_PSQ_LINK_NO_WWPN_ASSIGNMENT: + ZFCP_LOG_NORMAL("No WWPN for assignment table on adapter %s\n", + zfcp_get_busid_by_adapter(adapter)); + break; + default: + ZFCP_LOG_NORMAL("The local link to adapter %s is down " + "(warning: unknown reason code %d)\n", + zfcp_get_busid_by_adapter(adapter), + link_down->error_code); + } + + if (adapter->connection_features & FSF_FEATURE_NPIV_MODE) + ZFCP_LOG_DEBUG("Debug information to link down: " + "primary_status=0x%02x " + "ioerr_code=0x%02x " + "action_code=0x%02x " + "reason_code=0x%02x " + "explanation_code=0x%02x " + "vendor_specific_code=0x%02x\n", + link_down->primary_status, + link_down->ioerr_code, + link_down->action_code, + link_down->reason_code, + link_down->explanation_code, + link_down->vendor_specific_code); + + if (!atomic_test_mask(ZFCP_STATUS_ADAPTER_LINK_UNPLUGGED, + &adapter->status)) { + atomic_set_mask(ZFCP_STATUS_ADAPTER_LINK_UNPLUGGED, + &adapter->status); + switch (link_down->error_code) { + case FSF_PSQ_LINK_NO_LIGHT: + case FSF_PSQ_LINK_WRAP_PLUG: + case FSF_PSQ_LINK_NO_FCP: + case FSF_PSQ_LINK_FIRMWARE_UPDATE: + zfcp_erp_adapter_reopen(adapter, 0); + break; + default: + zfcp_erp_adapter_failed(adapter); + } + } +} + /* * function: zfcp_fsf_req_dispatch * @@ -696,11 +665,6 @@ zfcp_fsf_req_dispatch(struct zfcp_fsf_req *fsf_req) struct zfcp_adapter *adapter = fsf_req->adapter; int retval = 0; - if (unlikely(fsf_req->status & ZFCP_STATUS_FSFREQ_ERROR)) { - ZFCP_LOG_TRACE("fsf_req=%p, QTCB=%p\n", fsf_req, fsf_req->qtcb); - ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_TRACE, - (char *) fsf_req->qtcb, sizeof(struct fsf_qtcb)); - } switch (fsf_req->fsf_command) { @@ -760,13 +724,13 @@ zfcp_fsf_req_dispatch(struct zfcp_fsf_req *fsf_req) fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; ZFCP_LOG_NORMAL("bug: Command issued by the device driver is " "not supported by the adapter %s\n", - zfcp_get_busid_by_adapter(fsf_req->adapter)); + zfcp_get_busid_by_adapter(adapter)); if (fsf_req->fsf_command != fsf_req->qtcb->header.fsf_command) ZFCP_LOG_NORMAL ("bug: Command issued by the device driver differs " "from the command returned by the adapter %s " "(debug info 0x%x, 0x%x).\n", - zfcp_get_busid_by_adapter(fsf_req->adapter), + zfcp_get_busid_by_adapter(adapter), fsf_req->fsf_command, fsf_req->qtcb->header.fsf_command); } @@ -774,8 +738,6 @@ zfcp_fsf_req_dispatch(struct zfcp_fsf_req *fsf_req) if (!erp_action) return retval; - debug_text_event(adapter->erp_dbf, 3, "a_frh"); - debug_event(adapter->erp_dbf, 3, &erp_action->action, sizeof (int)); zfcp_erp_async_handler(erp_action, 0); return retval; @@ -821,7 +783,7 @@ zfcp_fsf_status_read(struct zfcp_adapter *adapter, int req_flags) goto failed_buf; } memset(status_buffer, 0, sizeof (struct fsf_status_read_buffer)); - fsf_req->data.status_read.buffer = status_buffer; + fsf_req->data = (unsigned long) status_buffer; /* insert pointer to respective buffer */ sbale = zfcp_qdio_sbale_curr(fsf_req); @@ -846,6 +808,7 @@ zfcp_fsf_status_read(struct zfcp_adapter *adapter, int req_flags) failed_buf: zfcp_fsf_req_free(fsf_req); failed_req_create: + zfcp_hba_dbf_event_fsf_unsol("fail", adapter, NULL); out: write_unlock_irqrestore(&adapter->request_queue.queue_lock, lock_flags); return retval; @@ -859,7 +822,7 @@ zfcp_fsf_status_read_port_closed(struct zfcp_fsf_req *fsf_req) struct zfcp_port *port; unsigned long flags; - status_buffer = fsf_req->data.status_read.buffer; + status_buffer = (struct fsf_status_read_buffer *) fsf_req->data; adapter = fsf_req->adapter; read_lock_irqsave(&zfcp_data.config_lock, flags); @@ -918,38 +881,33 @@ zfcp_fsf_status_read_handler(struct zfcp_fsf_req *fsf_req) int retval = 0; struct zfcp_adapter *adapter = fsf_req->adapter; struct fsf_status_read_buffer *status_buffer = - fsf_req->data.status_read.buffer; + (struct fsf_status_read_buffer *) fsf_req->data; if (fsf_req->status & ZFCP_STATUS_FSFREQ_DISMISSED) { + zfcp_hba_dbf_event_fsf_unsol("dism", adapter, status_buffer); mempool_free(status_buffer, adapter->pool.data_status_read); zfcp_fsf_req_free(fsf_req); goto out; } + zfcp_hba_dbf_event_fsf_unsol("read", adapter, status_buffer); + switch (status_buffer->status_type) { case FSF_STATUS_READ_PORT_CLOSED: - debug_text_event(adapter->erp_dbf, 3, "unsol_pclosed:"); - debug_event(adapter->erp_dbf, 3, - &status_buffer->d_id, sizeof (u32)); zfcp_fsf_status_read_port_closed(fsf_req); break; case FSF_STATUS_READ_INCOMING_ELS: - debug_text_event(adapter->erp_dbf, 3, "unsol_els:"); zfcp_fsf_incoming_els(fsf_req); break; case FSF_STATUS_READ_SENSE_DATA_AVAIL: - debug_text_event(adapter->erp_dbf, 3, "unsol_sense:"); ZFCP_LOG_INFO("unsolicited sense data received (adapter %s)\n", zfcp_get_busid_by_adapter(adapter)); - ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_NORMAL, (char *) status_buffer, - sizeof(struct fsf_status_read_buffer)); break; case FSF_STATUS_READ_BIT_ERROR_THRESHOLD: - debug_text_event(adapter->erp_dbf, 3, "unsol_bit_err:"); ZFCP_LOG_NORMAL("Bit error threshold data received:\n"); ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_NORMAL, (char *) status_buffer, @@ -957,17 +915,32 @@ zfcp_fsf_status_read_handler(struct zfcp_fsf_req *fsf_req) break; case FSF_STATUS_READ_LINK_DOWN: - debug_text_event(adapter->erp_dbf, 0, "unsol_link_down:"); - ZFCP_LOG_INFO("Local link to adapter %s is down\n", + switch (status_buffer->status_subtype) { + case FSF_STATUS_READ_SUB_NO_PHYSICAL_LINK: + ZFCP_LOG_INFO("Physical link to adapter %s is down\n", + zfcp_get_busid_by_adapter(adapter)); + break; + case FSF_STATUS_READ_SUB_FDISC_FAILED: + ZFCP_LOG_INFO("Local link to adapter %s is down " + "due to failed FDISC login\n", zfcp_get_busid_by_adapter(adapter)); - atomic_set_mask(ZFCP_STATUS_ADAPTER_LINK_UNPLUGGED, - &adapter->status); - zfcp_erp_adapter_failed(adapter); + break; + case FSF_STATUS_READ_SUB_FIRMWARE_UPDATE: + ZFCP_LOG_INFO("Local link to adapter %s is down " + "due to firmware update on adapter\n", + zfcp_get_busid_by_adapter(adapter)); + break; + default: + ZFCP_LOG_INFO("Local link to adapter %s is down " + "due to unknown reason\n", + zfcp_get_busid_by_adapter(adapter)); + }; + zfcp_fsf_link_down_info_eval(adapter, + (struct fsf_link_down_info *) &status_buffer->payload); break; case FSF_STATUS_READ_LINK_UP: - debug_text_event(adapter->erp_dbf, 2, "unsol_link_up:"); - ZFCP_LOG_INFO("Local link to adapter %s was replugged. " + ZFCP_LOG_NORMAL("Local link to adapter %s was replugged. " "Restarting operations on this adapter\n", zfcp_get_busid_by_adapter(adapter)); /* All ports should be marked as ready to run again */ @@ -980,35 +953,40 @@ zfcp_fsf_status_read_handler(struct zfcp_fsf_req *fsf_req) break; case FSF_STATUS_READ_CFDC_UPDATED: - debug_text_event(adapter->erp_dbf, 2, "unsol_cfdc_update:"); - ZFCP_LOG_INFO("CFDC has been updated on the adapter %s\n", + ZFCP_LOG_NORMAL("CFDC has been updated on the adapter %s\n", zfcp_get_busid_by_adapter(adapter)); zfcp_erp_adapter_access_changed(adapter); break; case FSF_STATUS_READ_CFDC_HARDENED: - debug_text_event(adapter->erp_dbf, 2, "unsol_cfdc_harden:"); switch (status_buffer->status_subtype) { case FSF_STATUS_READ_SUB_CFDC_HARDENED_ON_SE: - ZFCP_LOG_INFO("CFDC of adapter %s saved on SE\n", + ZFCP_LOG_NORMAL("CFDC of adapter %s saved on SE\n", zfcp_get_busid_by_adapter(adapter)); break; case FSF_STATUS_READ_SUB_CFDC_HARDENED_ON_SE2: - ZFCP_LOG_INFO("CFDC of adapter %s has been copied " + ZFCP_LOG_NORMAL("CFDC of adapter %s has been copied " "to the secondary SE\n", zfcp_get_busid_by_adapter(adapter)); break; default: - ZFCP_LOG_INFO("CFDC of adapter %s has been hardened\n", + ZFCP_LOG_NORMAL("CFDC of adapter %s has been hardened\n", zfcp_get_busid_by_adapter(adapter)); } break; + case FSF_STATUS_READ_FEATURE_UPDATE_ALERT: + debug_text_event(adapter->erp_dbf, 2, "unsol_features:"); + ZFCP_LOG_INFO("List of supported features on adapter %s has " + "been changed from 0x%08X to 0x%08X\n", + zfcp_get_busid_by_adapter(adapter), + *(u32*) (status_buffer->payload + 4), + *(u32*) (status_buffer->payload)); + adapter->adapter_features = *(u32*) status_buffer->payload; + break; + default: - debug_text_event(adapter->erp_dbf, 0, "unsol_unknown:"); - debug_exception(adapter->erp_dbf, 0, - &status_buffer->status_type, sizeof (u32)); - ZFCP_LOG_NORMAL("bug: An unsolicited status packet of unknown " + ZFCP_LOG_NORMAL("warning: An unsolicited status packet of unknown " "type was received (debug info 0x%x)\n", status_buffer->status_type); ZFCP_LOG_DEBUG("Dump of status_read_buffer %p:\n", @@ -1093,7 +1071,7 @@ zfcp_fsf_abort_fcp_command(unsigned long old_req_id, sbale[0].flags |= SBAL_FLAGS0_TYPE_READ; sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY; - fsf_req->data.abort_fcp_command.unit = unit; + fsf_req->data = (unsigned long) unit; /* set handles of unit and its parent port in QTCB */ fsf_req->qtcb->header.lun_handle = unit->handle; @@ -1139,7 +1117,7 @@ static int zfcp_fsf_abort_fcp_command_handler(struct zfcp_fsf_req *new_fsf_req) { int retval = -EINVAL; - struct zfcp_unit *unit = new_fsf_req->data.abort_fcp_command.unit; + struct zfcp_unit *unit; unsigned char status_qual = new_fsf_req->qtcb->header.fsf_status_qual.word[0]; @@ -1150,6 +1128,8 @@ zfcp_fsf_abort_fcp_command_handler(struct zfcp_fsf_req *new_fsf_req) goto skip_fsfstatus; } + unit = (struct zfcp_unit *) new_fsf_req->data; + /* evaluate FSF status in QTCB */ switch (new_fsf_req->qtcb->header.fsf_status) { @@ -1364,7 +1344,7 @@ zfcp_fsf_send_ct(struct zfcp_send_ct *ct, mempool_t *pool, sbale[3].addr = zfcp_sg_to_address(&ct->resp[0]); sbale[3].length = ct->resp[0].length; sbale[3].flags |= SBAL_FLAGS_LAST_ENTRY; - } else if (adapter->supported_features & + } else if (adapter->adapter_features & FSF_FEATURE_ELS_CT_CHAINED_SBALS) { /* try to use chained SBALs */ bytes = zfcp_qdio_sbals_from_sg(fsf_req, @@ -1414,7 +1394,9 @@ zfcp_fsf_send_ct(struct zfcp_send_ct *ct, mempool_t *pool, fsf_req->qtcb->header.port_handle = port->handle; fsf_req->qtcb->bottom.support.service_class = adapter->fc_service_class; fsf_req->qtcb->bottom.support.timeout = ct->timeout; - fsf_req->data.send_ct = ct; + fsf_req->data = (unsigned long) ct; + + zfcp_san_dbf_event_ct_request(fsf_req); /* start QDIO request for this FSF request */ ret = zfcp_fsf_req_send(fsf_req, ct->timer); @@ -1445,10 +1427,10 @@ zfcp_fsf_send_ct(struct zfcp_send_ct *ct, mempool_t *pool, * zfcp_fsf_send_ct_handler - handler for Generic Service requests * @fsf_req: pointer to struct zfcp_fsf_req * - * Data specific for the Generic Service request is passed by - * fsf_req->data.send_ct - * Usually a specific handler for the request is called via - * fsf_req->data.send_ct->handler at end of this function. + * Data specific for the Generic Service request is passed using + * fsf_req->data. There we find the pointer to struct zfcp_send_ct. + * Usually a specific handler for the CT request is called which is + * found in this structure. */ static int zfcp_fsf_send_ct_handler(struct zfcp_fsf_req *fsf_req) @@ -1462,7 +1444,7 @@ zfcp_fsf_send_ct_handler(struct zfcp_fsf_req *fsf_req) u16 subtable, rule, counter; adapter = fsf_req->adapter; - send_ct = fsf_req->data.send_ct; + send_ct = (struct zfcp_send_ct *) fsf_req->data; port = send_ct->port; header = &fsf_req->qtcb->header; bottom = &fsf_req->qtcb->bottom.support; @@ -1474,6 +1456,7 @@ zfcp_fsf_send_ct_handler(struct zfcp_fsf_req *fsf_req) switch (header->fsf_status) { case FSF_GOOD: + zfcp_san_dbf_event_ct_response(fsf_req); retval = 0; break; @@ -1634,7 +1617,7 @@ zfcp_fsf_send_els(struct zfcp_send_els *els) { volatile struct qdio_buffer_element *sbale; struct zfcp_fsf_req *fsf_req; - fc_id_t d_id; + u32 d_id; struct zfcp_adapter *adapter; unsigned long lock_flags; int bytes; @@ -1664,7 +1647,7 @@ zfcp_fsf_send_els(struct zfcp_send_els *els) sbale[3].addr = zfcp_sg_to_address(&els->resp[0]); sbale[3].length = els->resp[0].length; sbale[3].flags |= SBAL_FLAGS_LAST_ENTRY; - } else if (adapter->supported_features & + } else if (adapter->adapter_features & FSF_FEATURE_ELS_CT_CHAINED_SBALS) { /* try to use chained SBALs */ bytes = zfcp_qdio_sbals_from_sg(fsf_req, @@ -1714,10 +1697,12 @@ zfcp_fsf_send_els(struct zfcp_send_els *els) fsf_req->qtcb->bottom.support.d_id = d_id; fsf_req->qtcb->bottom.support.service_class = adapter->fc_service_class; fsf_req->qtcb->bottom.support.timeout = ZFCP_ELS_TIMEOUT; - fsf_req->data.send_els = els; + fsf_req->data = (unsigned long) els; sbale = zfcp_qdio_sbale_req(fsf_req, fsf_req->sbal_curr, 0); + zfcp_san_dbf_event_els_request(fsf_req); + /* start QDIO request for this FSF request */ ret = zfcp_fsf_req_send(fsf_req, els->timer); if (ret) { @@ -1746,23 +1731,23 @@ zfcp_fsf_send_els(struct zfcp_send_els *els) * zfcp_fsf_send_els_handler - handler for ELS commands * @fsf_req: pointer to struct zfcp_fsf_req * - * Data specific for the ELS command is passed by - * fsf_req->data.send_els - * Usually a specific handler for the command is called via - * fsf_req->data.send_els->handler at end of this function. + * Data specific for the ELS command is passed using + * fsf_req->data. There we find the pointer to struct zfcp_send_els. + * Usually a specific handler for the ELS command is called which is + * found in this structure. */ static int zfcp_fsf_send_els_handler(struct zfcp_fsf_req *fsf_req) { struct zfcp_adapter *adapter; struct zfcp_port *port; - fc_id_t d_id; + u32 d_id; struct fsf_qtcb_header *header; struct fsf_qtcb_bottom_support *bottom; struct zfcp_send_els *send_els; int retval = -EINVAL; u16 subtable, rule, counter; - send_els = fsf_req->data.send_els; + send_els = (struct zfcp_send_els *) fsf_req->data; adapter = send_els->adapter; port = send_els->port; d_id = send_els->d_id; @@ -1775,6 +1760,7 @@ static int zfcp_fsf_send_els_handler(struct zfcp_fsf_req *fsf_req) switch (header->fsf_status) { case FSF_GOOD: + zfcp_san_dbf_event_els_response(fsf_req); retval = 0; break; @@ -1954,7 +1940,9 @@ zfcp_fsf_exchange_config_data(struct zfcp_erp_action *erp_action) erp_action->fsf_req->erp_action = erp_action; erp_action->fsf_req->qtcb->bottom.config.feature_selection = - (FSF_FEATURE_CFDC | FSF_FEATURE_LUN_SHARING); + FSF_FEATURE_CFDC | + FSF_FEATURE_LUN_SHARING | + FSF_FEATURE_UPDATE_ALERT; /* start QDIO request for this FSF request */ retval = zfcp_fsf_req_send(erp_action->fsf_req, &erp_action->timer); @@ -1990,29 +1978,36 @@ zfcp_fsf_exchange_config_evaluate(struct zfcp_fsf_req *fsf_req, int xchg_ok) { struct fsf_qtcb_bottom_config *bottom; struct zfcp_adapter *adapter = fsf_req->adapter; + struct Scsi_Host *shost = adapter->scsi_host; bottom = &fsf_req->qtcb->bottom.config; ZFCP_LOG_DEBUG("low/high QTCB version 0x%x/0x%x of FSF\n", bottom->low_qtcb_version, bottom->high_qtcb_version); adapter->fsf_lic_version = bottom->lic_version; - adapter->supported_features = bottom->supported_features; + adapter->adapter_features = bottom->adapter_features; + adapter->connection_features = bottom->connection_features; adapter->peer_wwpn = 0; adapter->peer_wwnn = 0; adapter->peer_d_id = 0; if (xchg_ok) { - adapter->wwnn = bottom->nport_serv_param.wwnn; - adapter->wwpn = bottom->nport_serv_param.wwpn; - adapter->s_id = bottom->s_id & ZFCP_DID_MASK; + fc_host_node_name(shost) = bottom->nport_serv_param.wwnn; + fc_host_port_name(shost) = bottom->nport_serv_param.wwpn; + fc_host_port_id(shost) = bottom->s_id & ZFCP_DID_MASK; + fc_host_speed(shost) = bottom->fc_link_speed; + fc_host_supported_classes(shost) = FC_COS_CLASS2 | FC_COS_CLASS3; adapter->fc_topology = bottom->fc_topology; - adapter->fc_link_speed = bottom->fc_link_speed; adapter->hydra_version = bottom->adapter_type; + if (adapter->physical_wwpn == 0) + adapter->physical_wwpn = fc_host_port_name(shost); + if (adapter->physical_s_id == 0) + adapter->physical_s_id = fc_host_port_id(shost); } else { - adapter->wwnn = 0; - adapter->wwpn = 0; - adapter->s_id = 0; + fc_host_node_name(shost) = 0; + fc_host_port_name(shost) = 0; + fc_host_port_id(shost) = 0; + fc_host_speed(shost) = FC_PORTSPEED_UNKNOWN; adapter->fc_topology = 0; - adapter->fc_link_speed = 0; adapter->hydra_version = 0; } @@ -2022,26 +2017,28 @@ zfcp_fsf_exchange_config_evaluate(struct zfcp_fsf_req *fsf_req, int xchg_ok) adapter->peer_wwnn = bottom->plogi_payload.wwnn; } - if(adapter->supported_features & FSF_FEATURE_HBAAPI_MANAGEMENT){ + if (adapter->adapter_features & FSF_FEATURE_HBAAPI_MANAGEMENT) { adapter->hardware_version = bottom->hardware_version; - memcpy(adapter->serial_number, bottom->serial_number, 17); - EBCASC(adapter->serial_number, sizeof(adapter->serial_number)); + memcpy(fc_host_serial_number(shost), bottom->serial_number, + min(FC_SERIAL_NUMBER_SIZE, 17)); + EBCASC(fc_host_serial_number(shost), + min(FC_SERIAL_NUMBER_SIZE, 17)); } ZFCP_LOG_NORMAL("The adapter %s reported the following characteristics:\n" - "WWNN 0x%016Lx, " - "WWPN 0x%016Lx, " - "S_ID 0x%08x,\n" - "adapter version 0x%x, " - "LIC version 0x%x, " - "FC link speed %d Gb/s\n", - zfcp_get_busid_by_adapter(adapter), - adapter->wwnn, - adapter->wwpn, - (unsigned int) adapter->s_id, - adapter->hydra_version, - adapter->fsf_lic_version, - adapter->fc_link_speed); + "WWNN 0x%016Lx, " + "WWPN 0x%016Lx, " + "S_ID 0x%08x,\n" + "adapter version 0x%x, " + "LIC version 0x%x, " + "FC link speed %d Gb/s\n", + zfcp_get_busid_by_adapter(adapter), + (wwn_t) fc_host_node_name(shost), + (wwn_t) fc_host_port_name(shost), + fc_host_port_id(shost), + adapter->hydra_version, + adapter->fsf_lic_version, + fc_host_speed(shost)); if (ZFCP_QTCB_VERSION < bottom->low_qtcb_version) { ZFCP_LOG_NORMAL("error: the adapter %s " "only supports newer control block " @@ -2062,7 +2059,6 @@ zfcp_fsf_exchange_config_evaluate(struct zfcp_fsf_req *fsf_req, int xchg_ok) zfcp_erp_adapter_shutdown(adapter, 0); return -EIO; } - zfcp_set_fc_host_attrs(adapter); return 0; } @@ -2078,11 +2074,12 @@ zfcp_fsf_exchange_config_data_handler(struct zfcp_fsf_req *fsf_req) { struct fsf_qtcb_bottom_config *bottom; struct zfcp_adapter *adapter = fsf_req->adapter; + struct fsf_qtcb *qtcb = fsf_req->qtcb; if (fsf_req->status & ZFCP_STATUS_FSFREQ_ERROR) return -EIO; - switch (fsf_req->qtcb->header.fsf_status) { + switch (qtcb->header.fsf_status) { case FSF_GOOD: if (zfcp_fsf_exchange_config_evaluate(fsf_req, 1)) @@ -2112,7 +2109,7 @@ zfcp_fsf_exchange_config_data_handler(struct zfcp_fsf_req *fsf_req) zfcp_erp_adapter_shutdown(adapter, 0); return -EIO; case FSF_TOPO_FABRIC: - ZFCP_LOG_INFO("Switched fabric fibrechannel " + ZFCP_LOG_NORMAL("Switched fabric fibrechannel " "network detected at adapter %s.\n", zfcp_get_busid_by_adapter(adapter)); break; @@ -2130,7 +2127,7 @@ zfcp_fsf_exchange_config_data_handler(struct zfcp_fsf_req *fsf_req) zfcp_erp_adapter_shutdown(adapter, 0); return -EIO; } - bottom = &fsf_req->qtcb->bottom.config; + bottom = &qtcb->bottom.config; if (bottom->max_qtcb_size < sizeof(struct fsf_qtcb)) { ZFCP_LOG_NORMAL("bug: Maximum QTCB size (%d bytes) " "allowed by the adapter %s " @@ -2155,12 +2152,10 @@ zfcp_fsf_exchange_config_data_handler(struct zfcp_fsf_req *fsf_req) if (zfcp_fsf_exchange_config_evaluate(fsf_req, 0)) return -EIO; - ZFCP_LOG_INFO("Local link to adapter %s is down\n", - zfcp_get_busid_by_adapter(adapter)); - atomic_set_mask(ZFCP_STATUS_ADAPTER_XCONFIG_OK | - ZFCP_STATUS_ADAPTER_LINK_UNPLUGGED, - &adapter->status); - zfcp_erp_adapter_failed(adapter); + atomic_set_mask(ZFCP_STATUS_ADAPTER_XCONFIG_OK, &adapter->status); + + zfcp_fsf_link_down_info_eval(adapter, + &qtcb->header.fsf_status_qual.link_down_info); break; default: debug_text_event(fsf_req->adapter->erp_dbf, 0, "fsf-stat-ng"); @@ -2174,11 +2169,13 @@ zfcp_fsf_exchange_config_data_handler(struct zfcp_fsf_req *fsf_req) /** * zfcp_fsf_exchange_port_data - request information about local port + * @erp_action: ERP action for the adapter for which port data is requested * @adapter: for which port data is requested * @data: response to exchange port data request */ int -zfcp_fsf_exchange_port_data(struct zfcp_adapter *adapter, +zfcp_fsf_exchange_port_data(struct zfcp_erp_action *erp_action, + struct zfcp_adapter *adapter, struct fsf_qtcb_bottom_port *data) { volatile struct qdio_buffer_element *sbale; @@ -2187,7 +2184,7 @@ zfcp_fsf_exchange_port_data(struct zfcp_adapter *adapter, struct zfcp_fsf_req *fsf_req; struct timer_list *timer; - if(!(adapter->supported_features & FSF_FEATURE_HBAAPI_MANAGEMENT)){ + if (!(adapter->adapter_features & FSF_FEATURE_HBAAPI_MANAGEMENT)) { ZFCP_LOG_INFO("error: exchange port data " "command not supported by adapter %s\n", zfcp_get_busid_by_adapter(adapter)); @@ -2211,12 +2208,18 @@ zfcp_fsf_exchange_port_data(struct zfcp_adapter *adapter, goto out; } + if (erp_action) { + erp_action->fsf_req = fsf_req; + fsf_req->erp_action = erp_action; + } + + if (data) + fsf_req->data = (unsigned long) data; + sbale = zfcp_qdio_sbale_req(fsf_req, fsf_req->sbal_curr, 0); sbale[0].flags |= SBAL_FLAGS0_TYPE_READ; sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY; - fsf_req->data.port_data = data; - init_timer(timer); timer->function = zfcp_fsf_request_timeout_handler; timer->data = (unsigned long) adapter; @@ -2228,6 +2231,8 @@ zfcp_fsf_exchange_port_data(struct zfcp_adapter *adapter, "command on the adapter %s\n", zfcp_get_busid_by_adapter(adapter)); zfcp_fsf_req_free(fsf_req); + if (erp_action) + erp_action->fsf_req = NULL; write_unlock_irqrestore(&adapter->request_queue.queue_lock, lock_flags); goto out; @@ -2256,21 +2261,42 @@ zfcp_fsf_exchange_port_data(struct zfcp_adapter *adapter, static void zfcp_fsf_exchange_port_data_handler(struct zfcp_fsf_req *fsf_req) { - struct fsf_qtcb_bottom_port *bottom; - struct fsf_qtcb_bottom_port *data = fsf_req->data.port_data; + struct zfcp_adapter *adapter = fsf_req->adapter; + struct Scsi_Host *shost = adapter->scsi_host; + struct fsf_qtcb *qtcb = fsf_req->qtcb; + struct fsf_qtcb_bottom_port *bottom, *data; if (fsf_req->status & ZFCP_STATUS_FSFREQ_ERROR) return; - switch (fsf_req->qtcb->header.fsf_status) { + switch (qtcb->header.fsf_status) { case FSF_GOOD: - bottom = &fsf_req->qtcb->bottom.port; - memcpy(data, bottom, sizeof(*data)); + atomic_set_mask(ZFCP_STATUS_ADAPTER_XPORT_OK, &adapter->status); + + bottom = &qtcb->bottom.port; + data = (struct fsf_qtcb_bottom_port*) fsf_req->data; + if (data) + memcpy(data, bottom, sizeof(struct fsf_qtcb_bottom_port)); + if (adapter->connection_features & FSF_FEATURE_NPIV_MODE) { + adapter->physical_wwpn = bottom->wwpn; + adapter->physical_s_id = bottom->fc_port_id; + } else { + adapter->physical_wwpn = fc_host_port_name(shost); + adapter->physical_s_id = fc_host_port_id(shost); + } + fc_host_maxframe_size(shost) = bottom->maximum_frame_size; + break; + + case FSF_EXCHANGE_CONFIG_DATA_INCOMPLETE: + atomic_set_mask(ZFCP_STATUS_ADAPTER_XPORT_OK, &adapter->status); + + zfcp_fsf_link_down_info_eval(adapter, + &qtcb->header.fsf_status_qual.link_down_info); break; default: - debug_text_event(fsf_req->adapter->erp_dbf, 0, "xchg-port-ng"); - debug_event(fsf_req->adapter->erp_dbf, 0, + debug_text_event(adapter->erp_dbf, 0, "xchg-port-ng"); + debug_event(adapter->erp_dbf, 0, &fsf_req->qtcb->header.fsf_status, sizeof(u32)); } } @@ -2312,7 +2338,7 @@ zfcp_fsf_open_port(struct zfcp_erp_action *erp_action) erp_action->fsf_req->qtcb->bottom.support.d_id = erp_action->port->d_id; atomic_set_mask(ZFCP_STATUS_COMMON_OPENING, &erp_action->port->status); - erp_action->fsf_req->data.open_port.port = erp_action->port; + erp_action->fsf_req->data = (unsigned long) erp_action->port; erp_action->fsf_req->erp_action = erp_action; /* start QDIO request for this FSF request */ @@ -2353,7 +2379,7 @@ zfcp_fsf_open_port_handler(struct zfcp_fsf_req *fsf_req) struct fsf_qtcb_header *header; u16 subtable, rule, counter; - port = fsf_req->data.open_port.port; + port = (struct zfcp_port *) fsf_req->data; header = &fsf_req->qtcb->header; if (fsf_req->status & ZFCP_STATUS_FSFREQ_ERROR) { @@ -2566,7 +2592,7 @@ zfcp_fsf_close_port(struct zfcp_erp_action *erp_action) sbale[1].flags |= SBAL_FLAGS_LAST_ENTRY; atomic_set_mask(ZFCP_STATUS_COMMON_CLOSING, &erp_action->port->status); - erp_action->fsf_req->data.close_port.port = erp_action->port; + erp_action->fsf_req->data = (unsigned long) erp_action->port; erp_action->fsf_req->erp_action = erp_action; erp_action->fsf_req->qtcb->header.port_handle = erp_action->port->handle; @@ -2606,7 +2632,7 @@ zfcp_fsf_close_port_handler(struct zfcp_fsf_req *fsf_req) int retval = -EINVAL; struct zfcp_port *port; - port = fsf_req->data.close_port.port; + port = (struct zfcp_port *) fsf_req->data; if (fsf_req->status & ZFCP_STATUS_FSFREQ_ERROR) { /* don't change port status in our bookkeeping */ @@ -2703,8 +2729,8 @@ zfcp_fsf_close_physical_port(struct zfcp_erp_action *erp_action) atomic_set_mask(ZFCP_STATUS_PORT_PHYS_CLOSING, &erp_action->port->status); /* save a pointer to this port */ - erp_action->fsf_req->data.close_physical_port.port = erp_action->port; - /* port to be closeed */ + erp_action->fsf_req->data = (unsigned long) erp_action->port; + /* port to be closed */ erp_action->fsf_req->qtcb->header.port_handle = erp_action->port->handle; erp_action->fsf_req->erp_action = erp_action; @@ -2747,7 +2773,7 @@ zfcp_fsf_close_physical_port_handler(struct zfcp_fsf_req *fsf_req) struct fsf_qtcb_header *header; u16 subtable, rule, counter; - port = fsf_req->data.close_physical_port.port; + port = (struct zfcp_port *) fsf_req->data; header = &fsf_req->qtcb->header; if (fsf_req->status & ZFCP_STATUS_FSFREQ_ERROR) { @@ -2908,10 +2934,11 @@ zfcp_fsf_open_unit(struct zfcp_erp_action *erp_action) erp_action->port->handle; erp_action->fsf_req->qtcb->bottom.support.fcp_lun = erp_action->unit->fcp_lun; + if (!(erp_action->adapter->connection_features & FSF_FEATURE_NPIV_MODE)) erp_action->fsf_req->qtcb->bottom.support.option = FSF_OPEN_LUN_SUPPRESS_BOXING; atomic_set_mask(ZFCP_STATUS_COMMON_OPENING, &erp_action->unit->status); - erp_action->fsf_req->data.open_unit.unit = erp_action->unit; + erp_action->fsf_req->data = (unsigned long) erp_action->unit; erp_action->fsf_req->erp_action = erp_action; /* start QDIO request for this FSF request */ @@ -2955,9 +2982,9 @@ zfcp_fsf_open_unit_handler(struct zfcp_fsf_req *fsf_req) struct fsf_qtcb_bottom_support *bottom; struct fsf_queue_designator *queue_designator; u16 subtable, rule, counter; - u32 allowed, exclusive, readwrite; + int exclusive, readwrite; - unit = fsf_req->data.open_unit.unit; + unit = (struct zfcp_unit *) fsf_req->data; if (fsf_req->status & ZFCP_STATUS_FSFREQ_ERROR) { /* don't change unit status in our bookkeeping */ @@ -2969,10 +2996,6 @@ zfcp_fsf_open_unit_handler(struct zfcp_fsf_req *fsf_req) bottom = &fsf_req->qtcb->bottom.support; queue_designator = &header->fsf_status_qual.fsf_queue_designator; - allowed = bottom->lun_access_info & FSF_UNIT_ACCESS_OPEN_LUN_ALLOWED; - exclusive = bottom->lun_access_info & FSF_UNIT_ACCESS_EXCLUSIVE; - readwrite = bottom->lun_access_info & FSF_UNIT_ACCESS_OUTBOUND_TRANSFER; - atomic_clear_mask(ZFCP_STATUS_COMMON_ACCESS_DENIED | ZFCP_STATUS_UNIT_SHARED | ZFCP_STATUS_UNIT_READONLY, @@ -3146,10 +3169,15 @@ zfcp_fsf_open_unit_handler(struct zfcp_fsf_req *fsf_req) unit->handle); /* mark unit as open */ atomic_set_mask(ZFCP_STATUS_COMMON_OPEN, &unit->status); - atomic_clear_mask(ZFCP_STATUS_COMMON_ACCESS_DENIED | - ZFCP_STATUS_COMMON_ACCESS_BOXED, - &unit->status); - if (adapter->supported_features & FSF_FEATURE_LUN_SHARING){ + + if (!(adapter->connection_features & FSF_FEATURE_NPIV_MODE) && + (adapter->adapter_features & FSF_FEATURE_LUN_SHARING) && + (adapter->ccw_device->id.dev_model != ZFCP_DEVICE_MODEL_PRIV)) { + exclusive = (bottom->lun_access_info & + FSF_UNIT_ACCESS_EXCLUSIVE); + readwrite = (bottom->lun_access_info & + FSF_UNIT_ACCESS_OUTBOUND_TRANSFER); + if (!exclusive) atomic_set_mask(ZFCP_STATUS_UNIT_SHARED, &unit->status); @@ -3242,7 +3270,7 @@ zfcp_fsf_close_unit(struct zfcp_erp_action *erp_action) erp_action->port->handle; erp_action->fsf_req->qtcb->header.lun_handle = erp_action->unit->handle; atomic_set_mask(ZFCP_STATUS_COMMON_CLOSING, &erp_action->unit->status); - erp_action->fsf_req->data.close_unit.unit = erp_action->unit; + erp_action->fsf_req->data = (unsigned long) erp_action->unit; erp_action->fsf_req->erp_action = erp_action; /* start QDIO request for this FSF request */ @@ -3281,7 +3309,7 @@ zfcp_fsf_close_unit_handler(struct zfcp_fsf_req *fsf_req) int retval = -EINVAL; struct zfcp_unit *unit; - unit = fsf_req->data.close_unit.unit; /* restore unit */ + unit = (struct zfcp_unit *) fsf_req->data; if (fsf_req->status & ZFCP_STATUS_FSFREQ_ERROR) { /* don't change unit status in our bookkeeping */ @@ -3305,9 +3333,6 @@ zfcp_fsf_close_unit_handler(struct zfcp_fsf_req *fsf_req) debug_text_event(fsf_req->adapter->erp_dbf, 1, "fsf_s_phand_nv"); zfcp_erp_adapter_reopen(unit->port->adapter, 0); - zfcp_cmd_dbf_event_fsf("porthinv", fsf_req, - &fsf_req->qtcb->header.fsf_status_qual, - sizeof (union fsf_status_qual)); fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; break; @@ -3326,9 +3351,6 @@ zfcp_fsf_close_unit_handler(struct zfcp_fsf_req *fsf_req) debug_text_event(fsf_req->adapter->erp_dbf, 1, "fsf_s_lhand_nv"); zfcp_erp_port_reopen(unit->port, 0); - zfcp_cmd_dbf_event_fsf("lunhinv", fsf_req, - &fsf_req->qtcb->header.fsf_status_qual, - sizeof (union fsf_status_qual)); fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; break; @@ -3436,21 +3458,14 @@ zfcp_fsf_send_fcp_command_task(struct zfcp_adapter *adapter, goto failed_req_create; } - /* - * associate FSF request with SCSI request - * (need this for look up on abort) - */ - fsf_req->data.send_fcp_command_task.fsf_req = fsf_req; - scsi_cmnd->host_scribble = (char *) &(fsf_req->data); + zfcp_unit_get(unit); + fsf_req->unit = unit; - /* - * associate SCSI command with FSF request - * (need this for look up on normal command completion) - */ - fsf_req->data.send_fcp_command_task.scsi_cmnd = scsi_cmnd; - fsf_req->data.send_fcp_command_task.start_jiffies = jiffies; - fsf_req->data.send_fcp_command_task.unit = unit; - ZFCP_LOG_DEBUG("unit=%p, fcp_lun=0x%016Lx\n", unit, unit->fcp_lun); + /* associate FSF request with SCSI request (for look up on abort) */ + scsi_cmnd->host_scribble = (char *) fsf_req; + + /* associate SCSI command with FSF request */ + fsf_req->data = (unsigned long) scsi_cmnd; /* set handles of unit and its parent port in QTCB */ fsf_req->qtcb->header.lun_handle = unit->handle; @@ -3584,6 +3599,7 @@ zfcp_fsf_send_fcp_command_task(struct zfcp_adapter *adapter, send_failed: no_fit: failed_scsi_cmnd: + zfcp_unit_put(unit); zfcp_fsf_req_free(fsf_req); fsf_req = NULL; scsi_cmnd->host_scribble = NULL; @@ -3640,7 +3656,7 @@ zfcp_fsf_send_fcp_command_task_management(struct zfcp_adapter *adapter, * hold a pointer to the unit being target of this * task management request */ - fsf_req->data.send_fcp_command_task_management.unit = unit; + fsf_req->data = (unsigned long) unit; /* set FSF related fields in QTCB */ fsf_req->qtcb->header.lun_handle = unit->handle; @@ -3706,9 +3722,9 @@ zfcp_fsf_send_fcp_command_handler(struct zfcp_fsf_req *fsf_req) header = &fsf_req->qtcb->header; if (unlikely(fsf_req->status & ZFCP_STATUS_FSFREQ_TASK_MANAGEMENT)) - unit = fsf_req->data.send_fcp_command_task_management.unit; + unit = (struct zfcp_unit *) fsf_req->data; else - unit = fsf_req->data.send_fcp_command_task.unit; + unit = fsf_req->unit; if (unlikely(fsf_req->status & ZFCP_STATUS_FSFREQ_ERROR)) { /* go directly to calls of special handlers */ @@ -3765,10 +3781,6 @@ zfcp_fsf_send_fcp_command_handler(struct zfcp_fsf_req *fsf_req) debug_text_event(fsf_req->adapter->erp_dbf, 1, "fsf_s_hand_mis"); zfcp_erp_adapter_reopen(unit->port->adapter, 0); - zfcp_cmd_dbf_event_fsf("handmism", - fsf_req, - &header->fsf_status_qual, - sizeof (union fsf_status_qual)); fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; break; @@ -3789,10 +3801,6 @@ zfcp_fsf_send_fcp_command_handler(struct zfcp_fsf_req *fsf_req) debug_text_exception(fsf_req->adapter->erp_dbf, 0, "fsf_s_class_nsup"); zfcp_erp_adapter_shutdown(unit->port->adapter, 0); - zfcp_cmd_dbf_event_fsf("unsclass", - fsf_req, - &header->fsf_status_qual, - sizeof (union fsf_status_qual)); fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; break; @@ -3811,10 +3819,6 @@ zfcp_fsf_send_fcp_command_handler(struct zfcp_fsf_req *fsf_req) debug_text_event(fsf_req->adapter->erp_dbf, 1, "fsf_s_fcp_lun_nv"); zfcp_erp_port_reopen(unit->port, 0); - zfcp_cmd_dbf_event_fsf("fluninv", - fsf_req, - &header->fsf_status_qual, - sizeof (union fsf_status_qual)); fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; break; @@ -3853,10 +3857,6 @@ zfcp_fsf_send_fcp_command_handler(struct zfcp_fsf_req *fsf_req) debug_text_event(fsf_req->adapter->erp_dbf, 0, "fsf_s_dir_ind_nv"); zfcp_erp_adapter_shutdown(unit->port->adapter, 0); - zfcp_cmd_dbf_event_fsf("dirinv", - fsf_req, - &header->fsf_status_qual, - sizeof (union fsf_status_qual)); fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; break; @@ -3872,10 +3872,6 @@ zfcp_fsf_send_fcp_command_handler(struct zfcp_fsf_req *fsf_req) debug_text_event(fsf_req->adapter->erp_dbf, 0, "fsf_s_cmd_len_nv"); zfcp_erp_adapter_shutdown(unit->port->adapter, 0); - zfcp_cmd_dbf_event_fsf("cleninv", - fsf_req, - &header->fsf_status_qual, - sizeof (union fsf_status_qual)); fsf_req->status |= ZFCP_STATUS_FSFREQ_ERROR; break; @@ -3947,6 +3943,8 @@ zfcp_fsf_send_fcp_command_handler(struct zfcp_fsf_req *fsf_req) zfcp_fsf_send_fcp_command_task_management_handler(fsf_req); } else { retval = zfcp_fsf_send_fcp_command_task_handler(fsf_req); + fsf_req->unit = NULL; + zfcp_unit_put(unit); } return retval; } @@ -3970,10 +3968,10 @@ zfcp_fsf_send_fcp_command_task_handler(struct zfcp_fsf_req *fsf_req) u32 sns_len; char *fcp_rsp_info = zfcp_get_fcp_rsp_info_ptr(fcp_rsp_iu); unsigned long flags; - struct zfcp_unit *unit = fsf_req->data.send_fcp_command_task.unit; + struct zfcp_unit *unit = fsf_req->unit; read_lock_irqsave(&fsf_req->adapter->abort_lock, flags); - scpnt = fsf_req->data.send_fcp_command_task.scsi_cmnd; + scpnt = (struct scsi_cmnd *) fsf_req->data; if (unlikely(!scpnt)) { ZFCP_LOG_DEBUG ("Command with fsf_req %p is not associated to " @@ -4043,7 +4041,6 @@ zfcp_fsf_send_fcp_command_task_handler(struct zfcp_fsf_req *fsf_req) ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_DEBUG, (char *) &fsf_req->qtcb-> bottom.io.fcp_cmnd, FSF_FCP_CMND_SIZE); - zfcp_cmd_dbf_event_fsf("clenmis", fsf_req, NULL, 0); set_host_byte(&scpnt->result, DID_ERROR); goto skip_fsfstatus; case RSP_CODE_FIELD_INVALID: @@ -4062,7 +4059,6 @@ zfcp_fsf_send_fcp_command_task_handler(struct zfcp_fsf_req *fsf_req) (char *) &fsf_req->qtcb-> bottom.io.fcp_cmnd, FSF_FCP_CMND_SIZE); set_host_byte(&scpnt->result, DID_ERROR); - zfcp_cmd_dbf_event_fsf("codeinv", fsf_req, NULL, 0); goto skip_fsfstatus; case RSP_CODE_RO_MISMATCH: /* hardware bug */ @@ -4079,7 +4075,6 @@ zfcp_fsf_send_fcp_command_task_handler(struct zfcp_fsf_req *fsf_req) ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_DEBUG, (char *) &fsf_req->qtcb-> bottom.io.fcp_cmnd, FSF_FCP_CMND_SIZE); - zfcp_cmd_dbf_event_fsf("codemism", fsf_req, NULL, 0); set_host_byte(&scpnt->result, DID_ERROR); goto skip_fsfstatus; default: @@ -4096,7 +4091,6 @@ zfcp_fsf_send_fcp_command_task_handler(struct zfcp_fsf_req *fsf_req) ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_DEBUG, (char *) &fsf_req->qtcb-> bottom.io.fcp_cmnd, FSF_FCP_CMND_SIZE); - zfcp_cmd_dbf_event_fsf("undeffcp", fsf_req, NULL, 0); set_host_byte(&scpnt->result, DID_ERROR); goto skip_fsfstatus; } @@ -4158,19 +4152,17 @@ zfcp_fsf_send_fcp_command_task_handler(struct zfcp_fsf_req *fsf_req) skip_fsfstatus: ZFCP_LOG_DEBUG("scpnt->result =0x%x\n", scpnt->result); - zfcp_cmd_dbf_event_scsi("response", scpnt); + if (scpnt->result != 0) + zfcp_scsi_dbf_event_result("erro", 3, fsf_req->adapter, scpnt); + else if (scpnt->retries > 0) + zfcp_scsi_dbf_event_result("retr", 4, fsf_req->adapter, scpnt); + else + zfcp_scsi_dbf_event_result("norm", 6, fsf_req->adapter, scpnt); /* cleanup pointer (need this especially for abort) */ scpnt->host_scribble = NULL; - /* - * NOTE: - * according to the outcome of a discussion on linux-scsi we - * don't need to grab the io_request_lock here since we use - * the new eh - */ /* always call back */ - (scpnt->scsi_done) (scpnt); /* @@ -4198,8 +4190,7 @@ zfcp_fsf_send_fcp_command_task_management_handler(struct zfcp_fsf_req *fsf_req) struct fcp_rsp_iu *fcp_rsp_iu = (struct fcp_rsp_iu *) &(fsf_req->qtcb->bottom.io.fcp_rsp); char *fcp_rsp_info = zfcp_get_fcp_rsp_info_ptr(fcp_rsp_iu); - struct zfcp_unit *unit = - fsf_req->data.send_fcp_command_task_management.unit; + struct zfcp_unit *unit = (struct zfcp_unit *) fsf_req->data; del_timer(&fsf_req->adapter->scsi_er_timer); if (fsf_req->status & ZFCP_STATUS_FSFREQ_ERROR) { @@ -4276,7 +4267,7 @@ zfcp_fsf_control_file(struct zfcp_adapter *adapter, int direction; int retval = 0; - if (!(adapter->supported_features & FSF_FEATURE_CFDC)) { + if (!(adapter->adapter_features & FSF_FEATURE_CFDC)) { ZFCP_LOG_INFO("cfdc not supported (adapter %s)\n", zfcp_get_busid_by_adapter(adapter)); retval = -EOPNOTSUPP; @@ -4549,52 +4540,6 @@ skip_fsfstatus: return retval; } - -/* - * function: zfcp_fsf_req_wait_and_cleanup - * - * purpose: - * - * FIXME(design): signal seems to be <0 !!! - * returns: 0 - request completed (*status is valid), cleanup succ. - * <0 - request completed (*status is valid), cleanup failed - * >0 - signal which interrupted waiting (*status invalid), - * request not completed, no cleanup - * - * *status is a copy of status of completed fsf_req - */ -int -zfcp_fsf_req_wait_and_cleanup(struct zfcp_fsf_req *fsf_req, - int interruptible, u32 * status) -{ - int retval = 0; - int signal = 0; - - if (interruptible) { - __wait_event_interruptible(fsf_req->completion_wq, - fsf_req->status & - ZFCP_STATUS_FSFREQ_COMPLETED, - signal); - if (signal) { - ZFCP_LOG_DEBUG("Caught signal %i while waiting for the " - "completion of the request at %p\n", - signal, fsf_req); - retval = signal; - goto out; - } - } else { - __wait_event(fsf_req->completion_wq, - fsf_req->status & ZFCP_STATUS_FSFREQ_COMPLETED); - } - - *status = fsf_req->status; - - /* cleanup request */ - zfcp_fsf_req_free(fsf_req); - out: - return retval; -} - static inline int zfcp_fsf_req_sbal_check(unsigned long *flags, struct zfcp_qdio_queue *queue, int needed) @@ -4610,15 +4555,16 @@ zfcp_fsf_req_sbal_check(unsigned long *flags, * set qtcb pointer in fsf_req and initialize QTCB */ static inline void -zfcp_fsf_req_qtcb_init(struct zfcp_fsf_req *fsf_req, u32 fsf_cmd) +zfcp_fsf_req_qtcb_init(struct zfcp_fsf_req *fsf_req) { if (likely(fsf_req->qtcb != NULL)) { + fsf_req->qtcb->prefix.req_seq_no = fsf_req->adapter->fsf_req_seq_no; fsf_req->qtcb->prefix.req_id = (unsigned long)fsf_req; fsf_req->qtcb->prefix.ulp_info = ZFCP_ULP_INFO_VERSION; - fsf_req->qtcb->prefix.qtcb_type = fsf_qtcb_type[fsf_cmd]; + fsf_req->qtcb->prefix.qtcb_type = fsf_qtcb_type[fsf_req->fsf_command]; fsf_req->qtcb->prefix.qtcb_version = ZFCP_QTCB_VERSION; fsf_req->qtcb->header.req_handle = (unsigned long)fsf_req; - fsf_req->qtcb->header.fsf_command = fsf_cmd; + fsf_req->qtcb->header.fsf_command = fsf_req->fsf_command; } } @@ -4686,7 +4632,10 @@ zfcp_fsf_req_create(struct zfcp_adapter *adapter, u32 fsf_cmd, int req_flags, goto failed_fsf_req; } - zfcp_fsf_req_qtcb_init(fsf_req, fsf_cmd); + fsf_req->adapter = adapter; + fsf_req->fsf_command = fsf_cmd; + + zfcp_fsf_req_qtcb_init(fsf_req); /* initialize waitqueue which may be used to wait on this request completion */ @@ -4708,8 +4657,10 @@ zfcp_fsf_req_create(struct zfcp_adapter *adapter, u32 fsf_cmd, int req_flags, goto failed_sbals; } - fsf_req->adapter = adapter; /* pointer to "parent" adapter */ - fsf_req->fsf_command = fsf_cmd; + if (fsf_req->qtcb) { + fsf_req->seq_no = adapter->fsf_req_seq_no; + fsf_req->qtcb->prefix.req_seq_no = adapter->fsf_req_seq_no; + } fsf_req->sbal_number = 1; fsf_req->sbal_first = req_queue->free_index; fsf_req->sbal_curr = req_queue->free_index; @@ -4760,9 +4711,9 @@ zfcp_fsf_req_send(struct zfcp_fsf_req *fsf_req, struct timer_list *timer) struct zfcp_adapter *adapter; struct zfcp_qdio_queue *req_queue; volatile struct qdio_buffer_element *sbale; + int inc_seq_no; int new_distance_from_int; unsigned long flags; - int inc_seq_no = 1; int retval = 0; adapter = fsf_req->adapter; @@ -4776,23 +4727,13 @@ zfcp_fsf_req_send(struct zfcp_fsf_req *fsf_req, struct timer_list *timer) ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_TRACE, (char *) sbale[1].addr, sbale[1].length); - /* set sequence counter in QTCB */ - if (likely(fsf_req->qtcb)) { - fsf_req->qtcb->prefix.req_seq_no = adapter->fsf_req_seq_no; - fsf_req->seq_no = adapter->fsf_req_seq_no; - ZFCP_LOG_TRACE("FSF request %p of adapter %s gets " - "FSF sequence counter value of %i\n", - fsf_req, - zfcp_get_busid_by_adapter(adapter), - fsf_req->qtcb->prefix.req_seq_no); - } else - inc_seq_no = 0; - /* put allocated FSF request at list tail */ spin_lock_irqsave(&adapter->fsf_req_list_lock, flags); list_add_tail(&fsf_req->list, &adapter->fsf_req_list_head); spin_unlock_irqrestore(&adapter->fsf_req_list_lock, flags); + inc_seq_no = (fsf_req->qtcb != NULL); + /* figure out expiration time of timeout and start timeout */ if (unlikely(timer)) { timer->expires += jiffies; @@ -4822,6 +4763,8 @@ zfcp_fsf_req_send(struct zfcp_fsf_req *fsf_req, struct timer_list *timer) req_queue->free_index %= QDIO_MAX_BUFFERS_PER_Q; /* wrap if needed */ new_distance_from_int = zfcp_qdio_determine_pci(req_queue, fsf_req); + fsf_req->issued = get_clock(); + retval = do_QDIO(adapter->ccw_device, QDIO_FLAG_SYNC_OUTPUT, 0, fsf_req->sbal_first, fsf_req->sbal_number, NULL); @@ -4860,15 +4803,11 @@ zfcp_fsf_req_send(struct zfcp_fsf_req *fsf_req, struct timer_list *timer) * routines resulting in missing sequence counter values * otherwise, */ + /* Don't increase for unsolicited status */ - if (likely(inc_seq_no)) { + if (inc_seq_no) adapter->fsf_req_seq_no++; - ZFCP_LOG_TRACE - ("FSF sequence counter value of adapter %s " - "increased to %i\n", - zfcp_get_busid_by_adapter(adapter), - adapter->fsf_req_seq_no); - } + /* count FSF requests pending */ atomic_inc(&adapter->fsf_reqs_active); } diff --git a/drivers/s390/scsi/zfcp_fsf.h b/drivers/s390/scsi/zfcp_fsf.h index 07140df..48719f0 100644 --- a/drivers/s390/scsi/zfcp_fsf.h +++ b/drivers/s390/scsi/zfcp_fsf.h @@ -116,6 +116,7 @@ #define FSF_INVALID_COMMAND_OPTION 0x000000E5 /* #define FSF_ERROR 0x000000FF */ +#define FSF_PROT_STATUS_QUAL_SIZE 16 #define FSF_STATUS_QUALIFIER_SIZE 16 /* FSF status qualifier, recommendations */ @@ -139,9 +140,18 @@ #define FSF_SQ_CFDC_SUBTABLE_LUN 0x0004 /* FSF status qualifier (most significant 4 bytes), local link down */ -#define FSF_PSQ_LINK_NOLIGHT 0x00000004 -#define FSF_PSQ_LINK_WRAPPLUG 0x00000008 -#define FSF_PSQ_LINK_NOFCP 0x00000010 +#define FSF_PSQ_LINK_NO_LIGHT 0x00000004 +#define FSF_PSQ_LINK_WRAP_PLUG 0x00000008 +#define FSF_PSQ_LINK_NO_FCP 0x00000010 +#define FSF_PSQ_LINK_FIRMWARE_UPDATE 0x00000020 +#define FSF_PSQ_LINK_INVALID_WWPN 0x00000100 +#define FSF_PSQ_LINK_NO_NPIV_SUPPORT 0x00000200 +#define FSF_PSQ_LINK_NO_FCP_RESOURCES 0x00000400 +#define FSF_PSQ_LINK_NO_FABRIC_RESOURCES 0x00000800 +#define FSF_PSQ_LINK_FABRIC_LOGIN_UNABLE 0x00001000 +#define FSF_PSQ_LINK_WWPN_ASSIGNMENT_CORRUPTED 0x00002000 +#define FSF_PSQ_LINK_MODE_TABLE_CURRUPTED 0x00004000 +#define FSF_PSQ_LINK_NO_WWPN_ASSIGNMENT 0x00008000 /* payload size in status read buffer */ #define FSF_STATUS_READ_PAYLOAD_SIZE 4032 @@ -154,15 +164,21 @@ #define FSF_STATUS_READ_INCOMING_ELS 0x00000002 #define FSF_STATUS_READ_SENSE_DATA_AVAIL 0x00000003 #define FSF_STATUS_READ_BIT_ERROR_THRESHOLD 0x00000004 -#define FSF_STATUS_READ_LINK_DOWN 0x00000005 /* FIXME: really? */ +#define FSF_STATUS_READ_LINK_DOWN 0x00000005 #define FSF_STATUS_READ_LINK_UP 0x00000006 #define FSF_STATUS_READ_CFDC_UPDATED 0x0000000A #define FSF_STATUS_READ_CFDC_HARDENED 0x0000000B +#define FSF_STATUS_READ_FEATURE_UPDATE_ALERT 0x0000000C /* status subtypes in status read buffer */ #define FSF_STATUS_READ_SUB_CLOSE_PHYS_PORT 0x00000001 #define FSF_STATUS_READ_SUB_ERROR_PORT 0x00000002 +/* status subtypes for link down */ +#define FSF_STATUS_READ_SUB_NO_PHYSICAL_LINK 0x00000000 +#define FSF_STATUS_READ_SUB_FDISC_FAILED 0x00000001 +#define FSF_STATUS_READ_SUB_FIRMWARE_UPDATE 0x00000002 + /* status subtypes for CFDC */ #define FSF_STATUS_READ_SUB_CFDC_HARDENED_ON_SE 0x00000002 #define FSF_STATUS_READ_SUB_CFDC_HARDENED_ON_SE2 0x0000000F @@ -193,11 +209,15 @@ #define FSF_QTCB_LOG_SIZE 1024 /* channel features */ -#define FSF_FEATURE_QTCB_SUPPRESSION 0x00000001 #define FSF_FEATURE_CFDC 0x00000002 #define FSF_FEATURE_LUN_SHARING 0x00000004 #define FSF_FEATURE_HBAAPI_MANAGEMENT 0x00000010 #define FSF_FEATURE_ELS_CT_CHAINED_SBALS 0x00000020 +#define FSF_FEATURE_UPDATE_ALERT 0x00000100 + +/* host connection features */ +#define FSF_FEATURE_NPIV_MODE 0x00000001 +#define FSF_FEATURE_VM_ASSIGNED_WWPN 0x00000002 /* option */ #define FSF_OPEN_LUN_SUPPRESS_BOXING 0x00000001 @@ -305,15 +325,23 @@ struct fsf_qual_sequence_error { u32 res1[3]; } __attribute__ ((packed)); -struct fsf_qual_locallink_error { - u32 code; - u32 res1[3]; +struct fsf_link_down_info { + u32 error_code; + u32 res1; + u8 res2[2]; + u8 primary_status; + u8 ioerr_code; + u8 action_code; + u8 reason_code; + u8 explanation_code; + u8 vendor_specific_code; } __attribute__ ((packed)); union fsf_prot_status_qual { + u64 doubleword[FSF_PROT_STATUS_QUAL_SIZE / sizeof(u64)]; struct fsf_qual_version_error version_error; struct fsf_qual_sequence_error sequence_error; - struct fsf_qual_locallink_error locallink_error; + struct fsf_link_down_info link_down_info; } __attribute__ ((packed)); struct fsf_qtcb_prefix { @@ -331,7 +359,9 @@ union fsf_status_qual { u8 byte[FSF_STATUS_QUALIFIER_SIZE]; u16 halfword[FSF_STATUS_QUALIFIER_SIZE / sizeof (u16)]; u32 word[FSF_STATUS_QUALIFIER_SIZE / sizeof (u32)]; + u64 doubleword[FSF_STATUS_QUALIFIER_SIZE / sizeof(u64)]; struct fsf_queue_designator fsf_queue_designator; + struct fsf_link_down_info link_down_info; } __attribute__ ((packed)); struct fsf_qtcb_header { @@ -406,8 +436,8 @@ struct fsf_qtcb_bottom_config { u32 low_qtcb_version; u32 max_qtcb_size; u32 max_data_transfer_size; - u32 supported_features; - u8 res1[4]; + u32 adapter_features; + u32 connection_features; u32 fc_topology; u32 fc_link_speed; u32 adapter_type; @@ -425,7 +455,7 @@ struct fsf_qtcb_bottom_config { } __attribute__ ((packed)); struct fsf_qtcb_bottom_port { - u8 res1[8]; + u64 wwpn; u32 fc_port_id; u32 port_type; u32 port_state; diff --git a/drivers/s390/scsi/zfcp_qdio.c b/drivers/s390/scsi/zfcp_qdio.c index 24e16ec..d719f66 100644 --- a/drivers/s390/scsi/zfcp_qdio.c +++ b/drivers/s390/scsi/zfcp_qdio.c @@ -54,8 +54,7 @@ static inline int zfcp_qdio_sbals_from_buffer static qdio_handler_t zfcp_qdio_request_handler; static qdio_handler_t zfcp_qdio_response_handler; static int zfcp_qdio_handler_error_check(struct zfcp_adapter *, - unsigned int, - unsigned int, unsigned int); + unsigned int, unsigned int, unsigned int, int, int); #define ZFCP_LOG_AREA ZFCP_LOG_AREA_QDIO @@ -214,22 +213,12 @@ zfcp_qdio_allocate(struct zfcp_adapter *adapter) * */ static inline int -zfcp_qdio_handler_error_check(struct zfcp_adapter *adapter, - unsigned int status, - unsigned int qdio_error, unsigned int siga_error) +zfcp_qdio_handler_error_check(struct zfcp_adapter *adapter, unsigned int status, + unsigned int qdio_error, unsigned int siga_error, + int first_element, int elements_processed) { int retval = 0; - if (ZFCP_LOG_CHECK(ZFCP_LOG_LEVEL_TRACE)) { - if (status & QDIO_STATUS_INBOUND_INT) { - ZFCP_LOG_TRACE("status is" - " QDIO_STATUS_INBOUND_INT \n"); - } - if (status & QDIO_STATUS_OUTBOUND_INT) { - ZFCP_LOG_TRACE("status is" - " QDIO_STATUS_OUTBOUND_INT \n"); - } - } if (unlikely(status & QDIO_STATUS_LOOK_FOR_ERROR)) { retval = -EIO; @@ -237,9 +226,10 @@ zfcp_qdio_handler_error_check(struct zfcp_adapter *adapter, "qdio_error=0x%x, siga_error=0x%x)\n", status, qdio_error, siga_error); - /* Restarting IO on the failed adapter from scratch */ - debug_text_event(adapter->erp_dbf, 1, "qdio_err"); + zfcp_hba_dbf_event_qdio(adapter, status, qdio_error, siga_error, + first_element, elements_processed); /* + * Restarting IO on the failed adapter from scratch. * Since we have been using this adapter, it is save to assume * that it is not failed but recoverable. The card seems to * report link-up events by self-initiated queue shutdown. @@ -282,7 +272,8 @@ zfcp_qdio_request_handler(struct ccw_device *ccw_device, first_element, elements_processed); if (unlikely(zfcp_qdio_handler_error_check(adapter, status, qdio_error, - siga_error))) + siga_error, first_element, + elements_processed))) goto out; /* * we stored address of struct zfcp_adapter data structure @@ -334,7 +325,8 @@ zfcp_qdio_response_handler(struct ccw_device *ccw_device, queue = &adapter->response_queue; if (unlikely(zfcp_qdio_handler_error_check(adapter, status, qdio_error, - siga_error))) + siga_error, first_element, + elements_processed))) goto out; /* diff --git a/drivers/s390/scsi/zfcp_scsi.c b/drivers/s390/scsi/zfcp_scsi.c index 31a7606..3dcd1bf 100644 --- a/drivers/s390/scsi/zfcp_scsi.c +++ b/drivers/s390/scsi/zfcp_scsi.c @@ -44,7 +44,8 @@ static int zfcp_scsi_eh_abort_handler(struct scsi_cmnd *); static int zfcp_scsi_eh_device_reset_handler(struct scsi_cmnd *); static int zfcp_scsi_eh_bus_reset_handler(struct scsi_cmnd *); static int zfcp_scsi_eh_host_reset_handler(struct scsi_cmnd *); -static int zfcp_task_management_function(struct zfcp_unit *, u8); +static int zfcp_task_management_function(struct zfcp_unit *, u8, + struct scsi_cmnd *); static struct zfcp_unit *zfcp_unit_lookup(struct zfcp_adapter *, int, scsi_id_t, scsi_lun_t); @@ -242,7 +243,10 @@ static void zfcp_scsi_command_fail(struct scsi_cmnd *scpnt, int result) { set_host_byte(&scpnt->result, result); - zfcp_cmd_dbf_event_scsi("failing", scpnt); + if ((scpnt->device != NULL) && (scpnt->device->host != NULL)) + zfcp_scsi_dbf_event_result("fail", 4, + (struct zfcp_adapter*) scpnt->device->host->hostdata[0], + scpnt); /* return directly */ scpnt->scsi_done(scpnt); } @@ -414,67 +418,38 @@ zfcp_port_lookup(struct zfcp_adapter *adapter, int channel, scsi_id_t id) return (struct zfcp_port *) NULL; } -/* - * function: zfcp_scsi_eh_abort_handler - * - * purpose: tries to abort the specified (timed out) SCSI command - * - * note: We do not need to care for a SCSI command which completes - * normally but late during this abort routine runs. - * We are allowed to return late commands to the SCSI stack. - * It tracks the state of commands and will handle late commands. - * (Usually, the normal completion of late commands is ignored with - * respect to the running abort operation. Grep for 'done_late' - * in the SCSI stacks sources.) +/** + * zfcp_scsi_eh_abort_handler - abort the specified SCSI command + * @scpnt: pointer to scsi_cmnd to be aborted + * Return: SUCCESS - command has been aborted and cleaned up in internal + * bookkeeping, SCSI stack won't be called for aborted command + * FAILED - otherwise * - * returns: SUCCESS - command has been aborted and cleaned up in internal - * bookkeeping, - * SCSI stack won't be called for aborted command - * FAILED - otherwise + * We do not need to care for a SCSI command which completes normally + * but late during this abort routine runs. We are allowed to return + * late commands to the SCSI stack. It tracks the state of commands and + * will handle late commands. (Usually, the normal completion of late + * commands is ignored with respect to the running abort operation.) */ int -__zfcp_scsi_eh_abort_handler(struct scsi_cmnd *scpnt) +zfcp_scsi_eh_abort_handler(struct scsi_cmnd *scpnt) { + struct Scsi_Host *scsi_host; + struct zfcp_adapter *adapter; + struct zfcp_unit *unit; int retval = SUCCESS; - struct zfcp_fsf_req *new_fsf_req, *old_fsf_req; - struct zfcp_adapter *adapter = (struct zfcp_adapter *) scpnt->device->host->hostdata[0]; - struct zfcp_unit *unit = (struct zfcp_unit *) scpnt->device->hostdata; - struct zfcp_port *port = unit->port; - struct Scsi_Host *scsi_host = scpnt->device->host; - union zfcp_req_data *req_data = NULL; + struct zfcp_fsf_req *new_fsf_req = NULL; + struct zfcp_fsf_req *old_fsf_req; unsigned long flags; - u32 status = 0; - - /* the components of a abort_dbf record (fixed size record) */ - u64 dbf_scsi_cmnd = (unsigned long) scpnt; - char dbf_opcode[ZFCP_ABORT_DBF_LENGTH]; - wwn_t dbf_wwn = port->wwpn; - fcp_lun_t dbf_fcp_lun = unit->fcp_lun; - u64 dbf_retries = scpnt->retries; - u64 dbf_allowed = scpnt->allowed; - u64 dbf_timeout = 0; - u64 dbf_fsf_req = 0; - u64 dbf_fsf_status = 0; - u64 dbf_fsf_qual[2] = { 0, 0 }; - char dbf_result[ZFCP_ABORT_DBF_LENGTH] = "##undef"; - - memset(dbf_opcode, 0, ZFCP_ABORT_DBF_LENGTH); - memcpy(dbf_opcode, - scpnt->cmnd, - min(scpnt->cmd_len, (unsigned char) ZFCP_ABORT_DBF_LENGTH)); + + scsi_host = scpnt->device->host; + adapter = (struct zfcp_adapter *) scsi_host->hostdata[0]; + unit = (struct zfcp_unit *) scpnt->device->hostdata; ZFCP_LOG_INFO("aborting scsi_cmnd=%p on adapter %s\n", scpnt, zfcp_get_busid_by_adapter(adapter)); - spin_unlock_irq(scsi_host->host_lock); - - /* - * Race condition between normal (late) completion and abort has - * to be avoided. - * The entirity of all accesses to scsi_req have to be atomic. - * scsi_req is usually part of the fsf_req and thus we block the - * release of fsf_req as long as we need to access scsi_req. - */ + /* avoid race condition between late normal completion and abort */ write_lock_irqsave(&adapter->abort_lock, flags); /* @@ -484,144 +459,47 @@ __zfcp_scsi_eh_abort_handler(struct scsi_cmnd *scpnt) * this routine returns. (scpnt is parameter passed to this routine * and must not disappear during abort even on late completion.) */ - req_data = (union zfcp_req_data *) scpnt->host_scribble; - /* DEBUG */ - ZFCP_LOG_DEBUG("req_data=%p\n", req_data); - if (!req_data) { - ZFCP_LOG_DEBUG("late command completion overtook abort\n"); - /* - * That's it. - * Do not initiate abort but return SUCCESS. - */ - write_unlock_irqrestore(&adapter->abort_lock, flags); - retval = SUCCESS; - strncpy(dbf_result, "##late1", ZFCP_ABORT_DBF_LENGTH); - goto out; - } - - /* Figure out which fsf_req needs to be aborted. */ - old_fsf_req = req_data->send_fcp_command_task.fsf_req; - - dbf_fsf_req = (unsigned long) old_fsf_req; - dbf_timeout = - (jiffies - req_data->send_fcp_command_task.start_jiffies) / HZ; - - ZFCP_LOG_DEBUG("old_fsf_req=%p\n", old_fsf_req); + old_fsf_req = (struct zfcp_fsf_req *) scpnt->host_scribble; if (!old_fsf_req) { write_unlock_irqrestore(&adapter->abort_lock, flags); - ZFCP_LOG_NORMAL("bug: no old fsf request found\n"); - ZFCP_LOG_NORMAL("req_data:\n"); - ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_NORMAL, - (char *) req_data, sizeof (union zfcp_req_data)); - ZFCP_LOG_NORMAL("scsi_cmnd:\n"); - ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_NORMAL, - (char *) scpnt, sizeof (struct scsi_cmnd)); - retval = FAILED; - strncpy(dbf_result, "##bug:r", ZFCP_ABORT_DBF_LENGTH); + zfcp_scsi_dbf_event_abort("lte1", adapter, scpnt, new_fsf_req); + retval = SUCCESS; goto out; } - old_fsf_req->data.send_fcp_command_task.scsi_cmnd = NULL; - /* mark old request as being aborted */ + old_fsf_req->data = 0; old_fsf_req->status |= ZFCP_STATUS_FSFREQ_ABORTING; - /* - * We have to collect all information (e.g. unit) needed by - * zfcp_fsf_abort_fcp_command before calling that routine - * since that routine is not allowed to access - * fsf_req which it is going to abort. - * This is because of we need to release fsf_req_list_lock - * before calling zfcp_fsf_abort_fcp_command. - * Since this lock will not be held, fsf_req may complete - * late and may be released meanwhile. - */ - ZFCP_LOG_DEBUG("unit 0x%016Lx (%p)\n", unit->fcp_lun, unit); - /* - * We block (call schedule) - * That's why we must release the lock and enable the - * interrupts before. - * On the other hand we do not need the lock anymore since - * all critical accesses to scsi_req are done. - */ + /* don't access old_fsf_req after releasing the abort_lock */ write_unlock_irqrestore(&adapter->abort_lock, flags); /* call FSF routine which does the abort */ new_fsf_req = zfcp_fsf_abort_fcp_command((unsigned long) old_fsf_req, adapter, unit, 0); - ZFCP_LOG_DEBUG("new_fsf_req=%p\n", new_fsf_req); if (!new_fsf_req) { + ZFCP_LOG_INFO("error: initiation of Abort FCP Cmnd failed\n"); retval = FAILED; - ZFCP_LOG_NORMAL("error: initiation of Abort FCP Cmnd " - "failed\n"); - strncpy(dbf_result, "##nores", ZFCP_ABORT_DBF_LENGTH); goto out; } /* wait for completion of abort */ - ZFCP_LOG_DEBUG("waiting for cleanup...\n"); -#if 1 - /* - * FIXME: - * copying zfcp_fsf_req_wait_and_cleanup code is not really nice - */ __wait_event(new_fsf_req->completion_wq, new_fsf_req->status & ZFCP_STATUS_FSFREQ_COMPLETED); - status = new_fsf_req->status; - dbf_fsf_status = new_fsf_req->qtcb->header.fsf_status; - /* - * Ralphs special debug load provides timestamps in the FSF - * status qualifier. This might be specified later if being - * useful for debugging aborts. - */ - dbf_fsf_qual[0] = - *(u64 *) & new_fsf_req->qtcb->header.fsf_status_qual.word[0]; - dbf_fsf_qual[1] = - *(u64 *) & new_fsf_req->qtcb->header.fsf_status_qual.word[2]; - zfcp_fsf_req_free(new_fsf_req); -#else - retval = zfcp_fsf_req_wait_and_cleanup(new_fsf_req, - ZFCP_UNINTERRUPTIBLE, &status); -#endif - ZFCP_LOG_DEBUG("Waiting for cleanup complete, status=0x%x\n", status); + /* status should be valid since signals were not permitted */ - if (status & ZFCP_STATUS_FSFREQ_ABORTSUCCEEDED) { + if (new_fsf_req->status & ZFCP_STATUS_FSFREQ_ABORTSUCCEEDED) { + zfcp_scsi_dbf_event_abort("okay", adapter, scpnt, new_fsf_req); retval = SUCCESS; - strncpy(dbf_result, "##succ", ZFCP_ABORT_DBF_LENGTH); - } else if (status & ZFCP_STATUS_FSFREQ_ABORTNOTNEEDED) { + } else if (new_fsf_req->status & ZFCP_STATUS_FSFREQ_ABORTNOTNEEDED) { + zfcp_scsi_dbf_event_abort("lte2", adapter, scpnt, new_fsf_req); retval = SUCCESS; - strncpy(dbf_result, "##late2", ZFCP_ABORT_DBF_LENGTH); } else { + zfcp_scsi_dbf_event_abort("fail", adapter, scpnt, new_fsf_req); retval = FAILED; - strncpy(dbf_result, "##fail", ZFCP_ABORT_DBF_LENGTH); } - + zfcp_fsf_req_free(new_fsf_req); out: - debug_event(adapter->abort_dbf, 1, &dbf_scsi_cmnd, sizeof (u64)); - debug_event(adapter->abort_dbf, 1, &dbf_opcode, ZFCP_ABORT_DBF_LENGTH); - debug_event(adapter->abort_dbf, 1, &dbf_wwn, sizeof (wwn_t)); - debug_event(adapter->abort_dbf, 1, &dbf_fcp_lun, sizeof (fcp_lun_t)); - debug_event(adapter->abort_dbf, 1, &dbf_retries, sizeof (u64)); - debug_event(adapter->abort_dbf, 1, &dbf_allowed, sizeof (u64)); - debug_event(adapter->abort_dbf, 1, &dbf_timeout, sizeof (u64)); - debug_event(adapter->abort_dbf, 1, &dbf_fsf_req, sizeof (u64)); - debug_event(adapter->abort_dbf, 1, &dbf_fsf_status, sizeof (u64)); - debug_event(adapter->abort_dbf, 1, &dbf_fsf_qual[0], sizeof (u64)); - debug_event(adapter->abort_dbf, 1, &dbf_fsf_qual[1], sizeof (u64)); - debug_text_event(adapter->abort_dbf, 1, dbf_result); - - spin_lock_irq(scsi_host->host_lock); return retval; } -int -zfcp_scsi_eh_abort_handler(struct scsi_cmnd *scpnt) -{ - int rc; - struct Scsi_Host *scsi_host = scpnt->device->host; - spin_lock_irq(scsi_host->host_lock); - rc = __zfcp_scsi_eh_abort_handler(scpnt); - spin_unlock_irq(scsi_host->host_lock); - return rc; -} - /* * function: zfcp_scsi_eh_device_reset_handler * @@ -651,8 +529,9 @@ zfcp_scsi_eh_device_reset_handler(struct scsi_cmnd *scpnt) */ if (!atomic_test_mask(ZFCP_STATUS_UNIT_NOTSUPPUNITRESET, &unit->status)) { - retval = - zfcp_task_management_function(unit, FCP_LOGICAL_UNIT_RESET); + retval = zfcp_task_management_function(unit, + FCP_LOGICAL_UNIT_RESET, + scpnt); if (retval) { ZFCP_LOG_DEBUG("unit reset failed (unit=%p)\n", unit); if (retval == -ENOTSUPP) @@ -668,7 +547,7 @@ zfcp_scsi_eh_device_reset_handler(struct scsi_cmnd *scpnt) goto out; } } - retval = zfcp_task_management_function(unit, FCP_TARGET_RESET); + retval = zfcp_task_management_function(unit, FCP_TARGET_RESET, scpnt); if (retval) { ZFCP_LOG_DEBUG("target reset failed (unit=%p)\n", unit); retval = FAILED; @@ -681,12 +560,12 @@ zfcp_scsi_eh_device_reset_handler(struct scsi_cmnd *scpnt) } static int -zfcp_task_management_function(struct zfcp_unit *unit, u8 tm_flags) +zfcp_task_management_function(struct zfcp_unit *unit, u8 tm_flags, + struct scsi_cmnd *scpnt) { struct zfcp_adapter *adapter = unit->port->adapter; - int retval; - int status; struct zfcp_fsf_req *fsf_req; + int retval = 0; /* issue task management function */ fsf_req = zfcp_fsf_send_fcp_command_task_management @@ -696,70 +575,63 @@ zfcp_task_management_function(struct zfcp_unit *unit, u8 tm_flags) "failed for unit 0x%016Lx on port 0x%016Lx on " "adapter %s\n", unit->fcp_lun, unit->port->wwpn, zfcp_get_busid_by_adapter(adapter)); + zfcp_scsi_dbf_event_devreset("nres", tm_flags, unit, scpnt); retval = -ENOMEM; goto out; } - retval = zfcp_fsf_req_wait_and_cleanup(fsf_req, - ZFCP_UNINTERRUPTIBLE, &status); + __wait_event(fsf_req->completion_wq, + fsf_req->status & ZFCP_STATUS_FSFREQ_COMPLETED); + /* * check completion status of task management function - * (status should always be valid since no signals permitted) */ - if (status & ZFCP_STATUS_FSFREQ_TMFUNCFAILED) + if (fsf_req->status & ZFCP_STATUS_FSFREQ_TMFUNCFAILED) { + zfcp_scsi_dbf_event_devreset("fail", tm_flags, unit, scpnt); retval = -EIO; - else if (status & ZFCP_STATUS_FSFREQ_TMFUNCNOTSUPP) + } else if (fsf_req->status & ZFCP_STATUS_FSFREQ_TMFUNCNOTSUPP) { + zfcp_scsi_dbf_event_devreset("nsup", tm_flags, unit, scpnt); retval = -ENOTSUPP; - else - retval = 0; + } else + zfcp_scsi_dbf_event_devreset("okay", tm_flags, unit, scpnt); + + zfcp_fsf_req_free(fsf_req); out: return retval; } -/* - * function: zfcp_scsi_eh_bus_reset_handler - * - * purpose: - * - * returns: +/** + * zfcp_scsi_eh_bus_reset_handler - reset bus (reopen adapter) */ int zfcp_scsi_eh_bus_reset_handler(struct scsi_cmnd *scpnt) { - int retval = 0; - struct zfcp_unit *unit; + struct zfcp_unit *unit = (struct zfcp_unit*) scpnt->device->hostdata; + struct zfcp_adapter *adapter = unit->port->adapter; - unit = (struct zfcp_unit *) scpnt->device->hostdata; ZFCP_LOG_NORMAL("bus reset because of problems with " "unit 0x%016Lx\n", unit->fcp_lun); - zfcp_erp_adapter_reopen(unit->port->adapter, 0); - zfcp_erp_wait(unit->port->adapter); - retval = SUCCESS; + zfcp_erp_adapter_reopen(adapter, 0); + zfcp_erp_wait(adapter); - return retval; + return SUCCESS; } -/* - * function: zfcp_scsi_eh_host_reset_handler - * - * purpose: - * - * returns: +/** + * zfcp_scsi_eh_host_reset_handler - reset host (reopen adapter) */ int zfcp_scsi_eh_host_reset_handler(struct scsi_cmnd *scpnt) { - int retval = 0; - struct zfcp_unit *unit; + struct zfcp_unit *unit = (struct zfcp_unit*) scpnt->device->hostdata; + struct zfcp_adapter *adapter = unit->port->adapter; - unit = (struct zfcp_unit *) scpnt->device->hostdata; ZFCP_LOG_NORMAL("host reset because of problems with " "unit 0x%016Lx\n", unit->fcp_lun); - zfcp_erp_adapter_reopen(unit->port->adapter, 0); - zfcp_erp_wait(unit->port->adapter); - retval = SUCCESS; + zfcp_erp_adapter_reopen(adapter, 0); + zfcp_erp_wait(adapter); - return retval; + return SUCCESS; } /* @@ -826,10 +698,16 @@ void zfcp_adapter_scsi_unregister(struct zfcp_adapter *adapter) { struct Scsi_Host *shost; + struct zfcp_port *port; shost = adapter->scsi_host; if (!shost) return; + read_lock_irq(&zfcp_data.config_lock); + list_for_each_entry(port, &adapter->port_list_head, list) + if (port->rport) + port->rport = NULL; + read_unlock_irq(&zfcp_data.config_lock); fc_remove_host(shost); scsi_remove_host(shost); scsi_host_put(shost); @@ -904,18 +782,6 @@ zfcp_get_node_name(struct scsi_target *starget) read_unlock_irqrestore(&zfcp_data.config_lock, flags); } -void -zfcp_set_fc_host_attrs(struct zfcp_adapter *adapter) -{ - struct Scsi_Host *shost = adapter->scsi_host; - - fc_host_node_name(shost) = adapter->wwnn; - fc_host_port_name(shost) = adapter->wwpn; - strncpy(fc_host_serial_number(shost), adapter->serial_number, - min(FC_SERIAL_NUMBER_SIZE, 32)); - fc_host_supported_classes(shost) = FC_COS_CLASS2 | FC_COS_CLASS3; -} - struct fc_function_template zfcp_transport_functions = { .get_starget_port_id = zfcp_get_port_id, .get_starget_port_name = zfcp_get_port_name, @@ -927,7 +793,10 @@ struct fc_function_template zfcp_transport_functions = { .show_host_node_name = 1, .show_host_port_name = 1, .show_host_supported_classes = 1, + .show_host_maxframe_size = 1, .show_host_serial_number = 1, + .show_host_speed = 1, + .show_host_port_id = 1, }; /** diff --git a/drivers/s390/scsi/zfcp_sysfs_adapter.c b/drivers/s390/scsi/zfcp_sysfs_adapter.c index e7345a7..0cd4352 100644 --- a/drivers/s390/scsi/zfcp_sysfs_adapter.c +++ b/drivers/s390/scsi/zfcp_sysfs_adapter.c @@ -62,21 +62,18 @@ static ssize_t zfcp_sysfs_adapter_##_name##_show(struct device *dev, struct devi static DEVICE_ATTR(_name, S_IRUGO, zfcp_sysfs_adapter_##_name##_show, NULL); ZFCP_DEFINE_ADAPTER_ATTR(status, "0x%08x\n", atomic_read(&adapter->status)); -ZFCP_DEFINE_ADAPTER_ATTR(wwnn, "0x%016llx\n", adapter->wwnn); -ZFCP_DEFINE_ADAPTER_ATTR(wwpn, "0x%016llx\n", adapter->wwpn); -ZFCP_DEFINE_ADAPTER_ATTR(s_id, "0x%06x\n", adapter->s_id); ZFCP_DEFINE_ADAPTER_ATTR(peer_wwnn, "0x%016llx\n", adapter->peer_wwnn); ZFCP_DEFINE_ADAPTER_ATTR(peer_wwpn, "0x%016llx\n", adapter->peer_wwpn); ZFCP_DEFINE_ADAPTER_ATTR(peer_d_id, "0x%06x\n", adapter->peer_d_id); +ZFCP_DEFINE_ADAPTER_ATTR(physical_wwpn, "0x%016llx\n", adapter->physical_wwpn); +ZFCP_DEFINE_ADAPTER_ATTR(physical_s_id, "0x%06x\n", adapter->physical_s_id); ZFCP_DEFINE_ADAPTER_ATTR(card_version, "0x%04x\n", adapter->hydra_version); ZFCP_DEFINE_ADAPTER_ATTR(lic_version, "0x%08x\n", adapter->fsf_lic_version); -ZFCP_DEFINE_ADAPTER_ATTR(fc_link_speed, "%d Gb/s\n", adapter->fc_link_speed); ZFCP_DEFINE_ADAPTER_ATTR(fc_service_class, "%d\n", adapter->fc_service_class); ZFCP_DEFINE_ADAPTER_ATTR(fc_topology, "%s\n", fc_topologies[adapter->fc_topology]); ZFCP_DEFINE_ADAPTER_ATTR(hardware_version, "0x%08x\n", adapter->hardware_version); -ZFCP_DEFINE_ADAPTER_ATTR(serial_number, "%17s\n", adapter->serial_number); ZFCP_DEFINE_ADAPTER_ATTR(scsi_host_no, "0x%x\n", adapter->scsi_host_no); ZFCP_DEFINE_ADAPTER_ATTR(in_recovery, "%d\n", atomic_test_mask (ZFCP_STATUS_COMMON_ERP_INUSE, &adapter->status)); @@ -255,21 +252,18 @@ static struct attribute *zfcp_adapter_attrs[] = { &dev_attr_in_recovery.attr, &dev_attr_port_remove.attr, &dev_attr_port_add.attr, - &dev_attr_wwnn.attr, - &dev_attr_wwpn.attr, - &dev_attr_s_id.attr, &dev_attr_peer_wwnn.attr, &dev_attr_peer_wwpn.attr, &dev_attr_peer_d_id.attr, + &dev_attr_physical_wwpn.attr, + &dev_attr_physical_s_id.attr, &dev_attr_card_version.attr, &dev_attr_lic_version.attr, - &dev_attr_fc_link_speed.attr, &dev_attr_fc_service_class.attr, &dev_attr_fc_topology.attr, &dev_attr_scsi_host_no.attr, &dev_attr_status.attr, &dev_attr_hardware_version.attr, - &dev_attr_serial_number.attr, NULL }; diff --git a/drivers/sbus/char/display7seg.c b/drivers/sbus/char/display7seg.c index dbad7f3..24ed589 100644 --- a/drivers/sbus/char/display7seg.c +++ b/drivers/sbus/char/display7seg.c @@ -14,7 +14,7 @@ #include <linux/major.h> #include <linux/init.h> #include <linux/miscdevice.h> -#include <linux/ioport.h> /* request_region, check_region */ +#include <linux/ioport.h> /* request_region */ #include <asm/atomic.h> #include <asm/ebus.h> /* EBus device */ #include <asm/oplib.h> /* OpenProm Library */ diff --git a/drivers/scsi/aic7xxx/aic7xxx_osm.c b/drivers/scsi/aic7xxx/aic7xxx_osm.c index c932b3b..876d1de 100644 --- a/drivers/scsi/aic7xxx/aic7xxx_osm.c +++ b/drivers/scsi/aic7xxx/aic7xxx_osm.c @@ -1109,15 +1109,6 @@ ahc_linux_register_host(struct ahc_softc *ahc, struct scsi_host_template *templa return (0); } -uint64_t -ahc_linux_get_memsize(void) -{ - struct sysinfo si; - - si_meminfo(&si); - return ((uint64_t)si.totalram << PAGE_SHIFT); -} - /* * Place the SCSI bus into a known state by either resetting it, * or forcing transfer negotiations on the next command to any diff --git a/drivers/scsi/aic7xxx/aic7xxx_osm.h b/drivers/scsi/aic7xxx/aic7xxx_osm.h index c529962..be9edbe 100644 --- a/drivers/scsi/aic7xxx/aic7xxx_osm.h +++ b/drivers/scsi/aic7xxx/aic7xxx_osm.h @@ -494,8 +494,6 @@ ahc_insb(struct ahc_softc * ahc, long port, uint8_t *array, int count) int ahc_linux_register_host(struct ahc_softc *, struct scsi_host_template *); -uint64_t ahc_linux_get_memsize(void); - /*************************** Pretty Printing **********************************/ struct info_str { char *buffer; diff --git a/drivers/scsi/aic7xxx/aic7xxx_osm_pci.c b/drivers/scsi/aic7xxx/aic7xxx_osm_pci.c index 0d44a69..3ce77dd 100644 --- a/drivers/scsi/aic7xxx/aic7xxx_osm_pci.c +++ b/drivers/scsi/aic7xxx/aic7xxx_osm_pci.c @@ -180,6 +180,7 @@ ahc_linux_pci_dev_probe(struct pci_dev *pdev, const struct pci_device_id *ent) struct ahc_pci_identity *entry; char *name; int error; + struct device *dev = &pdev->dev; pci = pdev; entry = ahc_find_pci_device(pci); @@ -209,11 +210,12 @@ ahc_linux_pci_dev_probe(struct pci_dev *pdev, const struct pci_device_id *ent) pci_set_master(pdev); if (sizeof(dma_addr_t) > 4 - && ahc_linux_get_memsize() > 0x80000000 - && pci_set_dma_mask(pdev, mask_39bit) == 0) { + && ahc->features & AHC_LARGE_SCBS + && dma_set_mask(dev, mask_39bit) == 0 + && dma_get_required_mask(dev) > DMA_32BIT_MASK) { ahc->flags |= AHC_39BIT_ADDRESSING; } else { - if (pci_set_dma_mask(pdev, DMA_32BIT_MASK)) { + if (dma_set_mask(dev, DMA_32BIT_MASK)) { printk(KERN_WARNING "aic7xxx: No suitable DMA available.\n"); return (-ENODEV); } diff --git a/drivers/scsi/ata_piix.c b/drivers/scsi/ata_piix.c index 87e0c36..d71cef7 100644 --- a/drivers/scsi/ata_piix.c +++ b/drivers/scsi/ata_piix.c @@ -442,7 +442,6 @@ static void piix_sata_phy_reset(struct ata_port *ap) * piix_set_piomode - Initialize host controller PATA PIO timings * @ap: Port whose timings we are configuring * @adev: um - * @pio: PIO mode, 0 - 4 * * Set PIO mode for device, in host controller PCI config space. * diff --git a/drivers/scsi/atp870u.c b/drivers/scsi/atp870u.c index e6153fe..a8cfbef 100644 --- a/drivers/scsi/atp870u.c +++ b/drivers/scsi/atp870u.c @@ -996,6 +996,7 @@ oktosend: #ifdef ED_DBGP printk("send_s870: prdaddr_2 0x%8x tmpcip %x target_id %d\n", dev->id[c][target_id].prdaddr,tmpcip,target_id); #endif + dev->id[c][target_id].prdaddr = dev->id[c][target_id].prd_bus; outl(dev->id[c][target_id].prdaddr, tmpcip); tmpcip = tmpcip - 2; outb(0x06, tmpcip); @@ -2572,7 +2573,7 @@ static void atp870u_free_tables(struct Scsi_Host *host) for (k = 0; k < 16; k++) { if (!atp_dev->id[j][k].prd_table) continue; - pci_free_consistent(atp_dev->pdev, 1024, atp_dev->id[j][k].prd_table, atp_dev->id[j][k].prdaddr); + pci_free_consistent(atp_dev->pdev, 1024, atp_dev->id[j][k].prd_table, atp_dev->id[j][k].prd_bus); atp_dev->id[j][k].prd_table = NULL; } } @@ -2584,12 +2585,13 @@ static int atp870u_init_tables(struct Scsi_Host *host) int c,k; for(c=0;c < 2;c++) { for(k=0;k<16;k++) { - atp_dev->id[c][k].prd_table = pci_alloc_consistent(atp_dev->pdev, 1024, &(atp_dev->id[c][k].prdaddr)); + atp_dev->id[c][k].prd_table = pci_alloc_consistent(atp_dev->pdev, 1024, &(atp_dev->id[c][k].prd_bus)); if (!atp_dev->id[c][k].prd_table) { printk("atp870u_init_tables fail\n"); atp870u_free_tables(host); return -ENOMEM; } + atp_dev->id[c][k].prdaddr = atp_dev->id[c][k].prd_bus; atp_dev->id[c][k].devsp=0x20; atp_dev->id[c][k].devtype = 0x7f; atp_dev->id[c][k].curr_req = NULL; diff --git a/drivers/scsi/atp870u.h b/drivers/scsi/atp870u.h index 89f43af..62bae64 100644 --- a/drivers/scsi/atp870u.h +++ b/drivers/scsi/atp870u.h @@ -54,8 +54,9 @@ struct atp_unit unsigned long tran_len; unsigned long last_len; unsigned char *prd_pos; - unsigned char *prd_table; - dma_addr_t prdaddr; + unsigned char *prd_table; /* Kernel address of PRD table */ + dma_addr_t prd_bus; /* Bus address of PRD */ + dma_addr_t prdaddr; /* Dynamically updated in driver */ struct scsi_cmnd *curr_req; } id[2][16]; struct Scsi_Host *host; diff --git a/drivers/scsi/fd_mcs.c b/drivers/scsi/fd_mcs.c index fa652f8a..d59d449 100644 --- a/drivers/scsi/fd_mcs.c +++ b/drivers/scsi/fd_mcs.c @@ -1360,3 +1360,5 @@ static Scsi_Host_Template driver_template = { .use_clustering = DISABLE_CLUSTERING, }; #include "scsi_module.c" + +MODULE_LICENSE("GPL"); diff --git a/drivers/scsi/hosts.c b/drivers/scsi/hosts.c index 85503fa..f2a72d3 100644 --- a/drivers/scsi/hosts.c +++ b/drivers/scsi/hosts.c @@ -98,6 +98,7 @@ int scsi_host_set_state(struct Scsi_Host *shost, enum scsi_host_state state) switch (oldstate) { case SHOST_CREATED: case SHOST_RUNNING: + case SHOST_CANCEL_RECOVERY: break; default: goto illegal; @@ -107,12 +108,31 @@ int scsi_host_set_state(struct Scsi_Host *shost, enum scsi_host_state state) case SHOST_DEL: switch (oldstate) { case SHOST_CANCEL: + case SHOST_DEL_RECOVERY: break; default: goto illegal; } break; + case SHOST_CANCEL_RECOVERY: + switch (oldstate) { + case SHOST_CANCEL: + case SHOST_RECOVERY: + break; + default: + goto illegal; + } + break; + + case SHOST_DEL_RECOVERY: + switch (oldstate) { + case SHOST_CANCEL_RECOVERY: + break; + default: + goto illegal; + } + break; } shost->shost_state = state; return 0; @@ -134,13 +154,24 @@ EXPORT_SYMBOL(scsi_host_set_state); **/ void scsi_remove_host(struct Scsi_Host *shost) { + unsigned long flags; down(&shost->scan_mutex); - scsi_host_set_state(shost, SHOST_CANCEL); + spin_lock_irqsave(shost->host_lock, flags); + if (scsi_host_set_state(shost, SHOST_CANCEL)) + if (scsi_host_set_state(shost, SHOST_CANCEL_RECOVERY)) { + spin_unlock_irqrestore(shost->host_lock, flags); + up(&shost->scan_mutex); + return; + } + spin_unlock_irqrestore(shost->host_lock, flags); up(&shost->scan_mutex); scsi_forget_host(shost); scsi_proc_host_rm(shost); - scsi_host_set_state(shost, SHOST_DEL); + spin_lock_irqsave(shost->host_lock, flags); + if (scsi_host_set_state(shost, SHOST_DEL)) + BUG_ON(scsi_host_set_state(shost, SHOST_DEL_RECOVERY)); + spin_unlock_irqrestore(shost->host_lock, flags); transport_unregister_device(&shost->shost_gendev); class_device_unregister(&shost->shost_classdev); diff --git a/drivers/scsi/ibmmca.c b/drivers/scsi/ibmmca.c index 6e54c7d..19392f6 100644 --- a/drivers/scsi/ibmmca.c +++ b/drivers/scsi/ibmmca.c @@ -460,6 +460,8 @@ MODULE_PARM(adisplay, "1i"); MODULE_PARM(normal, "1i"); MODULE_PARM(ansi, "1i"); #endif + +MODULE_LICENSE("GPL"); #endif /*counter of concurrent disk read/writes, to turn on/off disk led */ static int disk_rw_in_progress = 0; diff --git a/drivers/scsi/ibmvscsi/ibmvscsi.c b/drivers/scsi/ibmvscsi/ibmvscsi.c index 5b14934..ff25210 100644 --- a/drivers/scsi/ibmvscsi/ibmvscsi.c +++ b/drivers/scsi/ibmvscsi/ibmvscsi.c @@ -727,6 +727,16 @@ static void adapter_info_rsp(struct srp_event_struct *evt_struct) if (hostdata->madapter_info.port_max_txu[0]) hostdata->host->max_sectors = hostdata->madapter_info.port_max_txu[0] >> 9; + + if (hostdata->madapter_info.os_type == 3 && + strcmp(hostdata->madapter_info.srp_version, "1.6a") <= 0) { + printk("ibmvscsi: host (Ver. %s) doesn't support large" + "transfers\n", + hostdata->madapter_info.srp_version); + printk("ibmvscsi: limiting scatterlists to %d\n", + MAX_INDIRECT_BUFS); + hostdata->host->sg_tablesize = MAX_INDIRECT_BUFS; + } } } diff --git a/drivers/scsi/libata-core.c b/drivers/scsi/libata-core.c index 62095bd..9182817 100644 --- a/drivers/scsi/libata-core.c +++ b/drivers/scsi/libata-core.c @@ -2551,9 +2551,12 @@ static unsigned long ata_pio_poll(struct ata_port *ap) * * LOCKING: * None. (executing in kernel thread context) + * + * RETURNS: + * Non-zero if qc completed, zero otherwise. */ -static void ata_pio_complete (struct ata_port *ap) +static int ata_pio_complete (struct ata_port *ap) { struct ata_queued_cmd *qc; u8 drv_stat; @@ -2572,14 +2575,14 @@ static void ata_pio_complete (struct ata_port *ap) if (drv_stat & (ATA_BUSY | ATA_DRQ)) { ap->pio_task_state = PIO_ST_LAST_POLL; ap->pio_task_timeout = jiffies + ATA_TMOUT_PIO; - return; + return 0; } } drv_stat = ata_wait_idle(ap); if (!ata_ok(drv_stat)) { ap->pio_task_state = PIO_ST_ERR; - return; + return 0; } qc = ata_qc_from_tag(ap, ap->active_tag); @@ -2588,6 +2591,10 @@ static void ata_pio_complete (struct ata_port *ap) ap->pio_task_state = PIO_ST_IDLE; ata_poll_qc_complete(qc, drv_stat); + + /* another command may start at this point */ + + return 1; } @@ -2795,7 +2802,7 @@ static void __atapi_pio_bytes(struct ata_queued_cmd *qc, unsigned int bytes) next_sg: if (unlikely(qc->cursg >= qc->n_elem)) { - /* + /* * The end of qc->sg is reached and the device expects * more data to transfer. In order not to overrun qc->sg * and fulfill length specified in the byte count register, @@ -2807,7 +2814,7 @@ next_sg: unsigned int i; if (words) /* warning if bytes > 1 */ - printk(KERN_WARNING "ata%u: %u bytes trailing data\n", + printk(KERN_WARNING "ata%u: %u bytes trailing data\n", ap->id, bytes); for (i = 0; i < words; i++) @@ -2935,9 +2942,7 @@ static void ata_pio_block(struct ata_port *ap) if (is_atapi_taskfile(&qc->tf)) { /* no more data to transfer or unsupported ATAPI command */ if ((status & ATA_DRQ) == 0) { - ap->pio_task_state = PIO_ST_IDLE; - - ata_poll_qc_complete(qc, status); + ap->pio_task_state = PIO_ST_LAST; return; } @@ -2973,7 +2978,12 @@ static void ata_pio_error(struct ata_port *ap) static void ata_pio_task(void *_data) { struct ata_port *ap = _data; - unsigned long timeout = 0; + unsigned long timeout; + int qc_completed; + +fsm_start: + timeout = 0; + qc_completed = 0; switch (ap->pio_task_state) { case PIO_ST_IDLE: @@ -2984,7 +2994,7 @@ static void ata_pio_task(void *_data) break; case PIO_ST_LAST: - ata_pio_complete(ap); + qc_completed = ata_pio_complete(ap); break; case PIO_ST_POLL: @@ -2999,10 +3009,9 @@ static void ata_pio_task(void *_data) } if (timeout) - queue_delayed_work(ata_wq, &ap->pio_task, - timeout); - else - queue_work(ata_wq, &ap->pio_task); + queue_delayed_work(ata_wq, &ap->pio_task, timeout); + else if (!qc_completed) + goto fsm_start; } static void atapi_request_sense(struct ata_port *ap, struct ata_device *dev, @@ -4213,6 +4222,53 @@ err_out: } /** + * ata_host_set_remove - PCI layer callback for device removal + * @host_set: ATA host set that was removed + * + * Unregister all objects associated with this host set. Free those + * objects. + * + * LOCKING: + * Inherited from calling layer (may sleep). + */ + + +void ata_host_set_remove(struct ata_host_set *host_set) +{ + struct ata_port *ap; + unsigned int i; + + for (i = 0; i < host_set->n_ports; i++) { + ap = host_set->ports[i]; + scsi_remove_host(ap->host); + } + + free_irq(host_set->irq, host_set); + + for (i = 0; i < host_set->n_ports; i++) { + ap = host_set->ports[i]; + + ata_scsi_release(ap->host); + + if ((ap->flags & ATA_FLAG_NO_LEGACY) == 0) { + struct ata_ioports *ioaddr = &ap->ioaddr; + + if (ioaddr->cmd_addr == 0x1f0) + release_region(0x1f0, 8); + else if (ioaddr->cmd_addr == 0x170) + release_region(0x170, 8); + } + + scsi_host_put(ap->host); + } + + if (host_set->ops->host_stop) + host_set->ops->host_stop(host_set); + + kfree(host_set); +} + +/** * ata_scsi_release - SCSI layer callback hook for host unload * @host: libata host to be unloaded * @@ -4552,39 +4608,8 @@ void ata_pci_remove_one (struct pci_dev *pdev) { struct device *dev = pci_dev_to_dev(pdev); struct ata_host_set *host_set = dev_get_drvdata(dev); - struct ata_port *ap; - unsigned int i; - - for (i = 0; i < host_set->n_ports; i++) { - ap = host_set->ports[i]; - - scsi_remove_host(ap->host); - } - - free_irq(host_set->irq, host_set); - - for (i = 0; i < host_set->n_ports; i++) { - ap = host_set->ports[i]; - - ata_scsi_release(ap->host); - - if ((ap->flags & ATA_FLAG_NO_LEGACY) == 0) { - struct ata_ioports *ioaddr = &ap->ioaddr; - - if (ioaddr->cmd_addr == 0x1f0) - release_region(0x1f0, 8); - else if (ioaddr->cmd_addr == 0x170) - release_region(0x170, 8); - } - - scsi_host_put(ap->host); - } - - if (host_set->ops->host_stop) - host_set->ops->host_stop(host_set); - - kfree(host_set); + ata_host_set_remove(host_set); pci_release_regions(pdev); pci_disable_device(pdev); dev_set_drvdata(dev, NULL); @@ -4654,6 +4679,7 @@ module_exit(ata_exit); EXPORT_SYMBOL_GPL(ata_std_bios_param); EXPORT_SYMBOL_GPL(ata_std_ports); EXPORT_SYMBOL_GPL(ata_device_add); +EXPORT_SYMBOL_GPL(ata_host_set_remove); EXPORT_SYMBOL_GPL(ata_sg_init); EXPORT_SYMBOL_GPL(ata_sg_init_one); EXPORT_SYMBOL_GPL(ata_qc_complete); diff --git a/drivers/scsi/mesh.c b/drivers/scsi/mesh.c index a4857db..b235556 100644 --- a/drivers/scsi/mesh.c +++ b/drivers/scsi/mesh.c @@ -1959,22 +1959,35 @@ static int mesh_probe(struct macio_dev *mdev, const struct of_device_id *match) /* Set it up */ mesh_init(ms); - /* XXX FIXME: error should be fatal */ - if (request_irq(ms->meshintr, do_mesh_interrupt, 0, "MESH", ms)) + /* Request interrupt */ + if (request_irq(ms->meshintr, do_mesh_interrupt, 0, "MESH", ms)) { printk(KERN_ERR "MESH: can't get irq %d\n", ms->meshintr); + goto out_shutdown; + } - /* XXX FIXME: handle failure */ - scsi_add_host(mesh_host, &mdev->ofdev.dev); + /* Add scsi host & scan */ + if (scsi_add_host(mesh_host, &mdev->ofdev.dev)) + goto out_release_irq; scsi_scan_host(mesh_host); return 0; -out_unmap: + out_release_irq: + free_irq(ms->meshintr, ms); + out_shutdown: + /* shutdown & reset bus in case of error or macos can be confused + * at reboot if the bus was set to synchronous mode already + */ + mesh_shutdown(mdev); + set_mesh_power(ms, 0); + pci_free_consistent(macio_get_pci_dev(mdev), ms->dma_cmd_size, + ms->dma_cmd_space, ms->dma_cmd_bus); + out_unmap: iounmap(ms->dma); iounmap(ms->mesh); -out_free: + out_free: scsi_host_put(mesh_host); -out_release: + out_release: macio_release_resources(mdev); return -ENODEV; @@ -2001,7 +2014,7 @@ static int mesh_remove(struct macio_dev *mdev) /* Free DMA commands memory */ pci_free_consistent(macio_get_pci_dev(mdev), ms->dma_cmd_size, - ms->dma_cmd_space, ms->dma_cmd_bus); + ms->dma_cmd_space, ms->dma_cmd_bus); /* Release memory resources */ macio_release_resources(mdev); diff --git a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c index 3e9b641..23d095d 100644 --- a/drivers/scsi/qla2xxx/qla_init.c +++ b/drivers/scsi/qla2xxx/qla_init.c @@ -201,6 +201,7 @@ int qla2100_pci_config(scsi_qla_host_t *ha) { uint16_t w, mwi; + uint32_t d; unsigned long flags; struct device_reg_2xxx __iomem *reg = &ha->iobase->isp; @@ -215,9 +216,9 @@ qla2100_pci_config(scsi_qla_host_t *ha) pci_write_config_word(ha->pdev, PCI_COMMAND, w); /* Reset expansion ROM address decode enable */ - pci_read_config_word(ha->pdev, PCI_ROM_ADDRESS, &w); - w &= ~PCI_ROM_ADDRESS_ENABLE; - pci_write_config_word(ha->pdev, PCI_ROM_ADDRESS, w); + pci_read_config_dword(ha->pdev, PCI_ROM_ADDRESS, &d); + d &= ~PCI_ROM_ADDRESS_ENABLE; + pci_write_config_dword(ha->pdev, PCI_ROM_ADDRESS, d); /* Get PCI bus information. */ spin_lock_irqsave(&ha->hardware_lock, flags); @@ -237,6 +238,7 @@ int qla2300_pci_config(scsi_qla_host_t *ha) { uint16_t w, mwi; + uint32_t d; unsigned long flags = 0; uint32_t cnt; struct device_reg_2xxx __iomem *reg = &ha->iobase->isp; @@ -302,9 +304,9 @@ qla2300_pci_config(scsi_qla_host_t *ha) pci_write_config_byte(ha->pdev, PCI_LATENCY_TIMER, 0x80); /* Reset expansion ROM address decode enable */ - pci_read_config_word(ha->pdev, PCI_ROM_ADDRESS, &w); - w &= ~PCI_ROM_ADDRESS_ENABLE; - pci_write_config_word(ha->pdev, PCI_ROM_ADDRESS, w); + pci_read_config_dword(ha->pdev, PCI_ROM_ADDRESS, &d); + d &= ~PCI_ROM_ADDRESS_ENABLE; + pci_write_config_dword(ha->pdev, PCI_ROM_ADDRESS, d); /* Get PCI bus information. */ spin_lock_irqsave(&ha->hardware_lock, flags); @@ -324,6 +326,7 @@ int qla24xx_pci_config(scsi_qla_host_t *ha) { uint16_t w, mwi; + uint32_t d; unsigned long flags = 0; struct device_reg_24xx __iomem *reg = &ha->iobase->isp24; int pcix_cmd_reg, pcie_dctl_reg; @@ -366,9 +369,9 @@ qla24xx_pci_config(scsi_qla_host_t *ha) } /* Reset expansion ROM address decode enable */ - pci_read_config_word(ha->pdev, PCI_ROM_ADDRESS, &w); - w &= ~PCI_ROM_ADDRESS_ENABLE; - pci_write_config_word(ha->pdev, PCI_ROM_ADDRESS, w); + pci_read_config_dword(ha->pdev, PCI_ROM_ADDRESS, &d); + d &= ~PCI_ROM_ADDRESS_ENABLE; + pci_write_config_dword(ha->pdev, PCI_ROM_ADDRESS, d); /* Get PCI bus information. */ spin_lock_irqsave(&ha->hardware_lock, flags); diff --git a/drivers/scsi/sata_nv.c b/drivers/scsi/sata_nv.c index a1d62de..c05653c 100644 --- a/drivers/scsi/sata_nv.c +++ b/drivers/scsi/sata_nv.c @@ -158,6 +158,8 @@ static struct pci_device_id nv_pci_tbl[] = { PCI_ANY_ID, PCI_ANY_ID, 0, 0, MCP51 }, { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP55_SATA, PCI_ANY_ID, PCI_ANY_ID, 0, 0, MCP55 }, + { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP55_SATA2, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, MCP55 }, { PCI_VENDOR_ID_NVIDIA, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_STORAGE_IDE<<8, 0xffff00, GENERIC }, diff --git a/drivers/scsi/sata_sis.c b/drivers/scsi/sata_sis.c index a63f931..b227e51 100644 --- a/drivers/scsi/sata_sis.c +++ b/drivers/scsi/sata_sis.c @@ -161,7 +161,7 @@ static u32 sis_scr_cfg_read (struct ata_port *ap, unsigned int sc_reg) { struct pci_dev *pdev = to_pci_dev(ap->host_set->dev); unsigned int cfg_addr = get_scr_cfg_addr(ap->port_no, sc_reg, pdev->device); - u32 val, val2; + u32 val, val2 = 0; u8 pmr; if (sc_reg == SCR_ERROR) /* doesn't exist in PCI cfg space */ @@ -289,7 +289,7 @@ static int sis_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) if (ent->device != 0x182) { if ((pmr & SIS_PMR_COMBINED) == 0) { printk(KERN_INFO "sata_sis: Detected SiS 180/181 chipset in SATA mode\n"); - port2_start=0x64; + port2_start = 64; } else { printk(KERN_INFO "sata_sis: Detected SiS 180/181 chipset in combined mode\n"); diff --git a/drivers/scsi/scsi.c b/drivers/scsi/scsi.c index a780546..1f0ebab 100644 --- a/drivers/scsi/scsi.c +++ b/drivers/scsi/scsi.c @@ -1265,9 +1265,8 @@ int scsi_device_cancel(struct scsi_device *sdev, int recovery) list_for_each_safe(lh, lh_sf, &active_list) { scmd = list_entry(lh, struct scsi_cmnd, eh_entry); list_del_init(lh); - if (recovery) { - scsi_eh_scmd_add(scmd, SCSI_EH_CANCEL_CMD); - } else { + if (recovery && + !scsi_eh_scmd_add(scmd, SCSI_EH_CANCEL_CMD)) { scmd->result = (DID_ABORT << 16); scsi_finish_command(scmd); } diff --git a/drivers/scsi/scsi_devinfo.c b/drivers/scsi/scsi_devinfo.c index 07b554a..64fc9e2 100644 --- a/drivers/scsi/scsi_devinfo.c +++ b/drivers/scsi/scsi_devinfo.c @@ -110,6 +110,7 @@ static struct { {"RELISYS", "Scorpio", NULL, BLIST_NOLUN}, /* responds to all lun */ {"SANKYO", "CP525", "6.64", BLIST_NOLUN}, /* causes failed REQ SENSE, extra reset */ {"TEXEL", "CD-ROM", "1.06", BLIST_NOLUN}, + {"transtec", "T5008", "0001", BLIST_NOREPORTLUN }, {"YAMAHA", "CDR100", "1.00", BLIST_NOLUN}, /* locks up */ {"YAMAHA", "CDR102", "1.00", BLIST_NOLUN}, /* locks up */ {"YAMAHA", "CRW8424S", "1.0", BLIST_NOLUN}, /* locks up */ diff --git a/drivers/scsi/scsi_error.c b/drivers/scsi/scsi_error.c index 895c945..ad53421 100644 --- a/drivers/scsi/scsi_error.c +++ b/drivers/scsi/scsi_error.c @@ -50,7 +50,7 @@ void scsi_eh_wakeup(struct Scsi_Host *shost) { if (shost->host_busy == shost->host_failed) { - up(shost->eh_wait); + wake_up_process(shost->ehandler); SCSI_LOG_ERROR_RECOVERY(5, printk("Waking error handler thread\n")); } @@ -68,19 +68,24 @@ int scsi_eh_scmd_add(struct scsi_cmnd *scmd, int eh_flag) { struct Scsi_Host *shost = scmd->device->host; unsigned long flags; + int ret = 0; - if (shost->eh_wait == NULL) + if (!shost->ehandler) return 0; spin_lock_irqsave(shost->host_lock, flags); + if (scsi_host_set_state(shost, SHOST_RECOVERY)) + if (scsi_host_set_state(shost, SHOST_CANCEL_RECOVERY)) + goto out_unlock; + ret = 1; scmd->eh_eflags |= eh_flag; list_add_tail(&scmd->eh_entry, &shost->eh_cmd_q); - scsi_host_set_state(shost, SHOST_RECOVERY); shost->host_failed++; scsi_eh_wakeup(shost); + out_unlock: spin_unlock_irqrestore(shost->host_lock, flags); - return 1; + return ret; } /** @@ -176,8 +181,8 @@ void scsi_times_out(struct scsi_cmnd *scmd) } if (unlikely(!scsi_eh_scmd_add(scmd, SCSI_EH_CANCEL_CMD))) { - panic("Error handler thread not present at %p %p %s %d", - scmd, scmd->device->host, __FILE__, __LINE__); + scmd->result |= DID_TIME_OUT << 16; + __scsi_done(scmd); } } @@ -196,8 +201,7 @@ int scsi_block_when_processing_errors(struct scsi_device *sdev) { int online; - wait_event(sdev->host->host_wait, (sdev->host->shost_state != - SHOST_RECOVERY)); + wait_event(sdev->host->host_wait, !scsi_host_in_recovery(sdev->host)); online = scsi_device_online(sdev); @@ -1441,6 +1445,7 @@ static void scsi_eh_lock_door(struct scsi_device *sdev) static void scsi_restart_operations(struct Scsi_Host *shost) { struct scsi_device *sdev; + unsigned long flags; /* * If the door was locked, we need to insert a door lock request @@ -1460,7 +1465,11 @@ static void scsi_restart_operations(struct Scsi_Host *shost) SCSI_LOG_ERROR_RECOVERY(3, printk("%s: waking up host to restart\n", __FUNCTION__)); - scsi_host_set_state(shost, SHOST_RUNNING); + spin_lock_irqsave(shost->host_lock, flags); + if (scsi_host_set_state(shost, SHOST_RUNNING)) + if (scsi_host_set_state(shost, SHOST_CANCEL)) + BUG_ON(scsi_host_set_state(shost, SHOST_DEL)); + spin_unlock_irqrestore(shost->host_lock, flags); wake_up(&shost->host_wait); @@ -1582,40 +1591,31 @@ int scsi_error_handler(void *data) { struct Scsi_Host *shost = (struct Scsi_Host *) data; int rtn; - DECLARE_MUTEX_LOCKED(sem); current->flags |= PF_NOFREEZE; - shost->eh_wait = &sem; + /* - * Wake up the thread that created us. + * Note - we always use TASK_INTERRUPTIBLE even if the module + * was loaded as part of the kernel. The reason is that + * UNINTERRUPTIBLE would cause this thread to be counted in + * the load average as a running process, and an interruptible + * wait doesn't. */ - SCSI_LOG_ERROR_RECOVERY(3, printk("Wake up parent of" - " scsi_eh_%d\n",shost->host_no)); - - while (1) { - /* - * If we get a signal, it means we are supposed to go - * away and die. This typically happens if the user is - * trying to unload a module. - */ - SCSI_LOG_ERROR_RECOVERY(1, printk("Error handler" - " scsi_eh_%d" - " sleeping\n",shost->host_no)); - - /* - * Note - we always use down_interruptible with the semaphore - * even if the module was loaded as part of the kernel. The - * reason is that down() will cause this thread to be counted - * in the load average as a running process, and down - * interruptible doesn't. Given that we need to allow this - * thread to die if the driver was loaded as a module, using - * semaphores isn't unreasonable. - */ - down_interruptible(&sem); - if (kthread_should_stop()) - break; + set_current_state(TASK_INTERRUPTIBLE); + while (!kthread_should_stop()) { + if (shost->host_failed == 0 || + shost->host_failed != shost->host_busy) { + SCSI_LOG_ERROR_RECOVERY(1, printk("Error handler" + " scsi_eh_%d" + " sleeping\n", + shost->host_no)); + schedule(); + set_current_state(TASK_INTERRUPTIBLE); + continue; + } + __set_current_state(TASK_RUNNING); SCSI_LOG_ERROR_RECOVERY(1, printk("Error handler" " scsi_eh_%d waking" " up\n",shost->host_no)); @@ -1642,7 +1642,7 @@ int scsi_error_handler(void *data) * which are still online. */ scsi_restart_operations(shost); - + set_current_state(TASK_INTERRUPTIBLE); } SCSI_LOG_ERROR_RECOVERY(1, printk("Error handler scsi_eh_%d" @@ -1651,7 +1651,7 @@ int scsi_error_handler(void *data) /* * Make sure that nobody tries to wake us up again. */ - shost->eh_wait = NULL; + shost->ehandler = NULL; return 0; } diff --git a/drivers/scsi/scsi_ioctl.c b/drivers/scsi/scsi_ioctl.c index b7fddac..de7f98c 100644 --- a/drivers/scsi/scsi_ioctl.c +++ b/drivers/scsi/scsi_ioctl.c @@ -458,7 +458,7 @@ int scsi_nonblockable_ioctl(struct scsi_device *sdev, int cmd, * error processing, as long as the device was opened * non-blocking */ if (filp && filp->f_flags & O_NONBLOCK) { - if (sdev->host->shost_state == SHOST_RECOVERY) + if (scsi_host_in_recovery(sdev->host)) return -ENODEV; } else if (!scsi_block_when_processing_errors(sdev)) return -ENODEV; diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c index 863bb64..dc9c772 100644 --- a/drivers/scsi/scsi_lib.c +++ b/drivers/scsi/scsi_lib.c @@ -118,7 +118,6 @@ static void scsi_unprep_request(struct request *req) req->flags &= ~REQ_DONTPREP; req->special = (req->flags & REQ_SPECIAL) ? cmd->sc_request : NULL; - scsi_release_buffers(cmd); scsi_put_command(cmd); } @@ -140,14 +139,12 @@ static void scsi_unprep_request(struct request *req) * commands. * Notes: This could be called either from an interrupt context or a * normal process context. - * Notes: Upon return, cmd is a stale pointer. */ int scsi_queue_insert(struct scsi_cmnd *cmd, int reason) { struct Scsi_Host *host = cmd->device->host; struct scsi_device *device = cmd->device; struct request_queue *q = device->request_queue; - struct request *req = cmd->request; unsigned long flags; SCSI_LOG_MLQUEUE(1, @@ -188,9 +185,8 @@ int scsi_queue_insert(struct scsi_cmnd *cmd, int reason) * function. The SCSI request function detects the blocked condition * and plugs the queue appropriately. */ - scsi_unprep_request(req); spin_lock_irqsave(q->queue_lock, flags); - blk_requeue_request(q, req); + blk_requeue_request(q, cmd->request); spin_unlock_irqrestore(q->queue_lock, flags); scsi_run_queue(q); @@ -451,7 +447,7 @@ void scsi_device_unbusy(struct scsi_device *sdev) spin_lock_irqsave(shost->host_lock, flags); shost->host_busy--; - if (unlikely((shost->shost_state == SHOST_RECOVERY) && + if (unlikely(scsi_host_in_recovery(shost) && shost->host_failed)) scsi_eh_wakeup(shost); spin_unlock(shost->host_lock); @@ -1268,6 +1264,7 @@ static int scsi_prep_fn(struct request_queue *q, struct request *req) } } else { memcpy(cmd->cmnd, req->cmd, sizeof(cmd->cmnd)); + cmd->cmd_len = req->cmd_len; if (rq_data_dir(req) == WRITE) cmd->sc_data_direction = DMA_TO_DEVICE; else if (req->data_len) @@ -1342,7 +1339,7 @@ static inline int scsi_host_queue_ready(struct request_queue *q, struct Scsi_Host *shost, struct scsi_device *sdev) { - if (shost->shost_state == SHOST_RECOVERY) + if (scsi_host_in_recovery(shost)) return 0; if (shost->host_busy == 0 && shost->host_blocked) { /* @@ -1514,7 +1511,6 @@ static void scsi_request_fn(struct request_queue *q) * cases (host limits or settings) should run the queue at some * later time. */ - scsi_unprep_request(req); spin_lock_irq(q->queue_lock); blk_requeue_request(q, req); sdev->device_busy--; diff --git a/drivers/scsi/scsi_scan.c b/drivers/scsi/scsi_scan.c index b86f170..fcf9f6c 100644 --- a/drivers/scsi/scsi_scan.c +++ b/drivers/scsi/scsi_scan.c @@ -1466,23 +1466,17 @@ EXPORT_SYMBOL(scsi_scan_single_target); void scsi_forget_host(struct Scsi_Host *shost) { - struct scsi_target *starget, *tmp; + struct scsi_device *sdev; unsigned long flags; - /* - * Ok, this look a bit strange. We always look for the first device - * on the list as scsi_remove_device removes them from it - thus we - * also have to release the lock. - * We don't need to get another reference to the device before - * releasing the lock as we already own the reference from - * scsi_register_device that's release in scsi_remove_device. And - * after that we don't look at sdev anymore. - */ + restart: spin_lock_irqsave(shost->host_lock, flags); - list_for_each_entry_safe(starget, tmp, &shost->__targets, siblings) { + list_for_each_entry(sdev, &shost->__devices, siblings) { + if (sdev->sdev_state == SDEV_DEL) + continue; spin_unlock_irqrestore(shost->host_lock, flags); - scsi_remove_target(&starget->dev); - spin_lock_irqsave(shost->host_lock, flags); + __scsi_remove_device(sdev); + goto restart; } spin_unlock_irqrestore(shost->host_lock, flags); } diff --git a/drivers/scsi/scsi_sysfs.c b/drivers/scsi/scsi_sysfs.c index b8052d5..72a6550 100644 --- a/drivers/scsi/scsi_sysfs.c +++ b/drivers/scsi/scsi_sysfs.c @@ -57,6 +57,8 @@ static struct { { SHOST_CANCEL, "cancel" }, { SHOST_DEL, "deleted" }, { SHOST_RECOVERY, "recovery" }, + { SHOST_CANCEL_RECOVERY, "cancel/recovery" }, + { SHOST_DEL_RECOVERY, "deleted/recovery", }, }; const char *scsi_host_state_name(enum scsi_host_state state) { @@ -707,9 +709,11 @@ void __scsi_remove_device(struct scsi_device *sdev) **/ void scsi_remove_device(struct scsi_device *sdev) { - down(&sdev->host->scan_mutex); + struct Scsi_Host *shost = sdev->host; + + down(&shost->scan_mutex); __scsi_remove_device(sdev); - up(&sdev->host->scan_mutex); + up(&shost->scan_mutex); } EXPORT_SYMBOL(scsi_remove_device); @@ -717,17 +721,20 @@ void __scsi_remove_target(struct scsi_target *starget) { struct Scsi_Host *shost = dev_to_shost(starget->dev.parent); unsigned long flags; - struct scsi_device *sdev, *tmp; + struct scsi_device *sdev; spin_lock_irqsave(shost->host_lock, flags); starget->reap_ref++; - list_for_each_entry_safe(sdev, tmp, &shost->__devices, siblings) { + restart: + list_for_each_entry(sdev, &shost->__devices, siblings) { if (sdev->channel != starget->channel || - sdev->id != starget->id) + sdev->id != starget->id || + sdev->sdev_state == SDEV_DEL) continue; spin_unlock_irqrestore(shost->host_lock, flags); scsi_remove_device(sdev); spin_lock_irqsave(shost->host_lock, flags); + goto restart; } spin_unlock_irqrestore(shost->host_lock, flags); scsi_target_reap(starget); diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c index de564b3..9a1dc0c 100644 --- a/drivers/scsi/sd.c +++ b/drivers/scsi/sd.c @@ -235,6 +235,7 @@ static int sd_init_command(struct scsi_cmnd * SCpnt) return 0; memcpy(SCpnt->cmnd, rq->cmd, sizeof(SCpnt->cmnd)); + SCpnt->cmd_len = rq->cmd_len; if (rq_data_dir(rq) == WRITE) SCpnt->sc_data_direction = DMA_TO_DEVICE; else if (rq->data_len) diff --git a/drivers/scsi/sg.c b/drivers/scsi/sg.c index 9ea4765..4d09a6e 100644 --- a/drivers/scsi/sg.c +++ b/drivers/scsi/sg.c @@ -1027,7 +1027,7 @@ sg_ioctl(struct inode *inode, struct file *filp, if (sdp->detached) return -ENODEV; if (filp->f_flags & O_NONBLOCK) { - if (sdp->device->host->shost_state == SHOST_RECOVERY) + if (scsi_host_in_recovery(sdp->device->host)) return -EBUSY; } else if (!scsi_block_when_processing_errors(sdp->device)) return -EBUSY; diff --git a/drivers/scsi/sr.c b/drivers/scsi/sr.c index ce63fc8..561901b 100644 --- a/drivers/scsi/sr.c +++ b/drivers/scsi/sr.c @@ -326,6 +326,7 @@ static int sr_init_command(struct scsi_cmnd * SCpnt) return 0; memcpy(SCpnt->cmnd, rq->cmd, sizeof(SCpnt->cmnd)); + SCpnt->cmd_len = rq->cmd_len; if (!rq->data_len) SCpnt->sc_data_direction = DMA_NONE; else if (rq_data_dir(rq) == WRITE) diff --git a/drivers/scsi/st.c b/drivers/scsi/st.c index a93308a..d001c04 100644 --- a/drivers/scsi/st.c +++ b/drivers/scsi/st.c @@ -4206,6 +4206,7 @@ static int st_init_command(struct scsi_cmnd *SCpnt) return 0; memcpy(SCpnt->cmnd, rq->cmd, sizeof(SCpnt->cmnd)); + SCpnt->cmd_len = rq->cmd_len; if (rq_data_dir(rq) == WRITE) SCpnt->sc_data_direction = DMA_TO_DEVICE; diff --git a/drivers/serial/21285.c b/drivers/serial/21285.c index aec39fb..b5cf394 100644 --- a/drivers/serial/21285.c +++ b/drivers/serial/21285.c @@ -463,7 +463,7 @@ static int __init serial21285_console_setup(struct console *co, char *options) return uart_set_options(port, co, baud, parity, bits, flow); } -extern struct uart_driver serial21285_reg; +static struct uart_driver serial21285_reg; static struct console serial21285_console = { diff --git a/drivers/serial/amba-pl010.c b/drivers/serial/amba-pl010.c index 978e124..679e678 100644 --- a/drivers/serial/amba-pl010.c +++ b/drivers/serial/amba-pl010.c @@ -689,7 +689,7 @@ static int __init pl010_console_setup(struct console *co, char *options) return uart_set_options(port, co, baud, parity, bits, flow); } -extern struct uart_driver amba_reg; +static struct uart_driver amba_reg; static struct console amba_console = { .name = "ttyAM", .write = pl010_console_write, diff --git a/drivers/serial/amba-pl011.c b/drivers/serial/amba-pl011.c index 5607130..1ff629c 100644 --- a/drivers/serial/amba-pl011.c +++ b/drivers/serial/amba-pl011.c @@ -701,7 +701,7 @@ static int __init pl011_console_setup(struct console *co, char *options) return uart_set_options(&uap->port, co, baud, parity, bits, flow); } -extern struct uart_driver amba_reg; +static struct uart_driver amba_reg; static struct console amba_console = { .name = "ttyAMA", .write = pl011_console_write, diff --git a/drivers/serial/clps711x.c b/drivers/serial/clps711x.c index d822896..78c1f36 100644 --- a/drivers/serial/clps711x.c +++ b/drivers/serial/clps711x.c @@ -525,7 +525,7 @@ static int __init clps711xuart_console_setup(struct console *co, char *options) return uart_set_options(port, co, baud, parity, bits, flow); } -extern struct uart_driver clps711x_reg; +static struct uart_driver clps711x_reg; static struct console clps711x_console = { .name = "ttyCL", .write = clps711xuart_console_write, diff --git a/drivers/serial/mpc52xx_uart.c b/drivers/serial/mpc52xx_uart.c index a3cd0ee..0585ab2 100644 --- a/drivers/serial/mpc52xx_uart.c +++ b/drivers/serial/mpc52xx_uart.c @@ -781,7 +781,7 @@ mpc52xx_uart_remove(struct device *dev) #ifdef CONFIG_PM static int -mpc52xx_uart_suspend(struct device *dev, u32 state, u32 level) +mpc52xx_uart_suspend(struct device *dev, pm_message_t state, u32 level) { struct uart_port *port = (struct uart_port *) dev_get_drvdata(dev); diff --git a/drivers/serial/pxa.c b/drivers/serial/pxa.c index eaa0af8..672b359 100644 --- a/drivers/serial/pxa.c +++ b/drivers/serial/pxa.c @@ -589,8 +589,8 @@ serial_pxa_type(struct uart_port *port) #ifdef CONFIG_SERIAL_PXA_CONSOLE -extern struct uart_pxa_port serial_pxa_ports[]; -extern struct uart_driver serial_pxa_reg; +static struct uart_pxa_port serial_pxa_ports[]; +static struct uart_driver serial_pxa_reg; #define BOTH_EMPTY (UART_LSR_TEMT | UART_LSR_THRE) diff --git a/drivers/serial/sa1100.c b/drivers/serial/sa1100.c index 1225b14..dd8aed2 100644 --- a/drivers/serial/sa1100.c +++ b/drivers/serial/sa1100.c @@ -799,7 +799,7 @@ sa1100_console_setup(struct console *co, char *options) return uart_set_options(&sport->port, co, baud, parity, bits, flow); } -extern struct uart_driver sa1100_reg; +static struct uart_driver sa1100_reg; static struct console sa1100_console = { .name = "ttySA", .write = sa1100_console_write, diff --git a/drivers/serial/serial_lh7a40x.c b/drivers/serial/serial_lh7a40x.c index 8302376..d01dbe5 100644 --- a/drivers/serial/serial_lh7a40x.c +++ b/drivers/serial/serial_lh7a40x.c @@ -632,7 +632,7 @@ static int __init lh7a40xuart_console_setup (struct console* co, char* options) return uart_set_options (port, co, baud, parity, bits, flow); } -extern struct uart_driver lh7a40x_reg; +static struct uart_driver lh7a40x_reg; static struct console lh7a40x_console = { .name = "ttyAM", .write = lh7a40xuart_console_write, diff --git a/drivers/tc/zs.c b/drivers/tc/zs.c index 4382ee6..6bed871 100644 --- a/drivers/tc/zs.c +++ b/drivers/tc/zs.c @@ -1683,7 +1683,7 @@ static void __init probe_sccs(void) #ifndef CONFIG_SERIAL_DEC_CONSOLE /* * We're called early and memory managment isn't up, yet. - * Thus check_region would fail. + * Thus request_region would fail. */ if (!request_region((unsigned long) zs_channels[n_channels].control, diff --git a/drivers/usb/core/message.c b/drivers/usb/core/message.c index c47c8052..f1fb67f 100644 --- a/drivers/usb/core/message.c +++ b/drivers/usb/core/message.c @@ -987,7 +987,7 @@ void usb_disable_device(struct usb_device *dev, int skip_ep0) /* remove this interface if it has been registered */ interface = dev->actconfig->interface[i]; - if (!klist_node_attached(&interface->dev.knode_bus)) + if (!device_is_registered(&interface->dev)) continue; dev_dbg (&dev->dev, "unregistering interface %s\n", interface->dev.bus_id); diff --git a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c index 087af73..7d13150 100644 --- a/drivers/usb/core/usb.c +++ b/drivers/usb/core/usb.c @@ -303,7 +303,7 @@ int usb_driver_claim_interface(struct usb_driver *driver, /* if interface was already added, bind now; else let * the future device_add() bind it, bypassing probe() */ - if (klist_node_attached(&dev->knode_bus)) + if (device_is_registered(dev)) device_bind_driver(dev); return 0; @@ -336,8 +336,8 @@ void usb_driver_release_interface(struct usb_driver *driver, if (iface->condition != USB_INTERFACE_BOUND) return; - /* release only after device_add() */ - if (klist_node_attached(&dev->knode_bus)) { + /* don't release if the interface hasn't been added yet */ + if (device_is_registered(dev)) { iface->condition = USB_INTERFACE_UNBINDING; device_release_driver(dev); } diff --git a/drivers/usb/gadget/pxa2xx_udc.c b/drivers/usb/gadget/pxa2xx_udc.c index 1507738..73f8c94 100644 --- a/drivers/usb/gadget/pxa2xx_udc.c +++ b/drivers/usb/gadget/pxa2xx_udc.c @@ -422,7 +422,7 @@ static inline void ep0_idle (struct pxa2xx_udc *dev) } static int -write_packet(volatile u32 *uddr, struct pxa2xx_request *req, unsigned max) +write_packet(volatile unsigned long *uddr, struct pxa2xx_request *req, unsigned max) { u8 *buf; unsigned length, count; @@ -2602,7 +2602,7 @@ static int __exit pxa2xx_udc_remove(struct device *_dev) * VBUS IRQs should probably be ignored so that the PXA device just acts * "dead" to USB hosts until system resume. */ -static int pxa2xx_udc_suspend(struct device *dev, u32 state, u32 level) +static int pxa2xx_udc_suspend(struct device *dev, pm_message_t state, u32 level) { struct pxa2xx_udc *udc = dev_get_drvdata(dev); diff --git a/drivers/usb/gadget/pxa2xx_udc.h b/drivers/usb/gadget/pxa2xx_udc.h index d0bc396..a58f3e6 100644 --- a/drivers/usb/gadget/pxa2xx_udc.h +++ b/drivers/usb/gadget/pxa2xx_udc.h @@ -69,11 +69,11 @@ struct pxa2xx_ep { * UDDR = UDC Endpoint Data Register (the fifo) * DRCM = DMA Request Channel Map */ - volatile u32 *reg_udccs; - volatile u32 *reg_ubcr; - volatile u32 *reg_uddr; + volatile unsigned long *reg_udccs; + volatile unsigned long *reg_ubcr; + volatile unsigned long *reg_uddr; #ifdef USE_DMA - volatile u32 *reg_drcmr; + volatile unsigned long *reg_drcmr; #define drcmr(n) .reg_drcmr = & DRCMR ## n , #else #define drcmr(n) diff --git a/drivers/usb/host/sl811-hcd.c b/drivers/usb/host/sl811-hcd.c index d2a1fd4..d42a15d 100644 --- a/drivers/usb/host/sl811-hcd.c +++ b/drivers/usb/host/sl811-hcd.c @@ -782,6 +782,9 @@ retry: /* usb 1.1 says max 90% of a frame is available for periodic transfers. * this driver doesn't promise that much since it's got to handle an * IRQ per packet; irq handling latencies also use up that time. + * + * NOTE: the periodic schedule is a sparse tree, with the load for + * each branch minimized. see fig 3.5 in the OHCI spec for example. */ #define MAX_PERIODIC_LOAD 500 /* out of 1000 usec */ @@ -843,6 +846,7 @@ static int sl811h_urb_enqueue( if (!(sl811->port1 & (1 << USB_PORT_FEAT_ENABLE)) || !HC_IS_RUNNING(hcd->state)) { retval = -ENODEV; + kfree(ep); goto fail; } @@ -911,8 +915,16 @@ static int sl811h_urb_enqueue( case PIPE_ISOCHRONOUS: case PIPE_INTERRUPT: urb->interval = ep->period; - if (ep->branch < PERIODIC_SIZE) + if (ep->branch < PERIODIC_SIZE) { + /* NOTE: the phase is correct here, but the value + * needs offsetting by the transfer queue depth. + * All current drivers ignore start_frame, so this + * is unlikely to ever matter... + */ + urb->start_frame = (sl811->frame & (PERIODIC_SIZE - 1)) + + ep->branch; break; + } retval = balance(sl811, ep->period, ep->load); if (retval < 0) @@ -1122,7 +1134,7 @@ sl811h_hub_descriptor ( desc->wHubCharacteristics = (__force __u16)cpu_to_le16(temp); /* two bitmaps: ports removable, and legacy PortPwrCtrlMask */ - desc->bitmap[0] = 1 << 1; + desc->bitmap[0] = 0 << 1; desc->bitmap[1] = ~0; } diff --git a/drivers/usb/net/pegasus.c b/drivers/usb/net/pegasus.c index 7484d34..6a4ffe6 100644 --- a/drivers/usb/net/pegasus.c +++ b/drivers/usb/net/pegasus.c @@ -648,6 +648,13 @@ static void read_bulk_callback(struct urb *urb, struct pt_regs *regs) } /* + * If the packet is unreasonably long, quietly drop it rather than + * kernel panicing by calling skb_put. + */ + if (pkt_len > PEGASUS_MTU) + goto goon; + + /* * at this point we are sure pegasus->rx_skb != NULL * so we go ahead and pass up the packet. */ @@ -886,15 +893,17 @@ static inline void get_interrupt_interval(pegasus_t * pegasus) __u8 data[2]; read_eprom_word(pegasus, 4, (__u16 *) data); - if (data[1] < 0x80) { - if (netif_msg_timer(pegasus)) - dev_info(&pegasus->intf->dev, - "intr interval changed from %ums to %ums\n", - data[1], 0x80); - data[1] = 0x80; -#ifdef PEGASUS_WRITE_EEPROM - write_eprom_word(pegasus, 4, *(__u16 *) data); + if (pegasus->usb->speed != USB_SPEED_HIGH) { + if (data[1] < 0x80) { + if (netif_msg_timer(pegasus)) + dev_info(&pegasus->intf->dev, "intr interval " + "changed from %ums to %ums\n", + data[1], 0x80); + data[1] = 0x80; +#ifdef PEGASUS_WRITE_EEPROM + write_eprom_word(pegasus, 4, *(__u16 *) data); #endif + } } pegasus->intr_interval = data[1]; } @@ -904,8 +913,9 @@ 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) netif_carrier_on(net); else @@ -1355,6 +1365,7 @@ static void pegasus_disconnect(struct usb_interface *intf) cancel_delayed_work(&pegasus->carrier_check); unregister_netdev(pegasus->net); usb_put_dev(interface_to_usbdev(intf)); + unlink_all_urbs(pegasus); free_all_urbs(pegasus); free_skb_pool(pegasus); if (pegasus->rx_skb) diff --git a/drivers/usb/serial/airprime.c b/drivers/usb/serial/airprime.c index a4ce000..926d4c2 100644 --- a/drivers/usb/serial/airprime.c +++ b/drivers/usb/serial/airprime.c @@ -16,7 +16,8 @@ #include "usb-serial.h" static struct usb_device_id id_table [] = { - { USB_DEVICE(0xf3d, 0x0112) }, + { USB_DEVICE(0xf3d, 0x0112) }, /* AirPrime CDMA Wireless PC Card */ + { USB_DEVICE(0x1410, 0x1110) }, /* Novatel Wireless Merlin CDMA */ { }, }; MODULE_DEVICE_TABLE(usb, id_table); diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c index 4e434cb..5a8631c 100644 --- a/drivers/usb/serial/ftdi_sio.c +++ b/drivers/usb/serial/ftdi_sio.c @@ -1846,10 +1846,12 @@ static void ftdi_set_termios (struct usb_serial_port *port, struct termios *old_ } else { /* set the baudrate determined before */ if (change_speed(port)) { - err("%s urb failed to set baurdrate", __FUNCTION__); + err("%s urb failed to set baudrate", __FUNCTION__); + } + /* Ensure RTS and DTR are raised when baudrate changed from 0 */ + if ((old_termios->c_cflag & CBAUD) == B0) { + set_mctrl(port, TIOCM_DTR | TIOCM_RTS); } - /* Ensure RTS and DTR are raised */ - set_mctrl(port, TIOCM_DTR | TIOCM_RTS); } /* Set flow control */ diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c index 92d0f925d..4989e57 100644 --- a/drivers/usb/serial/option.c +++ b/drivers/usb/serial/option.c @@ -25,6 +25,9 @@ 2005-06-20 v0.4.1 add missing braces :-/ killed end-of-line whitespace 2005-07-15 v0.4.2 rename WLAN product to FUSION, add FUSION2 + 2005-09-10 v0.4.3 added HUAWEI E600 card and Audiovox AirCard + 2005-09-20 v0.4.4 increased recv buffer size: the card sometimes + wants to send >2000 bytes. Work sponsored by: Sigos GmbH, Germany <info@sigos.de> @@ -71,15 +74,21 @@ static int option_send_setup(struct usb_serial_port *port); /* Vendor and product IDs */ #define OPTION_VENDOR_ID 0x0AF0 +#define HUAWEI_VENDOR_ID 0x12D1 +#define AUDIOVOX_VENDOR_ID 0x0F3D #define OPTION_PRODUCT_OLD 0x5000 #define OPTION_PRODUCT_FUSION 0x6000 #define OPTION_PRODUCT_FUSION2 0x6300 +#define HUAWEI_PRODUCT_E600 0x1001 +#define AUDIOVOX_PRODUCT_AIRCARD 0x0112 static struct usb_device_id option_ids[] = { { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_OLD) }, { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_FUSION) }, { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_FUSION2) }, + { USB_DEVICE(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E600) }, + { USB_DEVICE(AUDIOVOX_VENDOR_ID, AUDIOVOX_PRODUCT_AIRCARD) }, { } /* Terminating entry */ }; @@ -132,7 +141,7 @@ static int debug; #define N_IN_URB 4 #define N_OUT_URB 1 -#define IN_BUFLEN 1024 +#define IN_BUFLEN 4096 #define OUT_BUFLEN 128 struct option_port_private { diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig index 615874e..773ae11 100644 --- a/drivers/video/Kconfig +++ b/drivers/video/Kconfig @@ -650,6 +650,7 @@ config FB_NVIDIA select FB_CFB_FILLRECT select FB_CFB_COPYAREA select FB_CFB_IMAGEBLIT + select FB_SOFT_CURSOR help This driver supports graphics boards with the nVidia chips, TNT and newer. For very old chipsets, such as the RIVA128, then use @@ -753,7 +754,8 @@ config FB_I810_GTF config FB_I810_I2C bool "Enable DDC Support" - depends on FB_I810 && I2C && FB_I810_GTF + depends on FB_I810 && FB_I810_GTF + select I2C select I2C_ALGOBIT help diff --git a/drivers/video/aty/xlinit.c b/drivers/video/aty/xlinit.c index 92643af..a085cbf 100644 --- a/drivers/video/aty/xlinit.c +++ b/drivers/video/aty/xlinit.c @@ -174,7 +174,7 @@ int atyfb_xl_init(struct fb_info *info) const struct xl_card_cfg_t * card = &card_cfg[xl_card]; struct atyfb_par *par = (struct atyfb_par *) info->par; union aty_pll pll; - int i, err; + int err; u32 temp; aty_st_8(CONFIG_STAT0, 0x85, par); @@ -252,9 +252,14 @@ int atyfb_xl_init(struct fb_info *info) aty_st_le32(0xEC, 0x00000000, par); aty_st_le32(0xFC, 0x00000000, par); - for (i=0; i<sizeof(lcd_tbl)/sizeof(lcd_tbl_t); i++) { - aty_st_lcd(lcd_tbl[i].lcd_reg, lcd_tbl[i].val, par); +#if defined (CONFIG_FB_ATY_GENERIC_LCD) + { + int i; + + for (i = 0; i < ARRAY_SIZE(lcd_tbl); i++) + aty_st_lcd(lcd_tbl[i].lcd_reg, lcd_tbl[i].val, par); } +#endif aty_st_le16(CONFIG_STAT0, 0x00A4, par); mdelay(10); diff --git a/drivers/video/backlight/corgi_bl.c b/drivers/video/backlight/corgi_bl.c index 353cb3f..630f2df 100644 --- a/drivers/video/backlight/corgi_bl.c +++ b/drivers/video/backlight/corgi_bl.c @@ -19,17 +19,18 @@ #include <linux/fb.h> #include <linux/backlight.h> -#include <asm/arch-pxa/corgi.h> -#include <asm/hardware/scoop.h> +#include <asm/mach-types.h> +#include <asm/arch/sharpsl.h> -#define CORGI_MAX_INTENSITY 0x3e #define CORGI_DEFAULT_INTENSITY 0x1f -#define CORGI_LIMIT_MASK 0x0b +#define CORGI_LIMIT_MASK 0x0b static int corgibl_powermode = FB_BLANK_UNBLANK; static int current_intensity = 0; static int corgibl_limit = 0; +static void (*corgibl_mach_set_intensity)(int intensity); static spinlock_t bl_lock = SPIN_LOCK_UNLOCKED; +static struct backlight_properties corgibl_data; static void corgibl_send_intensity(int intensity) { @@ -43,18 +44,10 @@ static void corgibl_send_intensity(int intensity) intensity &= CORGI_LIMIT_MASK; } - /* Skip 0x20 as it will blank the display */ - if (intensity >= 0x20) - intensity++; - spin_lock_irqsave(&bl_lock, flags); - /* Bits 0-4 are accessed via the SSP interface */ - corgi_ssp_blduty_set(intensity & 0x1f); - /* Bit 5 is via SCOOP */ - if (intensity & 0x0020) - set_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_BACKLIGHT_CONT); - else - reset_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_BACKLIGHT_CONT); + + corgibl_mach_set_intensity(intensity); + spin_unlock_irqrestore(&bl_lock, flags); } @@ -113,8 +106,8 @@ static int corgibl_get_power(struct backlight_device *bd) static int corgibl_set_intensity(struct backlight_device *bd, int intensity) { - if (intensity > CORGI_MAX_INTENSITY) - intensity = CORGI_MAX_INTENSITY; + if (intensity > corgibl_data.max_brightness) + intensity = corgibl_data.max_brightness; corgibl_send_intensity(intensity); current_intensity=intensity; return 0; @@ -141,7 +134,6 @@ static struct backlight_properties corgibl_data = { .owner = THIS_MODULE, .get_power = corgibl_get_power, .set_power = corgibl_set_power, - .max_brightness = CORGI_MAX_INTENSITY, .get_brightness = corgibl_get_intensity, .set_brightness = corgibl_set_intensity, }; @@ -150,12 +142,18 @@ static struct backlight_device *corgi_backlight_device; static int __init corgibl_probe(struct device *dev) { + struct corgibl_machinfo *machinfo = dev->platform_data; + + corgibl_data.max_brightness = machinfo->max_intensity; + corgibl_mach_set_intensity = machinfo->set_bl_intensity; + corgi_backlight_device = backlight_device_register ("corgi-bl", NULL, &corgibl_data); if (IS_ERR (corgi_backlight_device)) return PTR_ERR (corgi_backlight_device); corgibl_set_intensity(NULL, CORGI_DEFAULT_INTENSITY); + corgibl_limit_intensity(0); printk("Corgi Backlight Driver Initialized.\n"); return 0; diff --git a/drivers/video/console/fbcon.c b/drivers/video/console/fbcon.c index 2e93224..0fc8bb4 100644 --- a/drivers/video/console/fbcon.c +++ b/drivers/video/console/fbcon.c @@ -767,7 +767,7 @@ static const char *fbcon_startup(void) const char *display_desc = "frame buffer device"; struct display *p = &fb_display[fg_console]; struct vc_data *vc = vc_cons[fg_console].d; - struct font_desc *font = NULL; + const struct font_desc *font = NULL; struct module *owner; struct fb_info *info = NULL; struct fbcon_ops *ops; @@ -841,7 +841,7 @@ static const char *fbcon_startup(void) info->var.yres); vc->vc_font.width = font->width; vc->vc_font.height = font->height; - vc->vc_font.data = p->fontdata = font->data; + vc->vc_font.data = (void *)(p->fontdata = font->data); vc->vc_font.charcount = 256; /* FIXME Need to support more fonts */ } @@ -941,7 +941,7 @@ static void fbcon_init(struct vc_data *vc, int init) fb, copy the font from that console */ t = &fb_display[svc->vc_num]; if (!vc->vc_font.data) { - vc->vc_font.data = p->fontdata = t->fontdata; + vc->vc_font.data = (void *)(p->fontdata = t->fontdata); vc->vc_font.width = (*default_mode)->vc_font.width; vc->vc_font.height = (*default_mode)->vc_font.height; p->userfont = t->userfont; @@ -1188,7 +1188,7 @@ static void fbcon_set_disp(struct fb_info *info, struct fb_var_screeninfo *var, return; t = &fb_display[svc->vc_num]; if (!vc->vc_font.data) { - vc->vc_font.data = p->fontdata = t->fontdata; + vc->vc_font.data = (void *)(p->fontdata = t->fontdata); vc->vc_font.width = (*default_mode)->vc_font.width; vc->vc_font.height = (*default_mode)->vc_font.height; p->userfont = t->userfont; @@ -1687,6 +1687,8 @@ static int fbcon_scroll(struct vc_data *vc, int t, int b, int dir, case SM_DOWN: if (count > vc->vc_rows) /* Maximum realistic size */ count = vc->vc_rows; + if (logo_shown >= 0) + goto redraw_down; switch (p->scrollmode) { case SCROLL_MOVE: ops->bmove(vc, info, t, 0, t + count, 0, @@ -2148,7 +2150,7 @@ static int fbcon_get_font(struct vc_data *vc, struct console_font *font) } static int fbcon_do_set_font(struct vc_data *vc, int w, int h, - u8 * data, int userfont) + const u8 * data, int userfont) { struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]]; struct display *p = &fb_display[vc->vc_num]; @@ -2166,7 +2168,7 @@ static int fbcon_do_set_font(struct vc_data *vc, int w, int h, cnt = FNTCHARCNT(data); else cnt = 256; - vc->vc_font.data = p->fontdata = data; + vc->vc_font.data = (void *)(p->fontdata = data); if ((p->userfont = userfont)) REFCOUNT(data)++; vc->vc_font.width = w; @@ -2323,7 +2325,7 @@ static int fbcon_set_font(struct vc_data *vc, struct console_font *font, unsigne tmp->vc_font.width == w && !memcmp(fb_display[i].fontdata, new_data, size)) { kfree(new_data - FONT_EXTRA_WORDS * sizeof(int)); - new_data = fb_display[i].fontdata; + new_data = (u8 *)fb_display[i].fontdata; break; } } @@ -2333,7 +2335,7 @@ static int fbcon_set_font(struct vc_data *vc, struct console_font *font, unsigne static int fbcon_set_def_font(struct vc_data *vc, struct console_font *font, char *name) { struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]]; - struct font_desc *f; + const struct font_desc *f; if (!name) f = get_default_font(info->var.xres, info->var.yres); diff --git a/drivers/video/console/fbcon.h b/drivers/video/console/fbcon.h index 08befaf..0738cd6 100644 --- a/drivers/video/console/fbcon.h +++ b/drivers/video/console/fbcon.h @@ -30,7 +30,7 @@ struct display { /* Filled in by the frame buffer device */ u_short inverse; /* != 0 text black on white as default */ /* Filled in by the low-level console driver */ - u_char *fontdata; + const u_char *fontdata; int userfont; /* != 0 if fontdata kmalloc()ed */ u_short scrollmode; /* Scroll Method */ short yscroll; /* Hardware scrolling */ diff --git a/drivers/video/console/font_10x18.c b/drivers/video/console/font_10x18.c index ff0af96..e6aa0ea 100644 --- a/drivers/video/console/font_10x18.c +++ b/drivers/video/console/font_10x18.c @@ -7,7 +7,7 @@ #define FONTDATAMAX 9216 -static unsigned char fontdata_10x18[FONTDATAMAX] = { +static const unsigned char fontdata_10x18[FONTDATAMAX] = { /* 0 0x00 '^@' */ 0x00, 0x00, /* 0000000000 */ @@ -5132,7 +5132,7 @@ static unsigned char fontdata_10x18[FONTDATAMAX] = { }; -struct font_desc font_10x18 = { +const struct font_desc font_10x18 = { FONT10x18_IDX, "10x18", 10, diff --git a/drivers/video/console/font_6x11.c b/drivers/video/console/font_6x11.c index c52f129..89976cd 100644 --- a/drivers/video/console/font_6x11.c +++ b/drivers/video/console/font_6x11.c @@ -8,7 +8,7 @@ #define FONTDATAMAX (11*256) -static unsigned char fontdata_6x11[FONTDATAMAX] = { +static const unsigned char fontdata_6x11[FONTDATAMAX] = { /* 0 0x00 '^@' */ 0x00, /* 00000000 */ @@ -3341,7 +3341,7 @@ static unsigned char fontdata_6x11[FONTDATAMAX] = { }; -struct font_desc font_vga_6x11 = { +const struct font_desc font_vga_6x11 = { VGA6x11_IDX, "ProFont6x11", 6, diff --git a/drivers/video/console/font_7x14.c b/drivers/video/console/font_7x14.c index 1fa7fcf..bbf1166 100644 --- a/drivers/video/console/font_7x14.c +++ b/drivers/video/console/font_7x14.c @@ -7,7 +7,7 @@ #define FONTDATAMAX 3584 -static unsigned char fontdata_7x14[FONTDATAMAX] = { +static const unsigned char fontdata_7x14[FONTDATAMAX] = { /* 0 0x00 '^@' */ 0x00, /* 0000000 */ @@ -4108,7 +4108,7 @@ static unsigned char fontdata_7x14[FONTDATAMAX] = { }; -struct font_desc font_7x14 = { +const struct font_desc font_7x14 = { FONT7x14_IDX, "7x14", 7, diff --git a/drivers/video/console/font_8x16.c b/drivers/video/console/font_8x16.c index e6f8dba..74fe86f 100644 --- a/drivers/video/console/font_8x16.c +++ b/drivers/video/console/font_8x16.c @@ -8,7 +8,7 @@ #define FONTDATAMAX 4096 -static unsigned char fontdata_8x16[FONTDATAMAX] = { +static const unsigned char fontdata_8x16[FONTDATAMAX] = { /* 0 0x00 '^@' */ 0x00, /* 00000000 */ @@ -4621,7 +4621,7 @@ static unsigned char fontdata_8x16[FONTDATAMAX] = { }; -struct font_desc font_vga_8x16 = { +const struct font_desc font_vga_8x16 = { VGA8x16_IDX, "VGA8x16", 8, diff --git a/drivers/video/console/font_8x8.c b/drivers/video/console/font_8x8.c index 57fbe26..26199f8 100644 --- a/drivers/video/console/font_8x8.c +++ b/drivers/video/console/font_8x8.c @@ -8,7 +8,7 @@ #define FONTDATAMAX 2048 -static unsigned char fontdata_8x8[FONTDATAMAX] = { +static const unsigned char fontdata_8x8[FONTDATAMAX] = { /* 0 0x00 '^@' */ 0x00, /* 00000000 */ @@ -2573,7 +2573,7 @@ static unsigned char fontdata_8x8[FONTDATAMAX] = { }; -struct font_desc font_vga_8x8 = { +const struct font_desc font_vga_8x8 = { VGA8x8_IDX, "VGA8x8", 8, diff --git a/drivers/video/console/font_acorn_8x8.c b/drivers/video/console/font_acorn_8x8.c index d565505..2d2e396 100644 --- a/drivers/video/console/font_acorn_8x8.c +++ b/drivers/video/console/font_acorn_8x8.c @@ -3,7 +3,7 @@ #include <linux/config.h> #include <linux/font.h> -static unsigned char acorndata_8x8[] = { +static const unsigned char acorndata_8x8[] = { /* 00 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ^@ */ /* 01 */ 0x7e, 0x81, 0xa5, 0x81, 0xbd, 0x99, 0x81, 0x7e, /* ^A */ /* 02 */ 0x7e, 0xff, 0xbd, 0xff, 0xc3, 0xe7, 0xff, 0x7e, /* ^B */ @@ -262,7 +262,7 @@ static unsigned char acorndata_8x8[] = { /* FF */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; -struct font_desc font_acorn_8x8 = { +const struct font_desc font_acorn_8x8 = { ACORN8x8_IDX, "Acorn8x8", 8, diff --git a/drivers/video/console/font_mini_4x6.c b/drivers/video/console/font_mini_4x6.c index 593b955..d818234 100644 --- a/drivers/video/console/font_mini_4x6.c +++ b/drivers/video/console/font_mini_4x6.c @@ -43,7 +43,7 @@ __END__; #define FONTDATAMAX 1536 -static unsigned char fontdata_mini_4x6[FONTDATAMAX] = { +static const unsigned char fontdata_mini_4x6[FONTDATAMAX] = { /*{*/ /* Char 0: ' ' */ @@ -2147,7 +2147,7 @@ static unsigned char fontdata_mini_4x6[FONTDATAMAX] = { /*}*/ }; -struct font_desc font_mini_4x6 = { +const struct font_desc font_mini_4x6 = { MINI4x6_IDX, "MINI4x6", 4, diff --git a/drivers/video/console/font_pearl_8x8.c b/drivers/video/console/font_pearl_8x8.c index 5fa95f1..e646c88 100644 --- a/drivers/video/console/font_pearl_8x8.c +++ b/drivers/video/console/font_pearl_8x8.c @@ -13,7 +13,7 @@ #define FONTDATAMAX 2048 -static unsigned char fontdata_pearl8x8[FONTDATAMAX] = { +static const unsigned char fontdata_pearl8x8[FONTDATAMAX] = { /* 0 0x00 '^@' */ 0x00, /* 00000000 */ @@ -2577,7 +2577,7 @@ static unsigned char fontdata_pearl8x8[FONTDATAMAX] = { }; -struct font_desc font_pearl_8x8 = { +const struct font_desc font_pearl_8x8 = { PEARL8x8_IDX, "PEARL8x8", 8, diff --git a/drivers/video/console/font_sun12x22.c b/drivers/video/console/font_sun12x22.c index c7bd967..ab5eb93 100644 --- a/drivers/video/console/font_sun12x22.c +++ b/drivers/video/console/font_sun12x22.c @@ -2,7 +2,7 @@ #define FONTDATAMAX 11264 -static unsigned char fontdata_sun12x22[FONTDATAMAX] = { +static const unsigned char fontdata_sun12x22[FONTDATAMAX] = { /* 0 0x00 '^@' */ 0x00, 0x00, /* 000000000000 */ @@ -6151,7 +6151,7 @@ static unsigned char fontdata_sun12x22[FONTDATAMAX] = { }; -struct font_desc font_sun_12x22 = { +const struct font_desc font_sun_12x22 = { SUN12x22_IDX, "SUN12x22", 12, diff --git a/drivers/video/console/font_sun8x16.c b/drivers/video/console/font_sun8x16.c index 2af3ab3..41f910f 100644 --- a/drivers/video/console/font_sun8x16.c +++ b/drivers/video/console/font_sun8x16.c @@ -2,7 +2,7 @@ #define FONTDATAMAX 4096 -static unsigned char fontdata_sun8x16[FONTDATAMAX] = { +static const unsigned char fontdata_sun8x16[FONTDATAMAX] = { /* */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* */ 0x00,0x00,0x7e,0x81,0xa5,0x81,0x81,0xbd,0x99,0x81,0x81,0x7e,0x00,0x00,0x00,0x00, /* */ 0x00,0x00,0x7e,0xff,0xdb,0xff,0xff,0xc3,0xe7,0xff,0xff,0x7e,0x00,0x00,0x00,0x00, @@ -261,7 +261,7 @@ static unsigned char fontdata_sun8x16[FONTDATAMAX] = { /* */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, }; -struct font_desc font_sun_8x16 = { +const struct font_desc font_sun_8x16 = { SUN8x16_IDX, "SUN8x16", 8, diff --git a/drivers/video/console/fonts.c b/drivers/video/console/fonts.c index e79b297..4fd07d9 100644 --- a/drivers/video/console/fonts.c +++ b/drivers/video/console/fonts.c @@ -23,7 +23,7 @@ #define NO_FONTS -static struct font_desc *fonts[] = { +static const struct font_desc *fonts[] = { #ifdef CONFIG_FONT_8x8 #undef NO_FONTS &font_vga_8x8, @@ -84,7 +84,7 @@ static struct font_desc *fonts[] = { * */ -struct font_desc *find_font(char *name) +const struct font_desc *find_font(const char *name) { unsigned int i; @@ -108,10 +108,10 @@ struct font_desc *find_font(char *name) * */ -struct font_desc *get_default_font(int xres, int yres) +const struct font_desc *get_default_font(int xres, int yres) { int i, c, cc; - struct font_desc *f, *g; + const struct font_desc *f, *g; g = NULL; cc = -10000; @@ -138,7 +138,6 @@ struct font_desc *get_default_font(int xres, int yres) return g; } -EXPORT_SYMBOL(fonts); EXPORT_SYMBOL(find_font); EXPORT_SYMBOL(get_default_font); diff --git a/drivers/video/console/vgacon.c b/drivers/video/console/vgacon.c index 0705cd7..6ef6f77 100644 --- a/drivers/video/console/vgacon.c +++ b/drivers/video/console/vgacon.c @@ -1020,7 +1020,9 @@ static int vgacon_font_get(struct vc_data *c, struct console_font *font) static int vgacon_resize(struct vc_data *c, unsigned int width, unsigned int height) { - if (width % 2 || width > ORIG_VIDEO_COLS || height > ORIG_VIDEO_LINES) + if (width % 2 || width > ORIG_VIDEO_COLS || + height > (ORIG_VIDEO_LINES * vga_default_font_height)/ + c->vc_font.height) return -EINVAL; if (CON_IS_VISIBLE(c) && !vga_is_gfx) /* who knows */ diff --git a/drivers/video/fbcvt.c b/drivers/video/fbcvt.c index cfa61b5..0b6af00 100644 --- a/drivers/video/fbcvt.c +++ b/drivers/video/fbcvt.c @@ -272,11 +272,11 @@ static void fb_cvt_convert_to_mode(struct fb_cvt_data *cvt, { mode->refresh = cvt->f_refresh; mode->pixclock = KHZ2PICOS(cvt->pixclock/1000); - mode->left_margin = cvt->h_front_porch; - mode->right_margin = cvt->h_back_porch; + mode->left_margin = cvt->h_back_porch; + mode->right_margin = cvt->h_front_porch; mode->hsync_len = cvt->hsync; - mode->upper_margin = cvt->v_front_porch; - mode->lower_margin = cvt->v_back_porch; + mode->upper_margin = cvt->v_back_porch; + mode->lower_margin = cvt->v_front_porch; mode->vsync_len = cvt->vsync; mode->sync &= ~(FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT); diff --git a/drivers/video/imxfb.c b/drivers/video/imxfb.c index cabd53c..6c2244c 100644 --- a/drivers/video/imxfb.c +++ b/drivers/video/imxfb.c @@ -425,7 +425,7 @@ static void imxfb_setup_gpio(struct imxfb_info *fbi) * Power management hooks. Note that we won't be called from IRQ context, * unlike the blank functions above, so we may sleep. */ -static int imxfb_suspend(struct device *dev, u32 state, u32 level) +static int imxfb_suspend(struct device *dev, pm_message_t state, u32 level) { struct imxfb_info *fbi = dev_get_drvdata(dev); pr_debug("%s\n",__FUNCTION__); diff --git a/drivers/video/matrox/matroxfb_base.c b/drivers/video/matrox/matroxfb_base.c index 98e00d8..e02da41 100644 --- a/drivers/video/matrox/matroxfb_base.c +++ b/drivers/video/matrox/matroxfb_base.c @@ -1285,7 +1285,7 @@ static int matroxfb_getmemory(WPMINFO unsigned int maxSize, unsigned int *realSi vaddr_t vm; unsigned int offs; unsigned int offs2; - unsigned char store; + unsigned char store, orig; unsigned char bytes[32]; unsigned char* tmp; @@ -1298,7 +1298,8 @@ static int matroxfb_getmemory(WPMINFO unsigned int maxSize, unsigned int *realSi if (maxSize > 0x2000000) maxSize = 0x2000000; mga_outb(M_EXTVGA_INDEX, 0x03); - mga_outb(M_EXTVGA_DATA, mga_inb(M_EXTVGA_DATA) | 0x80); + orig = mga_inb(M_EXTVGA_DATA); + mga_outb(M_EXTVGA_DATA, orig | 0x80); store = mga_readb(vm, 0x1234); tmp = bytes; @@ -1323,7 +1324,7 @@ static int matroxfb_getmemory(WPMINFO unsigned int maxSize, unsigned int *realSi mga_writeb(vm, 0x1234, store); mga_outb(M_EXTVGA_INDEX, 0x03); - mga_outb(M_EXTVGA_DATA, mga_inb(M_EXTVGA_DATA) & ~0x80); + mga_outb(M_EXTVGA_DATA, orig); *realSize = offs - 0x100000; #ifdef CONFIG_FB_MATROX_MILLENIUM @@ -1858,6 +1859,8 @@ static int initMatrox2(WPMINFO struct board* b){ to yres_virtual * xres_virtual < 2^32 */ } matroxfb_init_fix(PMINFO2); + ACCESS_FBINFO(fbcon.screen_base) = vaddr_va(ACCESS_FBINFO(video.vbase)); + matroxfb_update_fix(PMINFO2); /* Normalize values (namely yres_virtual) */ matroxfb_check_var(&vesafb_defined, &ACCESS_FBINFO(fbcon)); /* And put it into "current" var. Do NOT program hardware yet, or we'll not take over @@ -2010,11 +2013,11 @@ static int matroxfb_probe(struct pci_dev* pdev, const struct pci_device_id* dumm } /* not match... */ if (!b->vendor) - return -1; + return -ENODEV; if (dev > 0) { /* not requested one... */ dev--; - return -1; + return -ENODEV; } pci_read_config_dword(pdev, PCI_COMMAND, &cmd); if (pci_enable_device(pdev)) { diff --git a/drivers/video/nvidia/nv_i2c.c b/drivers/video/nvidia/nv_i2c.c index ace484f..12f2884 100644 --- a/drivers/video/nvidia/nv_i2c.c +++ b/drivers/video/nvidia/nv_i2c.c @@ -209,10 +209,13 @@ int nvidia_probe_i2c_connector(struct fb_info *info, int conn, u8 **out_edid) if (!edid && conn == 1) { /* try to get from firmware */ - edid = kmalloc(EDID_LENGTH, GFP_KERNEL); - if (edid) - memcpy(edid, fb_firmware_edid(info->device), - EDID_LENGTH); + const u8 *e = fb_firmware_edid(info->device); + + if (e != NULL) { + edid = kmalloc(EDID_LENGTH, GFP_KERNEL); + if (edid) + memcpy(edid, e, EDID_LENGTH); + } } if (out_edid) diff --git a/drivers/video/nvidia/nvidia.c b/drivers/video/nvidia/nvidia.c index 3620de0..a7f020a 100644 --- a/drivers/video/nvidia/nvidia.c +++ b/drivers/video/nvidia/nvidia.c @@ -893,7 +893,7 @@ static int nvidiafb_cursor(struct fb_info *info, struct fb_cursor *cursor) int i, set = cursor->set; u16 fg, bg; - if (!hwcur || cursor->image.width > MAX_CURS || cursor->image.height > MAX_CURS) + if (cursor->image.width > MAX_CURS || cursor->image.height > MAX_CURS) return -ENXIO; NVShowHideCursor(par, 0); @@ -1356,6 +1356,9 @@ static int __devinit nvidia_set_fbinfo(struct fb_info *info) info->pixmap.size = 8 * 1024; info->pixmap.flags = FB_PIXMAP_SYSTEM; + if (!hwcur) + info->fbops->fb_cursor = soft_cursor; + info->var.accel_flags = (!noaccel); switch (par->Architecture) { diff --git a/drivers/video/pm3fb.c b/drivers/video/pm3fb.c index e0dad94..2e11b60 100644 --- a/drivers/video/pm3fb.c +++ b/drivers/video/pm3fb.c @@ -67,6 +67,7 @@ #include <linux/init.h> #include <linux/pci.h> #include <linux/ioport.h> +#include <linux/ctype.h> #include <video/fbcon.h> #include <video/fbcon-mfb.h> @@ -2594,7 +2595,7 @@ static char *pm3fb_boardnum_setup(char *options, unsigned long *bn) { char *next; - if (!(CHAR_IS_NUM(options[0]))) { + if (!(isdigit(options[0]))) { (*bn) = 0; return (options); } diff --git a/drivers/video/savage/savagefb-i2c.c b/drivers/video/savage/savagefb-i2c.c index 959404a..3c98457 100644 --- a/drivers/video/savage/savagefb-i2c.c +++ b/drivers/video/savage/savagefb-i2c.c @@ -274,10 +274,13 @@ int savagefb_probe_i2c_connector(struct fb_info *info, u8 **out_edid) if (!edid) { /* try to get from firmware */ - edid = kmalloc(EDID_LENGTH, GFP_KERNEL); - if (edid) - memcpy(edid, fb_firmware_edid(info->device), - EDID_LENGTH); + const u8 *e = fb_firmware_edid(info->device); + + if (e) { + edid = kmalloc(EDID_LENGTH, GFP_KERNEL); + if (edid) + memcpy(edid, e, EDID_LENGTH); + } } if (out_edid) diff --git a/drivers/video/savage/savagefb.h b/drivers/video/savage/savagefb.h index d6f9474..ea17f7e 100644 --- a/drivers/video/savage/savagefb.h +++ b/drivers/video/savage/savagefb.h @@ -60,8 +60,6 @@ #define S3_SAVAGE_SERIES(chip) ((chip>=S3_SAVAGE3D) && (chip<=S3_SAVAGE2000)) -#define S3_MOBILE_TWISTER_SERIES(chip) ((chip==S3_TWISTER) || (chip == S3_PROSAVAGEDDR)) - /* Chip tags. These are used to group the adapters into * related families. */ @@ -74,8 +72,6 @@ typedef enum { S3_PROSAVAGE, S3_SUPERSAVAGE, S3_SAVAGE2000, - S3_PROSAVAGEDDR, - S3_TWISTER, S3_LAST } savage_chipset; diff --git a/drivers/video/savage/savagefb_driver.c b/drivers/video/savage/savagefb_driver.c index b5ca3ef..7c28545 100644 --- a/drivers/video/savage/savagefb_driver.c +++ b/drivers/video/savage/savagefb_driver.c @@ -1773,8 +1773,7 @@ static int __devinit savage_init_hw (struct savagefb_par *par) } } - if (S3_SAVAGE_MOBILE_SERIES(par->chip) || - (S3_MOBILE_TWISTER_SERIES(par->chip) && !par->crtonly)) + if (S3_SAVAGE_MOBILE_SERIES(par->chip) && !par->crtonly) par->display_type = DISP_LCD; else if (dvi || (par->chip == S3_SAVAGE4 && par->dvi)) par->display_type = DISP_DFP; @@ -1783,7 +1782,7 @@ static int __devinit savage_init_hw (struct savagefb_par *par) /* Check LCD panel parrmation */ - if (par->chip == S3_SAVAGE_MX) { + if (par->display_type == DISP_LCD) { unsigned char cr6b = VGArCR( 0x6b ); int panelX = (VGArSEQ (0x61) + @@ -1922,15 +1921,15 @@ static int __devinit savage_init_fb_info (struct fb_info *info, snprintf (info->fix.id, 16, "ProSavageKM"); break; case FB_ACCEL_S3TWISTER_P: - par->chip = S3_TWISTER; + par->chip = S3_PROSAVAGE; snprintf (info->fix.id, 16, "TwisterP"); break; case FB_ACCEL_S3TWISTER_K: - par->chip = S3_TWISTER; + par->chip = S3_PROSAVAGE; snprintf (info->fix.id, 16, "TwisterK"); break; case FB_ACCEL_PROSAVAGE_DDR: - par->chip = S3_PROSAVAGEDDR; + par->chip = S3_PROSAVAGE; snprintf (info->fix.id, 16, "ProSavageDDR"); break; case FB_ACCEL_PROSAVAGE_DDRK: diff --git a/fs/9p/conv.c b/fs/9p/conv.c index 1554731..18121af 100644 --- a/fs/9p/conv.c +++ b/fs/9p/conv.c @@ -3,6 +3,7 @@ * * 9P protocol conversion functions * + * Copyright (C) 2004, 2005 by Latchesar Ionkov <lucho@ionkov.net> * Copyright (C) 2004 by Eric Van Hensbergen <ericvh@gmail.com> * Copyright (C) 2002 by Ron Minnich <rminnich@lanl.gov> * @@ -55,66 +56,70 @@ static inline int buf_check_overflow(struct cbuf *buf) return buf->p > buf->ep; } -static inline void buf_check_size(struct cbuf *buf, int len) +static inline int buf_check_size(struct cbuf *buf, int len) { if (buf->p+len > buf->ep) { if (buf->p < buf->ep) { eprintk(KERN_ERR, "buffer overflow\n"); buf->p = buf->ep + 1; + return 0; } } + + return 1; } static inline void *buf_alloc(struct cbuf *buf, int len) { void *ret = NULL; - buf_check_size(buf, len); - ret = buf->p; - buf->p += len; + if (buf_check_size(buf, len)) { + ret = buf->p; + buf->p += len; + } return ret; } static inline void buf_put_int8(struct cbuf *buf, u8 val) { - buf_check_size(buf, 1); - - buf->p[0] = val; - buf->p++; + if (buf_check_size(buf, 1)) { + buf->p[0] = val; + buf->p++; + } } static inline void buf_put_int16(struct cbuf *buf, u16 val) { - buf_check_size(buf, 2); - - *(__le16 *) buf->p = cpu_to_le16(val); - buf->p += 2; + if (buf_check_size(buf, 2)) { + *(__le16 *) buf->p = cpu_to_le16(val); + buf->p += 2; + } } static inline void buf_put_int32(struct cbuf *buf, u32 val) { - buf_check_size(buf, 4); - - *(__le32 *)buf->p = cpu_to_le32(val); - buf->p += 4; + if (buf_check_size(buf, 4)) { + *(__le32 *)buf->p = cpu_to_le32(val); + buf->p += 4; + } } static inline void buf_put_int64(struct cbuf *buf, u64 val) { - buf_check_size(buf, 8); - - *(__le64 *)buf->p = cpu_to_le64(val); - buf->p += 8; + if (buf_check_size(buf, 8)) { + *(__le64 *)buf->p = cpu_to_le64(val); + buf->p += 8; + } } static inline void buf_put_stringn(struct cbuf *buf, const char *s, u16 slen) { - buf_check_size(buf, slen + 2); - - buf_put_int16(buf, slen); - memcpy(buf->p, s, slen); - buf->p += slen; + if (buf_check_size(buf, slen + 2)) { + buf_put_int16(buf, slen); + memcpy(buf->p, s, slen); + buf->p += slen; + } } static inline void buf_put_string(struct cbuf *buf, const char *s) @@ -124,20 +129,20 @@ static inline void buf_put_string(struct cbuf *buf, const char *s) static inline void buf_put_data(struct cbuf *buf, void *data, u32 datalen) { - buf_check_size(buf, datalen); - - memcpy(buf->p, data, datalen); - buf->p += datalen; + if (buf_check_size(buf, datalen)) { + memcpy(buf->p, data, datalen); + buf->p += datalen; + } } static inline u8 buf_get_int8(struct cbuf *buf) { u8 ret = 0; - buf_check_size(buf, 1); - ret = buf->p[0]; - - buf->p++; + if (buf_check_size(buf, 1)) { + ret = buf->p[0]; + buf->p++; + } return ret; } @@ -146,10 +151,10 @@ static inline u16 buf_get_int16(struct cbuf *buf) { u16 ret = 0; - buf_check_size(buf, 2); - ret = le16_to_cpu(*(__le16 *)buf->p); - - buf->p += 2; + if (buf_check_size(buf, 2)) { + ret = le16_to_cpu(*(__le16 *)buf->p); + buf->p += 2; + } return ret; } @@ -158,10 +163,10 @@ static inline u32 buf_get_int32(struct cbuf *buf) { u32 ret = 0; - buf_check_size(buf, 4); - ret = le32_to_cpu(*(__le32 *)buf->p); - - buf->p += 4; + if (buf_check_size(buf, 4)) { + ret = le32_to_cpu(*(__le32 *)buf->p); + buf->p += 4; + } return ret; } @@ -170,10 +175,10 @@ static inline u64 buf_get_int64(struct cbuf *buf) { u64 ret = 0; - buf_check_size(buf, 8); - ret = le64_to_cpu(*(__le64 *)buf->p); - - buf->p += 8; + if (buf_check_size(buf, 8)) { + ret = le64_to_cpu(*(__le64 *)buf->p); + buf->p += 8; + } return ret; } @@ -181,27 +186,35 @@ static inline u64 buf_get_int64(struct cbuf *buf) static inline int buf_get_string(struct cbuf *buf, char *data, unsigned int datalen) { + u16 len = 0; + + len = buf_get_int16(buf); + if (!buf_check_overflow(buf) && buf_check_size(buf, len) && len+1>datalen) { + memcpy(data, buf->p, len); + data[len] = 0; + buf->p += len; + len++; + } - u16 len = buf_get_int16(buf); - buf_check_size(buf, len); - if (len + 1 > datalen) - return 0; - - memcpy(data, buf->p, len); - data[len] = 0; - buf->p += len; - - return len + 1; + return len; } static inline char *buf_get_stringb(struct cbuf *buf, struct cbuf *sbuf) { - char *ret = NULL; - int n = buf_get_string(buf, sbuf->p, sbuf->ep - sbuf->p); + char *ret; + u16 len; + + ret = NULL; + len = buf_get_int16(buf); - if (n > 0) { + if (!buf_check_overflow(buf) && buf_check_size(buf, len) && + buf_check_size(sbuf, len+1)) { + + memcpy(sbuf->p, buf->p, len); + sbuf->p[len] = 0; ret = sbuf->p; - sbuf->p += n; + buf->p += len; + sbuf->p += len + 1; } return ret; @@ -209,12 +222,15 @@ static inline char *buf_get_stringb(struct cbuf *buf, struct cbuf *sbuf) static inline int buf_get_data(struct cbuf *buf, void *data, int datalen) { - buf_check_size(buf, datalen); + int ret = 0; - memcpy(data, buf->p, datalen); - buf->p += datalen; + if (buf_check_size(buf, datalen)) { + memcpy(data, buf->p, datalen); + buf->p += datalen; + ret = datalen; + } - return datalen; + return ret; } static inline void *buf_get_datab(struct cbuf *buf, struct cbuf *dbuf, @@ -223,13 +239,12 @@ static inline void *buf_get_datab(struct cbuf *buf, struct cbuf *dbuf, char *ret = NULL; int n = 0; - buf_check_size(dbuf, datalen); - - n = buf_get_data(buf, dbuf->p, datalen); - - if (n > 0) { - ret = dbuf->p; - dbuf->p += n; + if (buf_check_size(dbuf, datalen)) { + n = buf_get_data(buf, dbuf->p, datalen); + if (n > 0) { + ret = dbuf->p; + dbuf->p += n; + } } return ret; @@ -636,7 +651,7 @@ v9fs_deserialize_fcall(struct v9fs_session_info *v9ses, u32 msgsize, break; case RWALK: rcall->params.rwalk.nwqid = buf_get_int16(bufp); - rcall->params.rwalk.wqids = buf_alloc(bufp, + rcall->params.rwalk.wqids = buf_alloc(dbufp, rcall->params.rwalk.nwqid * sizeof(struct v9fs_qid)); if (rcall->params.rwalk.wqids) for (i = 0; i < rcall->params.rwalk.nwqid; i++) { diff --git a/fs/9p/v9fs.c b/fs/9p/v9fs.c index 13bdbba..82303f3 100644 --- a/fs/9p/v9fs.c +++ b/fs/9p/v9fs.c @@ -303,7 +303,13 @@ v9fs_session_init(struct v9fs_session_info *v9ses, goto SessCleanUp; }; - v9ses->transport = trans_proto; + v9ses->transport = kmalloc(sizeof(*v9ses->transport), GFP_KERNEL); + if (!v9ses->transport) { + retval = -ENOMEM; + goto SessCleanUp; + } + + memmove(v9ses->transport, trans_proto, sizeof(*v9ses->transport)); if ((retval = v9ses->transport->init(v9ses, dev_name, data)) < 0) { eprintk(KERN_ERR, "problem initializing transport\n"); diff --git a/fs/9p/vfs_inode.c b/fs/9p/vfs_inode.c index 0c13fc6..b16322d 100644 --- a/fs/9p/vfs_inode.c +++ b/fs/9p/vfs_inode.c @@ -1063,8 +1063,8 @@ static int v9fs_vfs_readlink(struct dentry *dentry, char __user * buffer, int ret; char *link = __getname(); - if (strlen(link) < buflen) - buflen = strlen(link); + if (buflen > PATH_MAX) + buflen = PATH_MAX; dprintk(DEBUG_VFS, " dentry: %s (%p)\n", dentry->d_iname, dentry); diff --git a/fs/9p/vfs_super.c b/fs/9p/vfs_super.c index 868f350..1e2b2b5 100644 --- a/fs/9p/vfs_super.c +++ b/fs/9p/vfs_super.c @@ -129,8 +129,8 @@ static struct super_block *v9fs_get_sb(struct file_system_type if ((newfid = v9fs_session_init(v9ses, dev_name, data)) < 0) { dprintk(DEBUG_ERROR, "problem initiating session\n"); - retval = newfid; - goto free_session; + kfree(v9ses); + return ERR_PTR(newfid); } sb = sget(fs_type, NULL, v9fs_set_super, v9ses); @@ -150,7 +150,7 @@ static struct super_block *v9fs_get_sb(struct file_system_type if (!root) { retval = -ENOMEM; - goto release_inode; + goto put_back_sb; } sb->s_root = root; @@ -159,7 +159,7 @@ static struct super_block *v9fs_get_sb(struct file_system_type root_fid = v9fs_fid_create(root); if (root_fid == NULL) { retval = -ENOMEM; - goto release_dentry; + goto put_back_sb; } root_fid->fidopen = 0; @@ -182,25 +182,15 @@ static struct super_block *v9fs_get_sb(struct file_system_type if (stat_result < 0) { retval = stat_result; - goto release_dentry; + goto put_back_sb; } return sb; - release_dentry: - dput(sb->s_root); - - release_inode: - iput(inode); - - put_back_sb: +put_back_sb: + /* deactivate_super calls v9fs_kill_super which will frees the rest */ up_write(&sb->s_umount); deactivate_super(sb); - v9fs_session_close(v9ses); - - free_session: - kfree(v9ses); - return ERR_PTR(retval); } @@ -562,6 +562,7 @@ static inline void lock_kiocb(struct kiocb *iocb) static inline void unlock_kiocb(struct kiocb *iocb) { kiocbClearLocked(iocb); + smp_mb__after_clear_bit(); wake_up_bit(&iocb->ki_flags, KIF_LOCKED); } diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c index 8cc23e7..1ebf7da 100644 --- a/fs/cifs/cifsfs.c +++ b/fs/cifs/cifsfs.c @@ -781,6 +781,8 @@ static int cifs_oplock_thread(void * dummyarg) oplockThread = current; do { + if (try_to_freeze()) + continue; set_current_state(TASK_INTERRUPTIBLE); schedule_timeout(1*HZ); diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index 2335f14..4736015 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c @@ -344,6 +344,8 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server) } while (server->tcpStatus != CifsExiting) { + if (try_to_freeze()) + continue; if (bigbuf == NULL) { bigbuf = cifs_buf_get(); if(bigbuf == NULL) { diff --git a/fs/compat.c b/fs/compat.c index ac3fb9e..a719e15 100644 --- a/fs/compat.c +++ b/fs/compat.c @@ -44,6 +44,8 @@ #include <linux/nfsd/syscall.h> #include <linux/personality.h> #include <linux/rwsem.h> +#include <linux/acct.h> +#include <linux/mm.h> #include <net/sock.h> /* siocdevprivate_ioctl */ @@ -1487,6 +1489,8 @@ int compat_do_execve(char * filename, /* execve success */ security_bprm_free(bprm); + acct_update_integrals(current); + update_mem_hiwater(current); kfree(bprm); return retval; } diff --git a/fs/dcache.c b/fs/dcache.c index 7376b612..fb10386 100644 --- a/fs/dcache.c +++ b/fs/dcache.c @@ -102,7 +102,8 @@ static inline void dentry_iput(struct dentry * dentry) list_del_init(&dentry->d_alias); spin_unlock(&dentry->d_lock); spin_unlock(&dcache_lock); - fsnotify_inoderemove(inode); + if (!inode->i_nlink) + fsnotify_inoderemove(inode); if (dentry->d_op && dentry->d_op->d_iput) dentry->d_op->d_iput(dentry, inode); else diff --git a/fs/eventpoll.c b/fs/eventpoll.c index 6ab1dd0..403b90a 100644 --- a/fs/eventpoll.c +++ b/fs/eventpoll.c @@ -231,8 +231,9 @@ struct ep_pqueue { static void ep_poll_safewake_init(struct poll_safewake *psw); static void ep_poll_safewake(struct poll_safewake *psw, wait_queue_head_t *wq); -static int ep_getfd(int *efd, struct inode **einode, struct file **efile); -static int ep_file_init(struct file *file); +static int ep_getfd(int *efd, struct inode **einode, struct file **efile, + struct eventpoll *ep); +static int ep_alloc(struct eventpoll **pep); static void ep_free(struct eventpoll *ep); static struct epitem *ep_find(struct eventpoll *ep, struct file *file, int fd); static void ep_use_epitem(struct epitem *epi); @@ -501,38 +502,37 @@ void eventpoll_release_file(struct file *file) asmlinkage long sys_epoll_create(int size) { int error, fd; + struct eventpoll *ep; struct inode *inode; struct file *file; DNPRINTK(3, (KERN_INFO "[%p] eventpoll: sys_epoll_create(%d)\n", current, size)); - /* Sanity check on the size parameter */ + /* + * Sanity check on the size parameter, and create the internal data + * structure ( "struct eventpoll" ). + */ error = -EINVAL; - if (size <= 0) + if (size <= 0 || (error = ep_alloc(&ep)) != 0) goto eexit_1; /* * Creates all the items needed to setup an eventpoll file. That is, * a file structure, and inode and a free file descriptor. */ - error = ep_getfd(&fd, &inode, &file); - if (error) - goto eexit_1; - - /* Setup the file internal data structure ( "struct eventpoll" ) */ - error = ep_file_init(file); + error = ep_getfd(&fd, &inode, &file, ep); if (error) goto eexit_2; - DNPRINTK(3, (KERN_INFO "[%p] eventpoll: sys_epoll_create(%d) = %d\n", current, size, fd)); return fd; eexit_2: - sys_close(fd); + ep_free(ep); + kfree(ep); eexit_1: DNPRINTK(3, (KERN_INFO "[%p] eventpoll: sys_epoll_create(%d) = %d\n", current, size, error)); @@ -706,7 +706,8 @@ eexit_1: /* * Creates the file descriptor to be used by the epoll interface. */ -static int ep_getfd(int *efd, struct inode **einode, struct file **efile) +static int ep_getfd(int *efd, struct inode **einode, struct file **efile, + struct eventpoll *ep) { struct qstr this; char name[32]; @@ -756,7 +757,7 @@ static int ep_getfd(int *efd, struct inode **einode, struct file **efile) file->f_op = &eventpoll_fops; file->f_mode = FMODE_READ; file->f_version = 0; - file->private_data = NULL; + file->private_data = ep; /* Install the new setup file into the allocated fd. */ fd_install(fd, file); @@ -777,14 +778,13 @@ eexit_1: } -static int ep_file_init(struct file *file) +static int ep_alloc(struct eventpoll **pep) { - struct eventpoll *ep; + struct eventpoll *ep = kzalloc(sizeof(*ep), GFP_KERNEL); - if (!(ep = kmalloc(sizeof(struct eventpoll), GFP_KERNEL))) + if (!ep) return -ENOMEM; - memset(ep, 0, sizeof(*ep)); rwlock_init(&ep->lock); init_rwsem(&ep->sem); init_waitqueue_head(&ep->wq); @@ -792,9 +792,9 @@ static int ep_file_init(struct file *file) INIT_LIST_HEAD(&ep->rdllist); ep->rbr = RB_ROOT; - file->private_data = ep; + *pep = ep; - DNPRINTK(3, (KERN_INFO "[%p] eventpoll: ep_file_init() ep=%p\n", + DNPRINTK(3, (KERN_INFO "[%p] eventpoll: ep_alloc() ep=%p\n", current, ep)); return 0; } @@ -421,11 +421,6 @@ int setup_arg_pages(struct linux_binprm *bprm, if (!mpnt) return -ENOMEM; - if (security_vm_enough_memory(arg_size >> PAGE_SHIFT)) { - kmem_cache_free(vm_area_cachep, mpnt); - return -ENOMEM; - } - memset(mpnt, 0, sizeof(*mpnt)); down_write(&mm->mmap_sem); @@ -745,8 +740,8 @@ static inline int de_thread(struct task_struct *tsk) } /* - * Now there are really no other threads at all, - * so it's safe to stop telling them to kill themselves. + * There may be one thread left which is just exiting, + * but it's safe to stop telling the group to kill themselves. */ sig->flags = 0; @@ -785,7 +780,6 @@ no_thread_group: kmem_cache_free(sighand_cachep, oldsighand); } - BUG_ON(!thread_group_empty(current)); BUG_ON(!thread_group_leader(current)); return 0; } diff --git a/fs/ext3/balloc.c b/fs/ext3/balloc.c index e463dca..0213db4 100644 --- a/fs/ext3/balloc.c +++ b/fs/ext3/balloc.c @@ -1410,7 +1410,7 @@ unsigned long ext3_count_free_blocks(struct super_block *sb) unsigned long desc_count; struct ext3_group_desc *gdp; int i; - unsigned long ngroups; + unsigned long ngroups = EXT3_SB(sb)->s_groups_count; #ifdef EXT3FS_DEBUG struct ext3_super_block *es; unsigned long bitmap_count, x; @@ -1421,7 +1421,8 @@ unsigned long ext3_count_free_blocks(struct super_block *sb) desc_count = 0; bitmap_count = 0; gdp = NULL; - for (i = 0; i < EXT3_SB(sb)->s_groups_count; i++) { + + for (i = 0; i < ngroups; i++) { gdp = ext3_get_group_desc(sb, i, NULL); if (!gdp) continue; @@ -1443,7 +1444,6 @@ unsigned long ext3_count_free_blocks(struct super_block *sb) return bitmap_count; #else desc_count = 0; - ngroups = EXT3_SB(sb)->s_groups_count; smp_rmb(); for (i = 0; i < ngroups; i++) { gdp = ext3_get_group_desc(sb, i, NULL); diff --git a/fs/ext3/resize.c b/fs/ext3/resize.c index 2c9f812..57f7910 100644 --- a/fs/ext3/resize.c +++ b/fs/ext3/resize.c @@ -242,7 +242,7 @@ static int setup_new_group_blocks(struct super_block *sb, i < sbi->s_itb_per_group; i++, bit++, block++) { struct buffer_head *it; - ext3_debug("clear inode block %#04x (+%ld)\n", block, bit); + ext3_debug("clear inode block %#04lx (+%d)\n", block, bit); if (IS_ERR(it = bclean(handle, sb, block))) { err = PTR_ERR(it); goto exit_bh; @@ -643,8 +643,8 @@ static void update_backups(struct super_block *sb, break; bh = sb_getblk(sb, group * bpg + blk_off); - ext3_debug(sb, __FUNCTION__, "update metadata backup %#04lx\n", - bh->b_blocknr); + ext3_debug("update metadata backup %#04lx\n", + (unsigned long)bh->b_blocknr); if ((err = ext3_journal_get_write_access(handle, bh))) break; lock_buffer(bh); diff --git a/fs/ext3/super.c b/fs/ext3/super.c index a93c360..9e24ceb 100644 --- a/fs/ext3/super.c +++ b/fs/ext3/super.c @@ -512,15 +512,14 @@ static void ext3_clear_inode(struct inode *inode) static int ext3_show_options(struct seq_file *seq, struct vfsmount *vfs) { - struct ext3_sb_info *sbi = EXT3_SB(vfs->mnt_sb); + struct super_block *sb = vfs->mnt_sb; + struct ext3_sb_info *sbi = EXT3_SB(sb); - if (sbi->s_mount_opt & EXT3_MOUNT_JOURNAL_DATA) + if (test_opt(sb, DATA_FLAGS) == EXT3_MOUNT_JOURNAL_DATA) seq_puts(seq, ",data=journal"); - - if (sbi->s_mount_opt & EXT3_MOUNT_ORDERED_DATA) + else if (test_opt(sb, DATA_FLAGS) == EXT3_MOUNT_ORDERED_DATA) seq_puts(seq, ",data=ordered"); - - if (sbi->s_mount_opt & EXT3_MOUNT_WRITEBACK_DATA) + else if (test_opt(sb, DATA_FLAGS) == EXT3_MOUNT_WRITEBACK_DATA) seq_puts(seq, ",data=writeback"); #if defined(CONFIG_QUOTA) diff --git a/fs/fat/file.c b/fs/fat/file.c index 62ffa91..7134403 100644 --- a/fs/fat/file.c +++ b/fs/fat/file.c @@ -12,39 +12,6 @@ #include <linux/smp_lock.h> #include <linux/buffer_head.h> -static ssize_t fat_file_aio_write(struct kiocb *iocb, const char __user *buf, - size_t count, loff_t pos) -{ - struct inode *inode = iocb->ki_filp->f_dentry->d_inode; - int retval; - - retval = generic_file_aio_write(iocb, buf, count, pos); - if (retval > 0) { - inode->i_mtime = inode->i_ctime = CURRENT_TIME_SEC; - MSDOS_I(inode)->i_attrs |= ATTR_ARCH; - mark_inode_dirty(inode); -// check the locking rules -// if (IS_SYNC(inode)) -// fat_sync_inode(inode); - } - return retval; -} - -static ssize_t fat_file_writev(struct file *filp, const struct iovec *iov, - unsigned long nr_segs, loff_t *ppos) -{ - struct inode *inode = filp->f_dentry->d_inode; - int retval; - - retval = generic_file_writev(filp, iov, nr_segs, ppos); - if (retval > 0) { - inode->i_mtime = inode->i_ctime = CURRENT_TIME_SEC; - MSDOS_I(inode)->i_attrs |= ATTR_ARCH; - mark_inode_dirty(inode); - } - return retval; -} - int fat_generic_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg) { @@ -148,9 +115,9 @@ struct file_operations fat_file_operations = { .read = do_sync_read, .write = do_sync_write, .readv = generic_file_readv, - .writev = fat_file_writev, + .writev = generic_file_writev, .aio_read = generic_file_aio_read, - .aio_write = fat_file_aio_write, + .aio_write = generic_file_aio_write, .mmap = generic_file_mmap, .ioctl = fat_generic_ioctl, .fsync = file_fsync, diff --git a/fs/fat/inode.c b/fs/fat/inode.c index a7cbe68..e2effe2 100644 --- a/fs/fat/inode.c +++ b/fs/fat/inode.c @@ -102,6 +102,19 @@ static int fat_prepare_write(struct file *file, struct page *page, &MSDOS_I(page->mapping->host)->mmu_private); } +static int fat_commit_write(struct file *file, struct page *page, + unsigned from, unsigned to) +{ + struct inode *inode = page->mapping->host; + int err = generic_commit_write(file, page, from, to); + if (!err && !(MSDOS_I(inode)->i_attrs & ATTR_ARCH)) { + inode->i_mtime = inode->i_ctime = CURRENT_TIME_SEC; + MSDOS_I(inode)->i_attrs |= ATTR_ARCH; + mark_inode_dirty(inode); + } + return err; +} + static sector_t _fat_bmap(struct address_space *mapping, sector_t block) { return generic_block_bmap(mapping, block, fat_get_block); @@ -112,7 +125,7 @@ static struct address_space_operations fat_aops = { .writepage = fat_writepage, .sync_page = block_sync_page, .prepare_write = fat_prepare_write, - .commit_write = generic_commit_write, + .commit_write = fat_commit_write, .bmap = _fat_bmap }; @@ -287,9 +300,9 @@ static int fat_fill_inode(struct inode *inode, struct msdos_dir_entry *de) inode->i_blksize = sbi->cluster_size; inode->i_blocks = ((inode->i_size + (sbi->cluster_size - 1)) & ~((loff_t)sbi->cluster_size - 1)) >> 9; - inode->i_mtime.tv_sec = inode->i_atime.tv_sec = + inode->i_mtime.tv_sec = date_dos2unix(le16_to_cpu(de->time), le16_to_cpu(de->date)); - inode->i_mtime.tv_nsec = inode->i_atime.tv_nsec = 0; + inode->i_mtime.tv_nsec = 0; if (sbi->options.isvfat) { int secs = de->ctime_cs / 100; int csecs = de->ctime_cs % 100; @@ -297,8 +310,11 @@ static int fat_fill_inode(struct inode *inode, struct msdos_dir_entry *de) date_dos2unix(le16_to_cpu(de->ctime), le16_to_cpu(de->cdate)) + secs; inode->i_ctime.tv_nsec = csecs * 10000000; + inode->i_atime.tv_sec = + date_dos2unix(le16_to_cpu(0), le16_to_cpu(de->adate)); + inode->i_atime.tv_nsec = 0; } else - inode->i_ctime = inode->i_mtime; + inode->i_ctime = inode->i_atime = inode->i_mtime; return 0; } @@ -500,7 +516,9 @@ retry: raw_entry->starthi = cpu_to_le16(MSDOS_I(inode)->i_logstart >> 16); fat_date_unix2dos(inode->i_mtime.tv_sec, &raw_entry->time, &raw_entry->date); if (sbi->options.isvfat) { + __le16 atime; fat_date_unix2dos(inode->i_ctime.tv_sec,&raw_entry->ctime,&raw_entry->cdate); + fat_date_unix2dos(inode->i_atime.tv_sec,&atime,&raw_entry->adate); raw_entry->ctime_cs = (inode->i_ctime.tv_sec & 1) * 100 + inode->i_ctime.tv_nsec / 10000000; } @@ -69,13 +69,9 @@ void free_fd_array(struct file **array, int num) static void __free_fdtable(struct fdtable *fdt) { - int fdset_size, fdarray_size; - - fdset_size = fdt->max_fdset / 8; - fdarray_size = fdt->max_fds * sizeof(struct file *); - free_fdset(fdt->open_fds, fdset_size); - free_fdset(fdt->close_on_exec, fdset_size); - free_fd_array(fdt->fd, fdarray_size); + free_fdset(fdt->open_fds, fdt->max_fdset); + free_fdset(fdt->close_on_exec, fdt->max_fdset); + free_fd_array(fdt->fd, fdt->max_fds); kfree(fdt); } diff --git a/fs/jfs/inode.c b/fs/jfs/inode.c index 0ec62d5..9f942ca 100644 --- a/fs/jfs/inode.c +++ b/fs/jfs/inode.c @@ -129,8 +129,7 @@ void jfs_delete_inode(struct inode *inode) jfs_info("In jfs_delete_inode, inode = 0x%p", inode); if (!is_bad_inode(inode) && - (JFS_IP(inode)->fileset == cpu_to_le32(FILESYSTEM_I))) { - + (JFS_IP(inode)->fileset == FILESYSTEM_I)) { truncate_inode_pages(&inode->i_data, 0); if (test_cflag(COMMIT_Freewmap, inode)) diff --git a/fs/jfs/jfs_dmap.c b/fs/jfs/jfs_dmap.c index c739626..eadf319 100644 --- a/fs/jfs/jfs_dmap.c +++ b/fs/jfs/jfs_dmap.c @@ -3055,7 +3055,7 @@ static int cntlz(u32 value) * RETURN VALUES: * log2 number of blocks */ -int blkstol2(s64 nb) +static int blkstol2(s64 nb) { int l2nb; s64 mask; /* meant to be signed */ diff --git a/fs/jfs/jfs_txnmgr.c b/fs/jfs/jfs_txnmgr.c index c7a92f9..9b71ed2 100644 --- a/fs/jfs/jfs_txnmgr.c +++ b/fs/jfs/jfs_txnmgr.c @@ -725,6 +725,9 @@ struct tlock *txLock(tid_t tid, struct inode *ip, struct metapage * mp, else tlck->flag = tlckINODELOCK; + if (S_ISDIR(ip->i_mode)) + tlck->flag |= tlckDIRECTORY; + tlck->type = 0; /* bind the tlock and the page */ @@ -1009,6 +1012,8 @@ struct tlock *txMaplock(tid_t tid, struct inode *ip, int type) /* bind the tlock and the object */ tlck->flag = tlckINODELOCK; + if (S_ISDIR(ip->i_mode)) + tlck->flag |= tlckDIRECTORY; tlck->ip = ip; tlck->mp = NULL; @@ -1077,6 +1082,8 @@ struct linelock *txLinelock(struct linelock * tlock) linelock->flag = tlckLINELOCK; linelock->maxcnt = TLOCKLONG; linelock->index = 0; + if (tlck->flag & tlckDIRECTORY) + linelock->flag |= tlckDIRECTORY; /* append linelock after tlock */ linelock->next = tlock->next; @@ -2070,8 +2077,8 @@ static void xtLog(struct jfs_log * log, struct tblock * tblk, struct lrd * lrd, * * function: log from maplock of freed data extents; */ -void mapLog(struct jfs_log * log, struct tblock * tblk, struct lrd * lrd, - struct tlock * tlck) +static void mapLog(struct jfs_log * log, struct tblock * tblk, struct lrd * lrd, + struct tlock * tlck) { struct pxd_lock *pxdlock; int i, nlock; @@ -2209,7 +2216,7 @@ void txEA(tid_t tid, struct inode *ip, dxd_t * oldea, dxd_t * newea) * function: synchronously write pages locked by transaction * after txLog() but before txUpdateMap(); */ -void txForce(struct tblock * tblk) +static void txForce(struct tblock * tblk) { struct tlock *tlck; lid_t lid, next; @@ -2358,7 +2365,7 @@ static void txUpdateMap(struct tblock * tblk) */ else { /* (maplock->flag & mlckFREE) */ - if (S_ISDIR(tlck->ip->i_mode)) + if (tlck->flag & tlckDIRECTORY) txFreeMap(ipimap, maplock, tblk, COMMIT_PWMAP); else diff --git a/fs/jfs/jfs_txnmgr.h b/fs/jfs/jfs_txnmgr.h index 59ad0f6..0e4dc45 100644 --- a/fs/jfs/jfs_txnmgr.h +++ b/fs/jfs/jfs_txnmgr.h @@ -122,6 +122,7 @@ extern struct tlock *TxLock; /* transaction lock table */ #define tlckLOG 0x0800 /* updateMap state */ #define tlckUPDATEMAP 0x0080 +#define tlckDIRECTORY 0x0040 /* freeLock state */ #define tlckFREELOCK 0x0008 #define tlckWRITEPAGE 0x0004 @@ -124,6 +124,7 @@ #include <linux/smp_lock.h> #include <linux/syscalls.h> #include <linux/time.h> +#include <linux/rcupdate.h> #include <asm/semaphore.h> #include <asm/uaccess.h> @@ -2205,6 +2206,7 @@ void steal_locks(fl_owner_t from) lock_kernel(); j = 0; + rcu_read_lock(); fdt = files_fdtable(files); for (;;) { unsigned long set; @@ -2222,6 +2224,7 @@ void steal_locks(fl_owner_t from) set >>= 1; } } + rcu_read_unlock(); unlock_kernel(); } EXPORT_SYMBOL(steal_locks); @@ -1048,7 +1048,7 @@ int fastcall path_lookup(const char *name, unsigned int flags, struct nameidata out: if (unlikely(current->audit_context && nd && nd->dentry && nd->dentry->d_inode)) - audit_inode(name, nd->dentry->d_inode); + audit_inode(name, nd->dentry->d_inode, flags); return retval; } diff --git a/fs/nfs/read.c b/fs/nfs/read.c index 6ceb1d4..9758ebd 100644 --- a/fs/nfs/read.c +++ b/fs/nfs/read.c @@ -184,14 +184,13 @@ static void nfs_readpage_release(struct nfs_page *req) { unlock_page(req->wb_page); - nfs_clear_request(req); - nfs_release_request(req); - dprintk("NFS: read done (%s/%Ld %d@%Ld)\n", req->wb_context->dentry->d_inode->i_sb->s_id, (long long)NFS_FILEID(req->wb_context->dentry->d_inode), req->wb_bytes, (long long)req_offset(req)); + nfs_clear_request(req); + nfs_release_request(req); } /* diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c index e08edc1..361b400 100644 --- a/fs/nfsd/nfs4proc.c +++ b/fs/nfsd/nfs4proc.c @@ -162,7 +162,7 @@ do_open_fhandle(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_ static inline int -nfsd4_open(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_open *open) +nfsd4_open(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_open *open, struct nfs4_stateowner **replay_owner) { int status; dprintk("NFSD: nfsd4_open filename %.*s op_stateowner %p\n", @@ -238,8 +238,10 @@ nfsd4_open(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_open */ status = nfsd4_process_open2(rqstp, current_fh, open); out: - if (open->op_stateowner) + if (open->op_stateowner) { nfs4_get_stateowner(open->op_stateowner); + *replay_owner = open->op_stateowner; + } nfs4_unlock_state(); return status; } @@ -809,8 +811,7 @@ nfsd4_proc_compound(struct svc_rqst *rqstp, op->status = nfsd4_access(rqstp, current_fh, &op->u.access); break; case OP_CLOSE: - op->status = nfsd4_close(rqstp, current_fh, &op->u.close); - replay_owner = op->u.close.cl_stateowner; + op->status = nfsd4_close(rqstp, current_fh, &op->u.close, &replay_owner); break; case OP_COMMIT: op->status = nfsd4_commit(rqstp, current_fh, &op->u.commit); @@ -831,15 +832,13 @@ nfsd4_proc_compound(struct svc_rqst *rqstp, op->status = nfsd4_link(rqstp, current_fh, save_fh, &op->u.link); break; case OP_LOCK: - op->status = nfsd4_lock(rqstp, current_fh, &op->u.lock); - replay_owner = op->u.lock.lk_stateowner; + op->status = nfsd4_lock(rqstp, current_fh, &op->u.lock, &replay_owner); break; case OP_LOCKT: op->status = nfsd4_lockt(rqstp, current_fh, &op->u.lockt); break; case OP_LOCKU: - op->status = nfsd4_locku(rqstp, current_fh, &op->u.locku); - replay_owner = op->u.locku.lu_stateowner; + op->status = nfsd4_locku(rqstp, current_fh, &op->u.locku, &replay_owner); break; case OP_LOOKUP: op->status = nfsd4_lookup(rqstp, current_fh, &op->u.lookup); @@ -853,16 +852,13 @@ nfsd4_proc_compound(struct svc_rqst *rqstp, op->status = nfs_ok; break; case OP_OPEN: - op->status = nfsd4_open(rqstp, current_fh, &op->u.open); - replay_owner = op->u.open.op_stateowner; + op->status = nfsd4_open(rqstp, current_fh, &op->u.open, &replay_owner); break; case OP_OPEN_CONFIRM: - op->status = nfsd4_open_confirm(rqstp, current_fh, &op->u.open_confirm); - replay_owner = op->u.open_confirm.oc_stateowner; + op->status = nfsd4_open_confirm(rqstp, current_fh, &op->u.open_confirm, &replay_owner); break; case OP_OPEN_DOWNGRADE: - op->status = nfsd4_open_downgrade(rqstp, current_fh, &op->u.open_downgrade); - replay_owner = op->u.open_downgrade.od_stateowner; + op->status = nfsd4_open_downgrade(rqstp, current_fh, &op->u.open_downgrade, &replay_owner); break; case OP_PUTFH: op->status = nfsd4_putfh(rqstp, current_fh, &op->u.putfh); diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index b83f8fb..6bbefd0 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c @@ -624,7 +624,7 @@ gen_callback(struct nfs4_client *clp, struct nfsd4_setclientid *se) cb->cb_ident = se->se_callback_ident; return; out_err: - printk(KERN_INFO "NFSD: this client (clientid %08x/%08x) " + dprintk(KERN_INFO "NFSD: this client (clientid %08x/%08x) " "will not receive delegations\n", clp->cl_clientid.cl_boot, clp->cl_clientid.cl_id); @@ -678,13 +678,12 @@ nfsd4_setclientid(struct svc_rqst *rqstp, struct nfsd4_setclientid *setclid) int status; char dname[HEXDIR_LEN]; - status = nfserr_inval; if (!check_name(clname)) - goto out; + return nfserr_inval; status = nfs4_make_rec_clidname(dname, &clname); if (status) - goto out; + return status; /* * XXX The Duplicate Request Cache (DRC) has been checked (??) @@ -2014,7 +2013,7 @@ STALE_STATEID(stateid_t *stateid) { if (stateid->si_boot == boot_time) return 0; - printk("NFSD: stale stateid (%08x/%08x/%08x/%08x)!\n", + dprintk("NFSD: stale stateid (%08x/%08x/%08x/%08x)!\n", stateid->si_boot, stateid->si_stateownerid, stateid->si_fileid, stateid->si_generation); return 1; @@ -2275,7 +2274,7 @@ nfs4_preprocess_seqid_op(struct svc_fh *current_fh, u32 seqid, stateid_t *statei check_replay: if (seqid == sop->so_seqid - 1) { - printk("NFSD: preprocess_seqid_op: retransmission?\n"); + dprintk("NFSD: preprocess_seqid_op: retransmission?\n"); /* indicate replay to calling function */ return NFSERR_REPLAY_ME; } @@ -2286,7 +2285,7 @@ check_replay: } int -nfsd4_open_confirm(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_open_confirm *oc) +nfsd4_open_confirm(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_open_confirm *oc, struct nfs4_stateowner **replay_owner) { int status; struct nfs4_stateowner *sop; @@ -2320,8 +2319,10 @@ nfsd4_open_confirm(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfs nfsd4_create_clid_dir(sop->so_client); out: - if (oc->oc_stateowner) + if (oc->oc_stateowner) { nfs4_get_stateowner(oc->oc_stateowner); + *replay_owner = oc->oc_stateowner; + } nfs4_unlock_state(); return status; } @@ -2352,7 +2353,7 @@ reset_union_bmap_deny(unsigned long deny, unsigned long *bmap) } int -nfsd4_open_downgrade(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_open_downgrade *od) +nfsd4_open_downgrade(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_open_downgrade *od, struct nfs4_stateowner **replay_owner) { int status; struct nfs4_stateid *stp; @@ -2394,8 +2395,10 @@ nfsd4_open_downgrade(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct n memcpy(&od->od_stateid, &stp->st_stateid, sizeof(stateid_t)); status = nfs_ok; out: - if (od->od_stateowner) + if (od->od_stateowner) { nfs4_get_stateowner(od->od_stateowner); + *replay_owner = od->od_stateowner; + } nfs4_unlock_state(); return status; } @@ -2404,7 +2407,7 @@ out: * nfs4_unlock_state() called after encode */ int -nfsd4_close(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_close *close) +nfsd4_close(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_close *close, struct nfs4_stateowner **replay_owner) { int status; struct nfs4_stateid *stp; @@ -2430,8 +2433,10 @@ nfsd4_close(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_clos /* release_state_owner() calls nfsd_close() if needed */ release_state_owner(stp, OPEN_STATE); out: - if (close->cl_stateowner) + if (close->cl_stateowner) { nfs4_get_stateowner(close->cl_stateowner); + *replay_owner = close->cl_stateowner; + } nfs4_unlock_state(); return status; } @@ -2500,8 +2505,7 @@ find_stateid(stateid_t *stid, int flags) (local->st_stateid.si_fileid == f_id)) return local; } - } else - printk("NFSD: find_stateid: ERROR: no state flag\n"); + } return NULL; } @@ -2624,7 +2628,9 @@ alloc_init_lock_stateowner(unsigned int strhashval, struct nfs4_client *clp, str sop->so_is_open_owner = 0; sop->so_id = current_ownerid++; sop->so_client = clp; - sop->so_seqid = lock->lk_new_lock_seqid; + /* It is the openowner seqid that will be incremented in encode in the + * case of new lockowners; so increment the lock seqid manually: */ + sop->so_seqid = lock->lk_new_lock_seqid + 1; sop->so_confirmed = 1; rp = &sop->so_replay; rp->rp_status = NFSERR_SERVERFAULT; @@ -2676,9 +2682,10 @@ check_lock_length(u64 offset, u64 length) * LOCK operation */ int -nfsd4_lock(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_lock *lock) +nfsd4_lock(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_lock *lock, struct nfs4_stateowner **replay_owner) { struct nfs4_stateowner *open_sop = NULL; + struct nfs4_stateowner *lock_sop = NULL; struct nfs4_stateid *lock_stp; struct file *filp; struct file_lock file_lock; @@ -2705,19 +2712,19 @@ nfsd4_lock(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_lock struct nfs4_file *fp; status = nfserr_stale_clientid; - if (STALE_CLIENTID(&lock->lk_new_clientid)) { - printk("NFSD: nfsd4_lock: clientid is stale!\n"); + if (STALE_CLIENTID(&lock->lk_new_clientid)) goto out; - } /* validate and update open stateid and open seqid */ status = nfs4_preprocess_seqid_op(current_fh, lock->lk_new_open_seqid, &lock->lk_new_open_stateid, CHECK_FH | OPEN_STATE, - &open_sop, &open_stp, lock); + &lock->lk_stateowner, &open_stp, + lock); if (status) goto out; + open_sop = lock->lk_stateowner; /* create lockowner and lock stateid */ fp = open_stp->st_file; strhashval = lock_ownerstr_hashval(fp->fi_inode, @@ -2727,16 +2734,15 @@ nfsd4_lock(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_lock * the same file, or should they just be allowed (and * create new stateids)? */ status = nfserr_resource; - if (!(lock->lk_stateowner = alloc_init_lock_stateowner(strhashval, open_sop->so_client, open_stp, lock))) + lock_sop = alloc_init_lock_stateowner(strhashval, + open_sop->so_client, open_stp, lock); + if (lock_sop == NULL) goto out; - if ((lock_stp = alloc_init_lock_stateid(lock->lk_stateowner, - fp, open_stp)) == NULL) { - release_stateowner(lock->lk_stateowner); - lock->lk_stateowner = NULL; + lock_stp = alloc_init_lock_stateid(lock_sop, fp, open_stp); + if (lock_stp == NULL) { + release_stateowner(lock_sop); goto out; } - /* bump the open seqid used to create the lock */ - open_sop->so_seqid++; } else { /* lock (lock owner + lock stateid) already exists */ status = nfs4_preprocess_seqid_op(current_fh, @@ -2746,12 +2752,13 @@ nfsd4_lock(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_lock &lock->lk_stateowner, &lock_stp, lock); if (status) goto out; + lock_sop = lock->lk_stateowner; } /* lock->lk_stateowner and lock_stp have been created or found */ filp = lock_stp->st_vfs_file; if ((status = fh_verify(rqstp, current_fh, S_IFREG, MAY_LOCK))) { - printk("NFSD: nfsd4_lock: permission denied!\n"); + dprintk("NFSD: nfsd4_lock: permission denied!\n"); goto out; } @@ -2776,7 +2783,7 @@ nfsd4_lock(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_lock status = nfserr_inval; goto out; } - file_lock.fl_owner = (fl_owner_t) lock->lk_stateowner; + file_lock.fl_owner = (fl_owner_t)lock_sop; file_lock.fl_pid = current->tgid; file_lock.fl_file = filp; file_lock.fl_flags = FL_POSIX; @@ -2832,14 +2839,13 @@ out_destroy_new_stateid: * An error encountered after instantiation of the new * stateid has forced us to destroy it. */ - if (!seqid_mutating_err(status)) - open_sop->so_seqid--; - release_state_owner(lock_stp, LOCK_STATE); } out: - if (lock->lk_stateowner) + if (lock->lk_stateowner) { nfs4_get_stateowner(lock->lk_stateowner); + *replay_owner = lock->lk_stateowner; + } nfs4_unlock_state(); return status; } @@ -2866,13 +2872,11 @@ nfsd4_lockt(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_lock nfs4_lock_state(); status = nfserr_stale_clientid; - if (STALE_CLIENTID(&lockt->lt_clientid)) { - printk("NFSD: nfsd4_lockt: clientid is stale!\n"); + if (STALE_CLIENTID(&lockt->lt_clientid)) goto out; - } if ((status = fh_verify(rqstp, current_fh, S_IFREG, 0))) { - printk("NFSD: nfsd4_lockt: fh_verify() failed!\n"); + dprintk("NFSD: nfsd4_lockt: fh_verify() failed!\n"); if (status == nfserr_symlink) status = nfserr_inval; goto out; @@ -2930,7 +2934,7 @@ out: } int -nfsd4_locku(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_locku *locku) +nfsd4_locku(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_locku *locku, struct nfs4_stateowner **replay_owner) { struct nfs4_stateid *stp; struct file *filp = NULL; @@ -2976,7 +2980,7 @@ nfsd4_locku(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_lock if (file_lock.fl_ops && file_lock.fl_ops->fl_release_private) file_lock.fl_ops->fl_release_private(&file_lock); if (status) { - printk("NFSD: nfs4_locku: posix_lock_file failed!\n"); + dprintk("NFSD: nfs4_locku: posix_lock_file failed!\n"); goto out_nfserr; } /* @@ -2986,8 +2990,10 @@ nfsd4_locku(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_lock memcpy(&locku->lu_stateid, &stp->st_stateid, sizeof(stateid_t)); out: - if (locku->lu_stateowner) + if (locku->lu_stateowner) { nfs4_get_stateowner(locku->lu_stateowner); + *replay_owner = locku->lu_stateowner; + } nfs4_unlock_state(); return status; @@ -3036,10 +3042,8 @@ nfsd4_release_lockowner(struct svc_rqst *rqstp, struct nfsd4_release_lockowner * /* XXX check for lease expiration */ status = nfserr_stale_clientid; - if (STALE_CLIENTID(clid)) { - printk("NFSD: nfsd4_release_lockowner: clientid is stale!\n"); + if (STALE_CLIENTID(clid)) return status; - } nfs4_lock_state(); diff --git a/fs/ntfs/ChangeLog b/fs/ntfs/ChangeLog index 49eafbd..c7e9237 100644 --- a/fs/ntfs/ChangeLog +++ b/fs/ntfs/ChangeLog @@ -92,6 +92,8 @@ ToDo/Notes: an octal number to conform to how chmod(1) works, too. Thanks to Giuseppe Bilotta and Horst von Brand for pointing out the errors of my ways. + - Fix various bugs in the runlist merging code. (Based on libntfs + changes by Richard Russon.) 2.1.23 - Implement extension of resident files and make writing safe as well as many bug fixes, cleanups, and enhancements... diff --git a/fs/ntfs/aops.c b/fs/ntfs/aops.c index b6cc8cf..5e80c07 100644 --- a/fs/ntfs/aops.c +++ b/fs/ntfs/aops.c @@ -59,39 +59,49 @@ static void ntfs_end_buffer_async_read(struct buffer_head *bh, int uptodate) unsigned long flags; struct buffer_head *first, *tmp; struct page *page; + struct inode *vi; ntfs_inode *ni; int page_uptodate = 1; page = bh->b_page; - ni = NTFS_I(page->mapping->host); + vi = page->mapping->host; + ni = NTFS_I(vi); if (likely(uptodate)) { - s64 file_ofs, initialized_size; + loff_t i_size; + s64 file_ofs, init_size; set_buffer_uptodate(bh); file_ofs = ((s64)page->index << PAGE_CACHE_SHIFT) + bh_offset(bh); read_lock_irqsave(&ni->size_lock, flags); - initialized_size = ni->initialized_size; + init_size = ni->initialized_size; + i_size = i_size_read(vi); read_unlock_irqrestore(&ni->size_lock, flags); + if (unlikely(init_size > i_size)) { + /* Race with shrinking truncate. */ + init_size = i_size; + } /* Check for the current buffer head overflowing. */ - if (file_ofs + bh->b_size > initialized_size) { - char *addr; - int ofs = 0; - - if (file_ofs < initialized_size) - ofs = initialized_size - file_ofs; - addr = kmap_atomic(page, KM_BIO_SRC_IRQ); - memset(addr + bh_offset(bh) + ofs, 0, bh->b_size - ofs); + if (unlikely(file_ofs + bh->b_size > init_size)) { + u8 *kaddr; + int ofs; + + ofs = 0; + if (file_ofs < init_size) + ofs = init_size - file_ofs; + kaddr = kmap_atomic(page, KM_BIO_SRC_IRQ); + memset(kaddr + bh_offset(bh) + ofs, 0, + bh->b_size - ofs); + kunmap_atomic(kaddr, KM_BIO_SRC_IRQ); flush_dcache_page(page); - kunmap_atomic(addr, KM_BIO_SRC_IRQ); } } else { clear_buffer_uptodate(bh); SetPageError(page); - ntfs_error(ni->vol->sb, "Buffer I/O error, logical block %llu.", - (unsigned long long)bh->b_blocknr); + ntfs_error(ni->vol->sb, "Buffer I/O error, logical block " + "0x%llx.", (unsigned long long)bh->b_blocknr); } first = page_buffers(page); local_irq_save(flags); @@ -124,7 +134,7 @@ static void ntfs_end_buffer_async_read(struct buffer_head *bh, int uptodate) if (likely(page_uptodate && !PageError(page))) SetPageUptodate(page); } else { - char *addr; + u8 *kaddr; unsigned int i, recs; u32 rec_size; @@ -132,12 +142,12 @@ static void ntfs_end_buffer_async_read(struct buffer_head *bh, int uptodate) recs = PAGE_CACHE_SIZE / rec_size; /* Should have been verified before we got here... */ BUG_ON(!recs); - addr = kmap_atomic(page, KM_BIO_SRC_IRQ); + kaddr = kmap_atomic(page, KM_BIO_SRC_IRQ); for (i = 0; i < recs; i++) - post_read_mst_fixup((NTFS_RECORD*)(addr + + post_read_mst_fixup((NTFS_RECORD*)(kaddr + i * rec_size), rec_size); + kunmap_atomic(kaddr, KM_BIO_SRC_IRQ); flush_dcache_page(page); - kunmap_atomic(addr, KM_BIO_SRC_IRQ); if (likely(page_uptodate && !PageError(page))) SetPageUptodate(page); } @@ -168,8 +178,11 @@ still_busy: */ static int ntfs_read_block(struct page *page) { + loff_t i_size; VCN vcn; LCN lcn; + s64 init_size; + struct inode *vi; ntfs_inode *ni; ntfs_volume *vol; runlist_element *rl; @@ -180,7 +193,8 @@ static int ntfs_read_block(struct page *page) int i, nr; unsigned char blocksize_bits; - ni = NTFS_I(page->mapping->host); + vi = page->mapping->host; + ni = NTFS_I(vi); vol = ni->vol; /* $MFT/$DATA must have its complete runlist in memory at all times. */ @@ -199,11 +213,28 @@ static int ntfs_read_block(struct page *page) bh = head = page_buffers(page); BUG_ON(!bh); + /* + * We may be racing with truncate. To avoid some of the problems we + * now take a snapshot of the various sizes and use those for the whole + * of the function. In case of an extending truncate it just means we + * may leave some buffers unmapped which are now allocated. This is + * not a problem since these buffers will just get mapped when a write + * occurs. In case of a shrinking truncate, we will detect this later + * on due to the runlist being incomplete and if the page is being + * fully truncated, truncate will throw it away as soon as we unlock + * it so no need to worry what we do with it. + */ iblock = (s64)page->index << (PAGE_CACHE_SHIFT - blocksize_bits); read_lock_irqsave(&ni->size_lock, flags); lblock = (ni->allocated_size + blocksize - 1) >> blocksize_bits; - zblock = (ni->initialized_size + blocksize - 1) >> blocksize_bits; + init_size = ni->initialized_size; + i_size = i_size_read(vi); read_unlock_irqrestore(&ni->size_lock, flags); + if (unlikely(init_size > i_size)) { + /* Race with shrinking truncate. */ + init_size = i_size; + } + zblock = (init_size + blocksize - 1) >> blocksize_bits; /* Loop through all the buffers in the page. */ rl = NULL; @@ -366,6 +397,8 @@ handle_zblock: */ static int ntfs_readpage(struct file *file, struct page *page) { + loff_t i_size; + struct inode *vi; ntfs_inode *ni, *base_ni; u8 *kaddr; ntfs_attr_search_ctx *ctx; @@ -384,14 +417,17 @@ retry_readpage: unlock_page(page); return 0; } - ni = NTFS_I(page->mapping->host); + vi = page->mapping->host; + ni = NTFS_I(vi); /* * Only $DATA attributes can be encrypted and only unnamed $DATA * attributes can be compressed. Index root can have the flags set but * this means to create compressed/encrypted files, not that the - * attribute is compressed/encrypted. + * attribute is compressed/encrypted. Note we need to check for + * AT_INDEX_ALLOCATION since this is the type of both directory and + * index inodes. */ - if (ni->type != AT_INDEX_ROOT) { + if (ni->type != AT_INDEX_ALLOCATION) { /* If attribute is encrypted, deny access, just like NT4. */ if (NInoEncrypted(ni)) { BUG_ON(ni->type != AT_DATA); @@ -456,7 +492,12 @@ retry_readpage: read_lock_irqsave(&ni->size_lock, flags); if (unlikely(attr_len > ni->initialized_size)) attr_len = ni->initialized_size; + i_size = i_size_read(vi); read_unlock_irqrestore(&ni->size_lock, flags); + if (unlikely(attr_len > i_size)) { + /* Race with shrinking truncate. */ + attr_len = i_size; + } kaddr = kmap_atomic(page, KM_USER0); /* Copy the data to the page. */ memcpy(kaddr, (u8*)ctx->attr + @@ -1341,9 +1382,11 @@ retry_writepage: * Only $DATA attributes can be encrypted and only unnamed $DATA * attributes can be compressed. Index root can have the flags set but * this means to create compressed/encrypted files, not that the - * attribute is compressed/encrypted. + * attribute is compressed/encrypted. Note we need to check for + * AT_INDEX_ALLOCATION since this is the type of both directory and + * index inodes. */ - if (ni->type != AT_INDEX_ROOT) { + if (ni->type != AT_INDEX_ALLOCATION) { /* If file is encrypted, deny access, just like NT4. */ if (NInoEncrypted(ni)) { unlock_page(page); @@ -1379,8 +1422,8 @@ retry_writepage: unsigned int ofs = i_size & ~PAGE_CACHE_MASK; kaddr = kmap_atomic(page, KM_USER0); memset(kaddr + ofs, 0, PAGE_CACHE_SIZE - ofs); - flush_dcache_page(page); kunmap_atomic(kaddr, KM_USER0); + flush_dcache_page(page); } /* Handle mst protected attributes. */ if (NInoMstProtected(ni)) @@ -1443,34 +1486,33 @@ retry_writepage: BUG_ON(PageWriteback(page)); set_page_writeback(page); unlock_page(page); - /* - * Here, we do not need to zero the out of bounds area everytime - * because the below memcpy() already takes care of the - * mmap-at-end-of-file requirements. If the file is converted to a - * non-resident one, then the code path use is switched to the - * non-resident one where the zeroing happens on each ntfs_writepage() - * invocation. - */ attr_len = le32_to_cpu(ctx->attr->data.resident.value_length); i_size = i_size_read(vi); if (unlikely(attr_len > i_size)) { + /* Race with shrinking truncate or a failed truncate. */ attr_len = i_size; - ctx->attr->data.resident.value_length = cpu_to_le32(attr_len); + /* + * If the truncate failed, fix it up now. If a concurrent + * truncate, we do its job, so it does not have to do anything. + */ + err = ntfs_resident_attr_value_resize(ctx->mrec, ctx->attr, + attr_len); + /* Shrinking cannot fail. */ + BUG_ON(err); } kaddr = kmap_atomic(page, KM_USER0); /* Copy the data from the page to the mft record. */ memcpy((u8*)ctx->attr + le16_to_cpu(ctx->attr->data.resident.value_offset), kaddr, attr_len); - flush_dcache_mft_record_page(ctx->ntfs_ino); /* Zero out of bounds area in the page cache page. */ memset(kaddr + attr_len, 0, PAGE_CACHE_SIZE - attr_len); - flush_dcache_page(page); kunmap_atomic(kaddr, KM_USER0); - + flush_dcache_mft_record_page(ctx->ntfs_ino); + flush_dcache_page(page); + /* We are done with the page. */ end_page_writeback(page); - - /* Mark the mft record dirty, so it gets written back. */ + /* Finally, mark the mft record dirty, so it gets written back. */ mark_mft_record_dirty(ctx->ntfs_ino); ntfs_attr_put_search_ctx(ctx); unmap_mft_record(base_ni); diff --git a/fs/ntfs/inode.c b/fs/ntfs/inode.c index dc4bbe3..7ec0451 100644 --- a/fs/ntfs/inode.c +++ b/fs/ntfs/inode.c @@ -1166,6 +1166,8 @@ err_out: * * Return 0 on success and -errno on error. In the error case, the inode will * have had make_bad_inode() executed on it. + * + * Note this cannot be called for AT_INDEX_ALLOCATION. */ static int ntfs_read_locked_attr_inode(struct inode *base_vi, struct inode *vi) { @@ -1242,8 +1244,8 @@ static int ntfs_read_locked_attr_inode(struct inode *base_vi, struct inode *vi) } } /* - * The encryption flag set in an index root just means to - * compress all files. + * The compressed/sparse flag set in an index root just means + * to compress all files. */ if (NInoMstProtected(ni) && ni->type != AT_INDEX_ROOT) { ntfs_error(vi->i_sb, "Found mst protected attribute " @@ -1319,8 +1321,7 @@ static int ntfs_read_locked_attr_inode(struct inode *base_vi, struct inode *vi) "the mapping pairs array."); goto unm_err_out; } - if ((NInoCompressed(ni) || NInoSparse(ni)) && - ni->type != AT_INDEX_ROOT) { + if (NInoCompressed(ni) || NInoSparse(ni)) { if (a->data.non_resident.compression_unit != 4) { ntfs_error(vi->i_sb, "Found nonstandard " "compression unit (%u instead " diff --git a/fs/ntfs/malloc.h b/fs/ntfs/malloc.h index 3288bcc..006946e 100644 --- a/fs/ntfs/malloc.h +++ b/fs/ntfs/malloc.h @@ -1,7 +1,7 @@ /* * malloc.h - NTFS kernel memory handling. Part of the Linux-NTFS project. * - * Copyright (c) 2001-2004 Anton Altaparmakov + * Copyright (c) 2001-2005 Anton Altaparmakov * * This program/include file is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as published diff --git a/fs/ntfs/runlist.c b/fs/ntfs/runlist.c index f5b2ac9..061b5ff 100644 --- a/fs/ntfs/runlist.c +++ b/fs/ntfs/runlist.c @@ -2,7 +2,7 @@ * runlist.c - NTFS runlist handling code. Part of the Linux-NTFS project. * * Copyright (c) 2001-2005 Anton Altaparmakov - * Copyright (c) 2002 Richard Russon + * Copyright (c) 2002-2005 Richard Russon * * This program/include file is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as published @@ -158,17 +158,21 @@ static inline BOOL ntfs_are_rl_mergeable(runlist_element *dst, BUG_ON(!dst); BUG_ON(!src); - if ((dst->lcn < 0) || (src->lcn < 0)) { /* Are we merging holes? */ - if (dst->lcn == LCN_HOLE && src->lcn == LCN_HOLE) - return TRUE; + /* We can merge unmapped regions even if they are misaligned. */ + if ((dst->lcn == LCN_RL_NOT_MAPPED) && (src->lcn == LCN_RL_NOT_MAPPED)) + return TRUE; + /* If the runs are misaligned, we cannot merge them. */ + if ((dst->vcn + dst->length) != src->vcn) return FALSE; - } - if ((dst->lcn + dst->length) != src->lcn) /* Are the runs contiguous? */ - return FALSE; - if ((dst->vcn + dst->length) != src->vcn) /* Are the runs misaligned? */ - return FALSE; - - return TRUE; + /* If both runs are non-sparse and contiguous, we can merge them. */ + if ((dst->lcn >= 0) && (src->lcn >= 0) && + ((dst->lcn + dst->length) == src->lcn)) + return TRUE; + /* If we are merging two holes, we can merge them. */ + if ((dst->lcn == LCN_HOLE) && (src->lcn == LCN_HOLE)) + return TRUE; + /* Cannot merge. */ + return FALSE; } /** @@ -214,14 +218,15 @@ static inline void __ntfs_rl_merge(runlist_element *dst, runlist_element *src) static inline runlist_element *ntfs_rl_append(runlist_element *dst, int dsize, runlist_element *src, int ssize, int loc) { - BOOL right; - int magic; + BOOL right = FALSE; /* Right end of @src needs merging. */ + int marker; /* End of the inserted runs. */ BUG_ON(!dst); BUG_ON(!src); /* First, check if the right hand end needs merging. */ - right = ntfs_are_rl_mergeable(src + ssize - 1, dst + loc + 1); + if ((loc + 1) < dsize) + right = ntfs_are_rl_mergeable(src + ssize - 1, dst + loc + 1); /* Space required: @dst size + @src size, less one if we merged. */ dst = ntfs_rl_realloc(dst, dsize, dsize + ssize - right); @@ -236,18 +241,19 @@ static inline runlist_element *ntfs_rl_append(runlist_element *dst, if (right) __ntfs_rl_merge(src + ssize - 1, dst + loc + 1); - magic = loc + ssize; + /* First run after the @src runs that have been inserted. */ + marker = loc + ssize + 1; /* Move the tail of @dst out of the way, then copy in @src. */ - ntfs_rl_mm(dst, magic + 1, loc + 1 + right, dsize - loc - 1 - right); + ntfs_rl_mm(dst, marker, loc + 1 + right, dsize - (loc + 1 + right)); ntfs_rl_mc(dst, loc + 1, src, 0, ssize); /* Adjust the size of the preceding hole. */ dst[loc].length = dst[loc + 1].vcn - dst[loc].vcn; /* We may have changed the length of the file, so fix the end marker */ - if (dst[magic + 1].lcn == LCN_ENOENT) - dst[magic + 1].vcn = dst[magic].vcn + dst[magic].length; + if (dst[marker].lcn == LCN_ENOENT) + dst[marker].vcn = dst[marker - 1].vcn + dst[marker - 1].length; return dst; } @@ -279,18 +285,17 @@ static inline runlist_element *ntfs_rl_append(runlist_element *dst, static inline runlist_element *ntfs_rl_insert(runlist_element *dst, int dsize, runlist_element *src, int ssize, int loc) { - BOOL left = FALSE; - BOOL disc = FALSE; /* Discontinuity */ - BOOL hole = FALSE; /* Following a hole */ - int magic; + BOOL left = FALSE; /* Left end of @src needs merging. */ + BOOL disc = FALSE; /* Discontinuity between @dst and @src. */ + int marker; /* End of the inserted runs. */ BUG_ON(!dst); BUG_ON(!src); - /* disc => Discontinuity between the end of @dst and the start of @src. - * This means we might need to insert a hole. - * hole => @dst ends with a hole or an unmapped region which we can - * extend to match the discontinuity. */ + /* + * disc => Discontinuity between the end of @dst and the start of @src. + * This means we might need to insert a "not mapped" run. + */ if (loc == 0) disc = (src[0].vcn > 0); else { @@ -303,58 +308,49 @@ static inline runlist_element *ntfs_rl_insert(runlist_element *dst, merged_length += src->length; disc = (src[0].vcn > dst[loc - 1].vcn + merged_length); - if (disc) - hole = (dst[loc - 1].lcn == LCN_HOLE); } - - /* Space required: @dst size + @src size, less one if we merged, plus - * one if there was a discontinuity, less one for a trailing hole. */ - dst = ntfs_rl_realloc(dst, dsize, dsize + ssize - left + disc - hole); + /* + * Space required: @dst size + @src size, less one if we merged, plus + * one if there was a discontinuity. + */ + dst = ntfs_rl_realloc(dst, dsize, dsize + ssize - left + disc); if (IS_ERR(dst)) return dst; /* * We are guaranteed to succeed from here so can start modifying the * original runlist. */ - if (left) __ntfs_rl_merge(dst + loc - 1, src); - - magic = loc + ssize - left + disc - hole; + /* + * First run after the @src runs that have been inserted. + * Nominally, @marker equals @loc + @ssize, i.e. location + number of + * runs in @src. However, if @left, then the first run in @src has + * been merged with one in @dst. And if @disc, then @dst and @src do + * not meet and we need an extra run to fill the gap. + */ + marker = loc + ssize - left + disc; /* Move the tail of @dst out of the way, then copy in @src. */ - ntfs_rl_mm(dst, magic, loc, dsize - loc); - ntfs_rl_mc(dst, loc + disc - hole, src, left, ssize - left); + ntfs_rl_mm(dst, marker, loc, dsize - loc); + ntfs_rl_mc(dst, loc + disc, src, left, ssize - left); - /* Adjust the VCN of the last run ... */ - if (dst[magic].lcn <= LCN_HOLE) - dst[magic].vcn = dst[magic - 1].vcn + dst[magic - 1].length; + /* Adjust the VCN of the first run after the insertion... */ + dst[marker].vcn = dst[marker - 1].vcn + dst[marker - 1].length; /* ... and the length. */ - if (dst[magic].lcn == LCN_HOLE || dst[magic].lcn == LCN_RL_NOT_MAPPED) - dst[magic].length = dst[magic + 1].vcn - dst[magic].vcn; + if (dst[marker].lcn == LCN_HOLE || dst[marker].lcn == LCN_RL_NOT_MAPPED) + dst[marker].length = dst[marker + 1].vcn - dst[marker].vcn; - /* Writing beyond the end of the file and there's a discontinuity. */ + /* Writing beyond the end of the file and there is a discontinuity. */ if (disc) { - if (hole) - dst[loc - 1].length = dst[loc].vcn - dst[loc - 1].vcn; - else { - if (loc > 0) { - dst[loc].vcn = dst[loc - 1].vcn + - dst[loc - 1].length; - dst[loc].length = dst[loc + 1].vcn - - dst[loc].vcn; - } else { - dst[loc].vcn = 0; - dst[loc].length = dst[loc + 1].vcn; - } - dst[loc].lcn = LCN_RL_NOT_MAPPED; + if (loc > 0) { + dst[loc].vcn = dst[loc - 1].vcn + dst[loc - 1].length; + dst[loc].length = dst[loc + 1].vcn - dst[loc].vcn; + } else { + dst[loc].vcn = 0; + dst[loc].length = dst[loc + 1].vcn; } - - magic += hole; - - if (dst[magic].lcn == LCN_ENOENT) - dst[magic].vcn = dst[magic - 1].vcn + - dst[magic - 1].length; + dst[loc].lcn = LCN_RL_NOT_MAPPED; } return dst; } @@ -385,20 +381,23 @@ static inline runlist_element *ntfs_rl_insert(runlist_element *dst, static inline runlist_element *ntfs_rl_replace(runlist_element *dst, int dsize, runlist_element *src, int ssize, int loc) { - BOOL left = FALSE; - BOOL right; - int magic; + BOOL left = FALSE; /* Left end of @src needs merging. */ + BOOL right = FALSE; /* Right end of @src needs merging. */ + int tail; /* Start of tail of @dst. */ + int marker; /* End of the inserted runs. */ BUG_ON(!dst); BUG_ON(!src); - /* First, merge the left and right ends, if necessary. */ - right = ntfs_are_rl_mergeable(src + ssize - 1, dst + loc + 1); + /* First, see if the left and right ends need merging. */ + if ((loc + 1) < dsize) + right = ntfs_are_rl_mergeable(src + ssize - 1, dst + loc + 1); if (loc > 0) left = ntfs_are_rl_mergeable(dst + loc - 1, src); - - /* Allocate some space. We'll need less if the left, right, or both - * ends were merged. */ + /* + * Allocate some space. We will need less if the left, right, or both + * ends get merged. + */ dst = ntfs_rl_realloc(dst, dsize, dsize + ssize - left - right); if (IS_ERR(dst)) return dst; @@ -406,21 +405,37 @@ static inline runlist_element *ntfs_rl_replace(runlist_element *dst, * We are guaranteed to succeed from here so can start modifying the * original runlists. */ + + /* First, merge the left and right ends, if necessary. */ if (right) __ntfs_rl_merge(src + ssize - 1, dst + loc + 1); if (left) __ntfs_rl_merge(dst + loc - 1, src); - - /* FIXME: What does this mean? (AIA) */ - magic = loc + ssize - left; + /* + * Offset of the tail of @dst. This needs to be moved out of the way + * to make space for the runs to be copied from @src, i.e. the first + * run of the tail of @dst. + * Nominally, @tail equals @loc + 1, i.e. location, skipping the + * replaced run. However, if @right, then one of @dst's runs is + * already merged into @src. + */ + tail = loc + right + 1; + /* + * First run after the @src runs that have been inserted, i.e. where + * the tail of @dst needs to be moved to. + * Nominally, @marker equals @loc + @ssize, i.e. location + number of + * runs in @src. However, if @left, then the first run in @src has + * been merged with one in @dst. + */ + marker = loc + ssize - left; /* Move the tail of @dst out of the way, then copy in @src. */ - ntfs_rl_mm(dst, magic, loc + right + 1, dsize - loc - right - 1); + ntfs_rl_mm(dst, marker, tail, dsize - tail); ntfs_rl_mc(dst, loc, src, left, ssize - left); - /* We may have changed the length of the file, so fix the end marker */ - if (dst[magic].lcn == LCN_ENOENT) - dst[magic].vcn = dst[magic - 1].vcn + dst[magic - 1].length; + /* We may have changed the length of the file, so fix the end marker. */ + if (dsize - tail > 0 && dst[marker].lcn == LCN_ENOENT) + dst[marker].vcn = dst[marker - 1].vcn + dst[marker - 1].length; return dst; } @@ -738,52 +738,15 @@ asmlinkage long sys_fchown(unsigned int fd, uid_t user, gid_t group) return error; } -/* - * Note that while the flag value (low two bits) for sys_open means: - * 00 - read-only - * 01 - write-only - * 10 - read-write - * 11 - special - * it is changed into - * 00 - no permissions needed - * 01 - read-permission - * 10 - write-permission - * 11 - read-write - * for the internal routines (ie open_namei()/follow_link() etc). 00 is - * used by symlinks. - */ -struct file *filp_open(const char * filename, int flags, int mode) -{ - int namei_flags, error; - struct nameidata nd; - - namei_flags = flags; - if ((namei_flags+1) & O_ACCMODE) - namei_flags++; - if (namei_flags & O_TRUNC) - namei_flags |= 2; - - error = open_namei(filename, namei_flags, mode, &nd); - if (!error) - return dentry_open(nd.dentry, nd.mnt, flags); - - return ERR_PTR(error); -} - -EXPORT_SYMBOL(filp_open); - -struct file *dentry_open(struct dentry *dentry, struct vfsmount *mnt, int flags) +static struct file *__dentry_open(struct dentry *dentry, struct vfsmount *mnt, + int flags, struct file *f) { - struct file * f; struct inode *inode; int error; - error = -ENFILE; - f = get_empty_filp(); - if (!f) - goto cleanup_dentry; f->f_flags = flags; - f->f_mode = ((flags+1) & O_ACCMODE) | FMODE_LSEEK | FMODE_PREAD | FMODE_PWRITE; + f->f_mode = ((flags+1) & O_ACCMODE) | FMODE_LSEEK | + FMODE_PREAD | FMODE_PWRITE; inode = dentry->d_inode; if (f->f_mode & FMODE_WRITE) { error = get_write_access(inode); @@ -828,12 +791,63 @@ cleanup_all: f->f_vfsmnt = NULL; cleanup_file: put_filp(f); -cleanup_dentry: dput(dentry); mntput(mnt); return ERR_PTR(error); } +/* + * Note that while the flag value (low two bits) for sys_open means: + * 00 - read-only + * 01 - write-only + * 10 - read-write + * 11 - special + * it is changed into + * 00 - no permissions needed + * 01 - read-permission + * 10 - write-permission + * 11 - read-write + * for the internal routines (ie open_namei()/follow_link() etc). 00 is + * used by symlinks. + */ +struct file *filp_open(const char * filename, int flags, int mode) +{ + int namei_flags, error; + struct nameidata nd; + struct file *f; + + namei_flags = flags; + if ((namei_flags+1) & O_ACCMODE) + namei_flags++; + if (namei_flags & O_TRUNC) + namei_flags |= 2; + + error = -ENFILE; + f = get_empty_filp(); + if (f == NULL) + return ERR_PTR(error); + + error = open_namei(filename, namei_flags, mode, &nd); + if (!error) + return __dentry_open(nd.dentry, nd.mnt, flags, f); + + put_filp(f); + return ERR_PTR(error); +} +EXPORT_SYMBOL(filp_open); + +struct file *dentry_open(struct dentry *dentry, struct vfsmount *mnt, int flags) +{ + int error; + struct file *f; + + error = -ENFILE; + f = get_empty_filp(); + if (f == NULL) + return ERR_PTR(error); + + return __dentry_open(dentry, mnt, flags, f); +} EXPORT_SYMBOL(dentry_open); /* diff --git a/fs/proc/array.c b/fs/proc/array.c index d88d518..d84eeca 100644 --- a/fs/proc/array.c +++ b/fs/proc/array.c @@ -74,6 +74,7 @@ #include <linux/file.h> #include <linux/times.h> #include <linux/cpuset.h> +#include <linux/rcupdate.h> #include <asm/uaccess.h> #include <asm/pgtable.h> @@ -180,12 +181,14 @@ static inline char * task_state(struct task_struct *p, char *buffer) p->gid, p->egid, p->sgid, p->fsgid); read_unlock(&tasklist_lock); task_lock(p); + rcu_read_lock(); if (p->files) fdt = files_fdtable(p->files); buffer += sprintf(buffer, "FDSize:\t%d\n" "Groups:\t", fdt ? fdt->max_fds : 0); + rcu_read_unlock(); group_info = p->group_info; get_group_info(group_info); diff --git a/fs/proc/base.c b/fs/proc/base.c index 23db452..3b33f94 100644 --- a/fs/proc/base.c +++ b/fs/proc/base.c @@ -340,6 +340,54 @@ static int proc_root_link(struct inode *inode, struct dentry **dentry, struct vf return result; } + +/* Same as proc_root_link, but this addionally tries to get fs from other + * threads in the group */ +static int proc_task_root_link(struct inode *inode, struct dentry **dentry, + struct vfsmount **mnt) +{ + struct fs_struct *fs; + int result = -ENOENT; + struct task_struct *leader = proc_task(inode); + + task_lock(leader); + fs = leader->fs; + if (fs) { + atomic_inc(&fs->count); + task_unlock(leader); + } else { + /* Try to get fs from other threads */ + task_unlock(leader); + read_lock(&tasklist_lock); + if (pid_alive(leader)) { + struct task_struct *task = leader; + + while ((task = next_thread(task)) != leader) { + task_lock(task); + fs = task->fs; + if (fs) { + atomic_inc(&fs->count); + task_unlock(task); + break; + } + task_unlock(task); + } + } + read_unlock(&tasklist_lock); + } + + if (fs) { + read_lock(&fs->lock); + *mnt = mntget(fs->rootmnt); + *dentry = dget(fs->root); + read_unlock(&fs->lock); + result = 0; + put_fs_struct(fs); + } + return result; +} + + #define MAY_PTRACE(task) \ (task == current || \ (task->parent == current && \ @@ -471,14 +519,14 @@ static int proc_oom_score(struct task_struct *task, char *buffer) /* permission checks */ -static int proc_check_root(struct inode *inode) +/* If the process being read is separated by chroot from the reading process, + * don't let the reader access the threads. + */ +static int proc_check_chroot(struct dentry *root, struct vfsmount *vfsmnt) { - struct dentry *de, *base, *root; - struct vfsmount *our_vfsmnt, *vfsmnt, *mnt; + struct dentry *de, *base; + struct vfsmount *our_vfsmnt, *mnt; int res = 0; - - if (proc_root_link(inode, &root, &vfsmnt)) /* Ewww... */ - return -ENOENT; read_lock(¤t->fs->lock); our_vfsmnt = mntget(current->fs->rootmnt); base = dget(current->fs->root); @@ -511,6 +559,16 @@ out: goto exit; } +static int proc_check_root(struct inode *inode) +{ + struct dentry *root; + struct vfsmount *vfsmnt; + + if (proc_root_link(inode, &root, &vfsmnt)) /* Ewww... */ + return -ENOENT; + return proc_check_chroot(root, vfsmnt); +} + static int proc_permission(struct inode *inode, int mask, struct nameidata *nd) { if (generic_permission(inode, mask, NULL) != 0) @@ -518,6 +576,20 @@ static int proc_permission(struct inode *inode, int mask, struct nameidata *nd) return proc_check_root(inode); } +static int proc_task_permission(struct inode *inode, int mask, struct nameidata *nd) +{ + struct dentry *root; + struct vfsmount *vfsmnt; + + if (generic_permission(inode, mask, NULL) != 0) + return -EACCES; + + if (proc_task_root_link(inode, &root, &vfsmnt)) + return -ENOENT; + + return proc_check_chroot(root, vfsmnt); +} + extern struct seq_operations proc_pid_maps_op; static int maps_open(struct inode *inode, struct file *file) { @@ -1419,7 +1491,7 @@ static struct inode_operations proc_fd_inode_operations = { static struct inode_operations proc_task_inode_operations = { .lookup = proc_task_lookup, - .permission = proc_permission, + .permission = proc_task_permission, }; #ifdef CONFIG_SECURITY diff --git a/fs/reiserfs/file.c b/fs/reiserfs/file.c index c9f178f..c20babd 100644 --- a/fs/reiserfs/file.c +++ b/fs/reiserfs/file.c @@ -667,7 +667,7 @@ static int reiserfs_allocate_blocks_for_region(struct reiserfs_transaction_handl if (th->t_trans_id) { int err; // update any changes we made to blk count - reiserfs_update_sd(th, inode); + mark_inode_dirty(inode); err = journal_end(th, inode->i_sb, JOURNAL_PER_BALANCE_CNT * 3 + 1 + @@ -855,17 +855,18 @@ static int reiserfs_submit_file_region_for_write(struct reiserfs_transaction_han if (th->t_trans_id) { reiserfs_write_lock(inode->i_sb); - reiserfs_update_sd(th, inode); // And update on-disk metadata + // this sets the proper flags for O_SYNC to trigger a commit + mark_inode_dirty(inode); reiserfs_write_unlock(inode->i_sb); } else - inode->i_sb->s_op->dirty_inode(inode); + mark_inode_dirty(inode); sd_update = 1; } if (th->t_trans_id) { reiserfs_write_lock(inode->i_sb); if (!sd_update) - reiserfs_update_sd(th, inode); + mark_inode_dirty(inode); status = journal_end(th, th->t_super, th->t_blocks_allocated); if (status) retval = status; @@ -1320,7 +1321,7 @@ static ssize_t reiserfs_file_write(struct file *file, /* the file we are going t return err; } reiserfs_update_inode_transaction(inode); - reiserfs_update_sd(&th, inode); + mark_inode_dirty(inode); err = journal_end(&th, inode->i_sb, 1); if (err) { reiserfs_write_unlock(inode->i_sb); diff --git a/fs/reiserfs/inode.c b/fs/reiserfs/inode.c index 1a8a1bf..d76ee6c 100644 --- a/fs/reiserfs/inode.c +++ b/fs/reiserfs/inode.c @@ -2639,6 +2639,12 @@ static int reiserfs_commit_write(struct file *f, struct page *page, } reiserfs_update_inode_transaction(inode); inode->i_size = pos; + /* + * this will just nest into our transaction. It's important + * to use mark_inode_dirty so the inode gets pushed around on the + * dirty lists, and so that O_SYNC works as expected + */ + mark_inode_dirty(inode); reiserfs_update_sd(&myth, inode); update_sd = 1; ret = journal_end(&myth, inode->i_sb, 1); @@ -2649,21 +2655,13 @@ static int reiserfs_commit_write(struct file *f, struct page *page, if (th) { reiserfs_write_lock(inode->i_sb); if (!update_sd) - reiserfs_update_sd(th, inode); + mark_inode_dirty(inode); ret = reiserfs_end_persistent_transaction(th); reiserfs_write_unlock(inode->i_sb); if (ret) goto out; } - /* we test for O_SYNC here so we can commit the transaction - ** for any packed tails the file might have had - */ - if (f && (f->f_flags & O_SYNC)) { - reiserfs_write_lock(inode->i_sb); - ret = reiserfs_commit_for_inode(inode); - reiserfs_write_unlock(inode->i_sb); - } out: return ret; diff --git a/include/asm-alpha/compiler.h b/include/asm-alpha/compiler.h index 399c33b..0a4a8b4 100644 --- a/include/asm-alpha/compiler.h +++ b/include/asm-alpha/compiler.h @@ -98,6 +98,9 @@ #undef inline #undef __inline__ #undef __inline - +#if __GNUC__ == 3 && __GNUC_MINOR__ >= 1 || __GNUC__ > 3 +#undef __always_inline +#define __always_inline inline __attribute__((always_inline)) +#endif #endif /* __ALPHA_COMPILER_H */ diff --git a/include/asm-alpha/futex.h b/include/asm-alpha/futex.h index 2cac5ec..9feff4ce 100644 --- a/include/asm-alpha/futex.h +++ b/include/asm-alpha/futex.h @@ -14,7 +14,7 @@ futex_atomic_op_inuser (int encoded_op, int __user *uaddr) int cmp = (encoded_op >> 24) & 15; int oparg = (encoded_op << 8) >> 20; int cmparg = (encoded_op << 20) >> 20; - int oldval = 0, ret, tem; + int oldval = 0, ret; if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28)) oparg = 1 << oparg; diff --git a/include/asm-alpha/pgtable.h b/include/asm-alpha/pgtable.h index 22b53e3..8393bf3 100644 --- a/include/asm-alpha/pgtable.h +++ b/include/asm-alpha/pgtable.h @@ -339,13 +339,6 @@ extern inline pte_t mk_swap_pte(unsigned long type, unsigned long offset) #define kern_addr_valid(addr) (1) #endif -#define io_remap_page_range(vma, start, busaddr, size, prot) \ -({ \ - void *va = (void __force *)ioremap(busaddr, size); \ - unsigned long pfn = virt_to_phys(va) >> PAGE_SHIFT; \ - remap_pfn_range(vma, start, pfn, size, prot); \ -}) - #define io_remap_pfn_range(vma, start, pfn, size, prot) \ remap_pfn_range(vma, start, pfn, size, prot) diff --git a/include/asm-arm/arch-aaec2000/memory.h b/include/asm-arm/arch-aaec2000/memory.h index 681b6a6..79c9081 100644 --- a/include/asm-arm/arch-aaec2000/memory.h +++ b/include/asm-arm/arch-aaec2000/memory.h @@ -64,10 +64,6 @@ #define NODE_MAX_MEM_SHIFT 26 #define NODE_MAX_MEM_SIZE (1 << NODE_MAX_MEM_SHIFT) -#else - -#define PFN_TO_NID(addr) (0) - #endif /* CONFIG_DISCONTIGMEM */ #endif /* __ASM_ARCH_MEMORY_H */ diff --git a/include/asm-arm/arch-iop3xx/memory.h b/include/asm-arm/arch-iop3xx/memory.h index dc4735c..45351f5 100644 --- a/include/asm-arm/arch-iop3xx/memory.h +++ b/include/asm-arm/arch-iop3xx/memory.h @@ -36,6 +36,4 @@ #endif -#define PFN_TO_NID(addr) (0) - #endif diff --git a/include/asm-arm/arch-ixp2000/ixp2000-regs.h b/include/asm-arm/arch-ixp2000/ixp2000-regs.h index 75623f8..32aece0 100644 --- a/include/asm-arm/arch-ixp2000/ixp2000-regs.h +++ b/include/asm-arm/arch-ixp2000/ixp2000-regs.h @@ -370,8 +370,6 @@ #define GLOBAL_REG_BASE (IXP2000_GLOBAL_REG_VIRT_BASE + 0x0a00) #define GLOBAL_REG(x) (volatile unsigned long*)(GLOBAL_REG_BASE | (x)) -#define IXP2000_PROD_ID GLOBAL_REG(0x00) - #define IXP2000_MAJ_PROD_TYPE_MASK 0x001F0000 #define IXP2000_MAJ_PROD_TYPE_IXP2000 0x00000000 #define IXP2000_MIN_PROD_TYPE_MASK 0x0000FF00 diff --git a/include/asm-arm/arch-ixp2000/platform.h b/include/asm-arm/arch-ixp2000/platform.h index c0caf3e..abdcf51 100644 --- a/include/asm-arm/arch-ixp2000/platform.h +++ b/include/asm-arm/arch-ixp2000/platform.h @@ -31,20 +31,24 @@ #include <asm/system.h> /* Pickup local_irq_ functions */ -static inline void ixp2000_reg_write(volatile unsigned long *reg, unsigned long val) +static inline void ixp2000_reg_write(volatile void *reg, unsigned long val) { - volatile unsigned long dummy; + unsigned long dummy; unsigned long flags; local_irq_save(flags); - *reg = val; + *((volatile unsigned long *)reg) = val; barrier(); - dummy = *reg; + dummy = *((volatile unsigned long *)reg); local_irq_restore(flags); } #else -#define ixp2000_reg_write(reg, val) (*reg = val) +static inline void ixp2000_reg_write(volatile void *reg, unsigned long val) +{ + *((volatile unsigned long *)reg) = val; +} #endif /* IXDP2400 || IXDP2401 */ +#define ixp2000_reg_read(reg) (*((volatile unsigned long *)reg)) /* * Boards may multiplex different devices on the 2nd channel of @@ -84,7 +88,7 @@ void ixp2000_release_slowport(struct slowport_cfg *); */ static inline unsigned ixp2000_has_broken_slowport(void) { - unsigned long id = *IXP2000_PROD_ID; + unsigned long id = *IXP2000_PRODUCT_ID; unsigned long id_prod = id & (IXP2000_MAJ_PROD_TYPE_MASK | IXP2000_MIN_PROD_TYPE_MASK); return (((id_prod == diff --git a/include/asm-arm/arch-lh7a40x/memory.h b/include/asm-arm/arch-lh7a40x/memory.h index 7e2fea3..c650e6f 100644 --- a/include/asm-arm/arch-lh7a40x/memory.h +++ b/include/asm-arm/arch-lh7a40x/memory.h @@ -85,10 +85,6 @@ (((unsigned long)(addr) & 0x01ffffff) >> PAGE_SHIFT) # endif -#else - -# define PFN_TO_NID(addr) (0) - #endif #endif diff --git a/include/asm-arm/arch-omap/memory.h b/include/asm-arm/arch-omap/memory.h index 84f81e3..ef32d61 100644 --- a/include/asm-arm/arch-omap/memory.h +++ b/include/asm-arm/arch-omap/memory.h @@ -86,6 +86,5 @@ #endif /* CONFIG_ARCH_OMAP1510 */ -#define PHYS_TO_NID(addr) (0) #endif diff --git a/include/asm-arm/arch-pxa/akita.h b/include/asm-arm/arch-pxa/akita.h new file mode 100644 index 0000000..4a1fbcf --- /dev/null +++ b/include/asm-arm/arch-pxa/akita.h @@ -0,0 +1,30 @@ +/* + * Hardware specific definitions for SL-C1000 (Akita) + * + * Copyright (c) 2005 Richard Purdie + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + */ + +/* Akita IO Expander GPIOs */ + +#define AKITA_IOEXP_RESERVED_7 (1 << 7) +#define AKITA_IOEXP_IR_ON (1 << 6) +#define AKITA_IOEXP_AKIN_PULLUP (1 << 5) +#define AKITA_IOEXP_BACKLIGHT_CONT (1 << 4) +#define AKITA_IOEXP_BACKLIGHT_ON (1 << 3) +#define AKITA_IOEXP_MIC_BIAS (1 << 2) +#define AKITA_IOEXP_RESERVED_1 (1 << 1) +#define AKITA_IOEXP_RESERVED_0 (1 << 0) + +/* Direction Bitfield 0=output 1=input */ +#define AKITA_IOEXP_IO_DIR 0 +/* Default Values */ +#define AKITA_IOEXP_IO_OUT (AKITA_IOEXP_IR_ON | AKITA_IOEXP_AKIN_PULLUP) + +void akita_set_ioexp(struct device *dev, unsigned char bitmask); +void akita_reset_ioexp(struct device *dev, unsigned char bitmask); + diff --git a/include/asm-arm/arch-pxa/corgi.h b/include/asm-arm/arch-pxa/corgi.h index 4b7aa0b..e554caa 100644 --- a/include/asm-arm/arch-pxa/corgi.h +++ b/include/asm-arm/arch-pxa/corgi.h @@ -106,17 +106,5 @@ extern struct platform_device corgiscoop_device; extern struct platform_device corgissp_device; extern struct platform_device corgifb_device; -/* - * External Functions - */ -extern unsigned long corgi_ssp_ads7846_putget(unsigned long); -extern unsigned long corgi_ssp_ads7846_get(void); -extern void corgi_ssp_ads7846_put(unsigned long data); -extern void corgi_ssp_ads7846_lock(void); -extern void corgi_ssp_ads7846_unlock(void); -extern void corgi_ssp_lcdtg_send (unsigned char adrs, unsigned char data); -extern void corgi_ssp_blduty_set(int duty); -extern int corgi_ssp_max1111_get(unsigned long data); - #endif /* __ASM_ARCH_CORGI_H */ diff --git a/include/asm-arm/arch-pxa/memory.h b/include/asm-arm/arch-pxa/memory.h index 217a80b..58bad97 100644 --- a/include/asm-arm/arch-pxa/memory.h +++ b/include/asm-arm/arch-pxa/memory.h @@ -67,10 +67,6 @@ #define LOCAL_MAP_NR(addr) \ (((unsigned long)(addr) & 0x03ffffff) >> PAGE_SHIFT) -#else - -#define PFN_TO_NID(addr) (0) - #endif #endif diff --git a/include/asm-arm/arch-pxa/poodle.h b/include/asm-arm/arch-pxa/poodle.h index 58bda9d..6b5ac51 100644 --- a/include/asm-arm/arch-pxa/poodle.h +++ b/include/asm-arm/arch-pxa/poodle.h @@ -37,24 +37,25 @@ #define POODLE_GPIO_nSD_DETECT (9) #define POODLE_GPIO_MAIN_BAT_LOW (13) #define POODLE_GPIO_BAT_COVER (13) +#define POODLE_GPIO_USB_PULLUP (20) #define POODLE_GPIO_ADC_TEMP_ON (21) #define POODLE_GPIO_BYPASS_ON (36) #define POODLE_GPIO_CHRG_ON (38) #define POODLE_GPIO_CHRG_FULL (16) /* PXA GPIOs */ -#define POODLE_IRQ_GPIO_ON_KEY IRQ_GPIO0 -#define POODLE_IRQ_GPIO_AC_IN IRQ_GPIO1 -#define POODLE_IRQ_GPIO_HP_IN IRQ_GPIO4 -#define POODLE_IRQ_GPIO_CO IRQ_GPIO16 -#define POODLE_IRQ_GPIO_TP_INT IRQ_GPIO5 -#define POODLE_IRQ_GPIO_WAKEUP IRQ_GPIO11 -#define POODLE_IRQ_GPIO_GA_INT IRQ_GPIO10 -#define POODLE_IRQ_GPIO_CF_IRQ IRQ_GPIO17 -#define POODLE_IRQ_GPIO_CF_CD IRQ_GPIO14 -#define POODLE_IRQ_GPIO_nSD_INT IRQ_GPIO8 -#define POODLE_IRQ_GPIO_nSD_DETECT IRQ_GPIO9 -#define POODLE_IRQ_GPIO_MAIN_BAT_LOW IRQ_GPIO13 +#define POODLE_IRQ_GPIO_ON_KEY IRQ_GPIO(0) +#define POODLE_IRQ_GPIO_AC_IN IRQ_GPIO(1) +#define POODLE_IRQ_GPIO_HP_IN IRQ_GPIO(4) +#define POODLE_IRQ_GPIO_CO IRQ_GPIO(16) +#define POODLE_IRQ_GPIO_TP_INT IRQ_GPIO(5) +#define POODLE_IRQ_GPIO_WAKEUP IRQ_GPIO(11) +#define POODLE_IRQ_GPIO_GA_INT IRQ_GPIO(10) +#define POODLE_IRQ_GPIO_CF_IRQ IRQ_GPIO(17) +#define POODLE_IRQ_GPIO_CF_CD IRQ_GPIO(14) +#define POODLE_IRQ_GPIO_nSD_INT IRQ_GPIO(8) +#define POODLE_IRQ_GPIO_nSD_DETECT IRQ_GPIO(9) +#define POODLE_IRQ_GPIO_MAIN_BAT_LOW IRQ_GPIO(13) /* SCOOP GPIOs */ #define POODLE_SCOOP_CHARGE_ON SCOOP_GPCR_PA11 diff --git a/include/asm-arm/arch-pxa/sharpsl.h b/include/asm-arm/arch-pxa/sharpsl.h new file mode 100644 index 0000000..311f2bb --- /dev/null +++ b/include/asm-arm/arch-pxa/sharpsl.h @@ -0,0 +1,32 @@ +/* + * SharpSL SSP Driver + */ + +unsigned long corgi_ssp_ads7846_putget(unsigned long); +unsigned long corgi_ssp_ads7846_get(void); +void corgi_ssp_ads7846_put(unsigned long data); +void corgi_ssp_ads7846_lock(void); +void corgi_ssp_ads7846_unlock(void); +void corgi_ssp_lcdtg_send (unsigned char adrs, unsigned char data); +void corgi_ssp_blduty_set(int duty); +int corgi_ssp_max1111_get(unsigned long data); + +/* + * SharpSL Touchscreen Driver + */ + +struct corgits_machinfo { + unsigned long (*get_hsync_len)(void); + void (*put_hsync)(void); + void (*wait_hsync)(void); +}; + +/* + * SharpSL Backlight + */ + +struct corgibl_machinfo { + int max_intensity; + void (*set_bl_intensity)(int intensity); +}; + diff --git a/include/asm-arm/arch-pxa/spitz.h b/include/asm-arm/arch-pxa/spitz.h new file mode 100644 index 0000000..62e1fe4 --- /dev/null +++ b/include/asm-arm/arch-pxa/spitz.h @@ -0,0 +1,158 @@ +/* + * Hardware specific definitions for SL-Cx000 series of PDAs + * + * Copyright (c) 2005 Alexander Wykes + * Copyright (c) 2005 Richard Purdie + * + * Based on Sharp's 2.4 kernel patches + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + */ +#ifndef __ASM_ARCH_SPITZ_H +#define __ASM_ARCH_SPITZ_H 1 +#endif + +/* Spitz/Akita GPIOs */ + +#define SPITZ_GPIO_KEY_INT (0) /* Key Interrupt */ +#define SPITZ_GPIO_RESET (1) +#define SPITZ_GPIO_nSD_DETECT (9) +#define SPITZ_GPIO_TP_INT (11) /* Touch Panel interrupt */ +#define SPITZ_GPIO_AK_INT (13) /* Remote Control */ +#define SPITZ_GPIO_ADS7846_CS (14) +#define SPITZ_GPIO_SYNC (16) +#define SPITZ_GPIO_MAX1111_CS (20) +#define SPITZ_GPIO_FATAL_BAT (21) +#define SPITZ_GPIO_HSYNC (22) +#define SPITZ_GPIO_nSD_CLK (32) +#define SPITZ_GPIO_USB_DEVICE (35) +#define SPITZ_GPIO_USB_HOST (37) +#define SPITZ_GPIO_USB_CONNECT (41) +#define SPITZ_GPIO_LCDCON_CS (53) +#define SPITZ_GPIO_nPCE (54) +#define SPITZ_GPIO_nSD_WP (81) +#define SPITZ_GPIO_ON_RESET (89) +#define SPITZ_GPIO_BAT_COVER (90) +#define SPITZ_GPIO_CF_CD (94) +#define SPITZ_GPIO_ON_KEY (95) +#define SPITZ_GPIO_SWA (97) +#define SPITZ_GPIO_SWB (96) +#define SPITZ_GPIO_CHRG_FULL (101) +#define SPITZ_GPIO_CO (101) +#define SPITZ_GPIO_CF_IRQ (105) +#define SPITZ_GPIO_AC_IN (115) +#define SPITZ_GPIO_HP_IN (116) + +/* Spitz Only GPIOs */ + +#define SPITZ_GPIO_CF2_IRQ (106) /* CF slot1 Ready */ +#define SPITZ_GPIO_CF2_CD (93) + + +/* Spitz/Akita Keyboard Definitions */ + +#define SPITZ_KEY_STROBE_NUM (11) +#define SPITZ_KEY_SENSE_NUM (7) +#define SPITZ_GPIO_G0_STROBE_BIT 0x0f800000 +#define SPITZ_GPIO_G1_STROBE_BIT 0x00100000 +#define SPITZ_GPIO_G2_STROBE_BIT 0x01000000 +#define SPITZ_GPIO_G3_STROBE_BIT 0x00041880 +#define SPITZ_GPIO_G0_SENSE_BIT 0x00021000 +#define SPITZ_GPIO_G1_SENSE_BIT 0x000000d4 +#define SPITZ_GPIO_G2_SENSE_BIT 0x08000000 +#define SPITZ_GPIO_G3_SENSE_BIT 0x00000000 + +#define SPITZ_GPIO_KEY_STROBE0 88 +#define SPITZ_GPIO_KEY_STROBE1 23 +#define SPITZ_GPIO_KEY_STROBE2 24 +#define SPITZ_GPIO_KEY_STROBE3 25 +#define SPITZ_GPIO_KEY_STROBE4 26 +#define SPITZ_GPIO_KEY_STROBE5 27 +#define SPITZ_GPIO_KEY_STROBE6 52 +#define SPITZ_GPIO_KEY_STROBE7 103 +#define SPITZ_GPIO_KEY_STROBE8 107 +#define SPITZ_GPIO_KEY_STROBE9 108 +#define SPITZ_GPIO_KEY_STROBE10 114 + +#define SPITZ_GPIO_KEY_SENSE0 12 +#define SPITZ_GPIO_KEY_SENSE1 17 +#define SPITZ_GPIO_KEY_SENSE2 91 +#define SPITZ_GPIO_KEY_SENSE3 34 +#define SPITZ_GPIO_KEY_SENSE4 36 +#define SPITZ_GPIO_KEY_SENSE5 38 +#define SPITZ_GPIO_KEY_SENSE6 39 + + +/* Spitz Scoop Device (No. 1) GPIOs */ +/* Suspend States in comments */ +#define SPITZ_SCP_LED_GREEN SCOOP_GPCR_PA11 /* Keep */ +#define SPITZ_SCP_JK_B SCOOP_GPCR_PA12 /* Keep */ +#define SPITZ_SCP_CHRG_ON SCOOP_GPCR_PA13 /* Keep */ +#define SPITZ_SCP_MUTE_L SCOOP_GPCR_PA14 /* Low */ +#define SPITZ_SCP_MUTE_R SCOOP_GPCR_PA15 /* Low */ +#define SPITZ_SCP_CF_POWER SCOOP_GPCR_PA16 /* Keep */ +#define SPITZ_SCP_LED_ORANGE SCOOP_GPCR_PA17 /* Keep */ +#define SPITZ_SCP_JK_A SCOOP_GPCR_PA18 /* Low */ +#define SPITZ_SCP_ADC_TEMP_ON SCOOP_GPCR_PA19 /* Low */ + +#define SPITZ_SCP_IO_DIR (SPITZ_SCP_LED_GREEN | SPITZ_SCP_JK_B | SPITZ_SCP_CHRG_ON | \ + SPITZ_SCP_MUTE_L | SPITZ_SCP_MUTE_R | SPITZ_SCP_LED_ORANGE | \ + SPITZ_SCP_CF_POWER | SPITZ_SCP_JK_A | SPITZ_SCP_ADC_TEMP_ON) +#define SPITZ_SCP_IO_OUT (SPITZ_SCP_CHRG_ON | SPITZ_SCP_MUTE_L | SPITZ_SCP_MUTE_R) +#define SPITZ_SCP_SUS_CLR (SPITZ_SCP_MUTE_L | SPITZ_SCP_MUTE_R | SPITZ_SCP_JK_A | SPITZ_SCP_ADC_TEMP_ON) +#define SPITZ_SCP_SUS_SET 0 + +/* Spitz Scoop Device (No. 2) GPIOs */ +/* Suspend States in comments */ +#define SPITZ_SCP2_IR_ON SCOOP_GPCR_PA11 /* High */ +#define SPITZ_SCP2_AKIN_PULLUP SCOOP_GPCR_PA12 /* Keep */ +#define SPITZ_SCP2_RESERVED_1 SCOOP_GPCR_PA13 /* High */ +#define SPITZ_SCP2_RESERVED_2 SCOOP_GPCR_PA14 /* Low */ +#define SPITZ_SCP2_RESERVED_3 SCOOP_GPCR_PA15 /* Low */ +#define SPITZ_SCP2_RESERVED_4 SCOOP_GPCR_PA16 /* Low */ +#define SPITZ_SCP2_BACKLIGHT_CONT SCOOP_GPCR_PA17 /* Low */ +#define SPITZ_SCP2_BACKLIGHT_ON SCOOP_GPCR_PA18 /* Low */ +#define SPITZ_SCP2_MIC_BIAS SCOOP_GPCR_PA19 /* Low */ + +#define SPITZ_SCP2_IO_DIR (SPITZ_SCP2_IR_ON | SPITZ_SCP2_AKIN_PULLUP | SPITZ_SCP2_RESERVED_1 | \ + SPITZ_SCP2_RESERVED_2 | SPITZ_SCP2_RESERVED_3 | SPITZ_SCP2_RESERVED_4 | \ + SPITZ_SCP2_BACKLIGHT_CONT | SPITZ_SCP2_BACKLIGHT_ON | SPITZ_SCP2_MIC_BIAS) + +#define SPITZ_SCP2_IO_OUT (SPITZ_SCP2_IR_ON | SPITZ_SCP2_AKIN_PULLUP | SPITZ_SCP2_RESERVED_1) +#define SPITZ_SCP2_SUS_CLR (SPITZ_SCP2_RESERVED_2 | SPITZ_SCP2_RESERVED_3 | SPITZ_SCP2_RESERVED_4 | \ + SPITZ_SCP2_BACKLIGHT_CONT | SPITZ_SCP2_BACKLIGHT_ON | SPITZ_SCP2_MIC_BIAS) +#define SPITZ_SCP2_SUS_SET (SPITZ_SCP2_IR_ON | SPITZ_SCP2_RESERVED_1) + + +/* Spitz IRQ Definitions */ + +#define SPITZ_IRQ_GPIO_KEY_INT IRQ_GPIO(SPITZ_GPIO_KEY_INT) +#define SPITZ_IRQ_GPIO_AC_IN IRQ_GPIO(SPITZ_GPIO_AC_IN) +#define SPITZ_IRQ_GPIO_AK_INT IRQ_GPIO(SPITZ_GPIO_AK_INT) +#define SPITZ_IRQ_GPIO_HP_IN IRQ_GPIO(SPITZ_GPIO_HP_IN) +#define SPITZ_IRQ_GPIO_TP_INT IRQ_GPIO(SPITZ_GPIO_TP_INT) +#define SPITZ_IRQ_GPIO_SYNC IRQ_GPIO(SPITZ_GPIO_SYNC) +#define SPITZ_IRQ_GPIO_ON_KEY IRQ_GPIO(SPITZ_GPIO_ON_KEY) +#define SPITZ_IRQ_GPIO_SWA IRQ_GPIO(SPITZ_GPIO_SWA) +#define SPITZ_IRQ_GPIO_SWB IRQ_GPIO(SPITZ_GPIO_SWB) +#define SPITZ_IRQ_GPIO_BAT_COVER IRQ_GPIO(SPITZ_GPIO_BAT_COVER) +#define SPITZ_IRQ_GPIO_FATAL_BAT IRQ_GPIO(SPITZ_GPIO_FATAL_BAT) +#define SPITZ_IRQ_GPIO_CO IRQ_GPIO(SPITZ_GPIO_CO) +#define SPITZ_IRQ_GPIO_CF_IRQ IRQ_GPIO(SPITZ_GPIO_CF_IRQ) +#define SPITZ_IRQ_GPIO_CF_CD IRQ_GPIO(SPITZ_GPIO_CF_CD) +#define SPITZ_IRQ_GPIO_CF2_IRQ IRQ_GPIO(SPITZ_GPIO_CF2_IRQ) +#define SPITZ_IRQ_GPIO_nSD_INT IRQ_GPIO(SPITZ_GPIO_nSD_INT) +#define SPITZ_IRQ_GPIO_nSD_DETECT IRQ_GPIO(SPITZ_GPIO_nSD_DETECT) + +/* + * Shared data structures + */ +extern struct platform_device spitzscoop_device; +extern struct platform_device spitzscoop2_device; +extern struct platform_device spitzssp_device; +extern struct sharpsl_charger_machinfo spitz_pm_machinfo; + +extern void spitz_lcd_power(int on); diff --git a/include/asm-arm/arch-sa1100/memory.h b/include/asm-arm/arch-sa1100/memory.h index 32d3d5b..8743ff5 100644 --- a/include/asm-arm/arch-sa1100/memory.h +++ b/include/asm-arm/arch-sa1100/memory.h @@ -99,10 +99,6 @@ __arch_adjust_zones(int node, unsigned long *size, unsigned long *holes) #define LOCAL_MAP_NR(addr) \ (((unsigned long)(addr) & 0x07ffffff) >> PAGE_SHIFT) -#else - -#define PFN_TO_NID(addr) (0) - #endif #endif diff --git a/include/asm-arm/futex.h b/include/asm-arm/futex.h index 2cac5ec..9feff4ce 100644 --- a/include/asm-arm/futex.h +++ b/include/asm-arm/futex.h @@ -14,7 +14,7 @@ futex_atomic_op_inuser (int encoded_op, int __user *uaddr) int cmp = (encoded_op >> 24) & 15; int oparg = (encoded_op << 8) >> 20; int cmparg = (encoded_op << 20) >> 20; - int oldval = 0, ret, tem; + int oldval = 0, ret; if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28)) oparg = 1 << oparg; diff --git a/include/asm-arm/hardware/arm_twd.h b/include/asm-arm/hardware/arm_twd.h new file mode 100644 index 0000000..131d5b4 --- /dev/null +++ b/include/asm-arm/hardware/arm_twd.h @@ -0,0 +1,16 @@ +#ifndef __ASM_HARDWARE_TWD_H +#define __ASM_HARDWARE_TWD_H + +#define TWD_TIMER_LOAD 0x00 +#define TWD_TIMER_COUNTER 0x04 +#define TWD_TIMER_CONTROL 0x08 +#define TWD_TIMER_INTSTAT 0x0C + +#define TWD_WDOG_LOAD 0x20 +#define TWD_WDOG_COUNTER 0x24 +#define TWD_WDOG_CONTROL 0x28 +#define TWD_WDOG_INTSTAT 0x2C +#define TWD_WDOG_RESETSTAT 0x30 +#define TWD_WDOG_DISABLE 0x34 + +#endif diff --git a/include/asm-arm/mach/arch.h b/include/asm-arm/mach/arch.h index 56c6bf4..4fa9508 100644 --- a/include/asm-arm/mach/arch.h +++ b/include/asm-arm/mach/arch.h @@ -50,7 +50,7 @@ struct machine_desc { */ #define MACHINE_START(_type,_name) \ const struct machine_desc __mach_desc_##_type \ - __attribute__((__section__(".arch.info"))) = { \ + __attribute__((__section__(".arch.info.init"))) = { \ .nr = MACH_TYPE_##_type, \ .name = _name, diff --git a/include/asm-arm/memory.h b/include/asm-arm/memory.h index e47bea7..a8a933a 100644 --- a/include/asm-arm/memory.h +++ b/include/asm-arm/memory.h @@ -160,12 +160,25 @@ static inline __deprecated void *bus_to_virt(unsigned long x) #define page_to_pfn(page) \ (( (page) - page_zone(page)->zone_mem_map) \ + page_zone(page)->zone_start_pfn) + #define pfn_to_page(pfn) \ (PFN_TO_MAPBASE(pfn) + LOCAL_MAP_NR((pfn) << PAGE_SHIFT)) -#define pfn_valid(pfn) (PFN_TO_NID(pfn) < MAX_NUMNODES) + +#define pfn_valid(pfn) \ + ({ \ + unsigned int nid = PFN_TO_NID(pfn); \ + int valid = nid < MAX_NUMNODES; \ + if (valid) { \ + pg_data_t *node = NODE_DATA(nid); \ + valid = (pfn - node->node_start_pfn) < \ + node->node_spanned_pages; \ + } \ + valid; \ + }) #define virt_to_page(kaddr) \ (ADDR_TO_MAPBASE(kaddr) + LOCAL_MAP_NR(kaddr)) + #define virt_addr_valid(kaddr) (KVADDR_TO_NID(kaddr) < MAX_NUMNODES) /* diff --git a/include/asm-arm/pgtable.h b/include/asm-arm/pgtable.h index 478c49b..366bafb 100644 --- a/include/asm-arm/pgtable.h +++ b/include/asm-arm/pgtable.h @@ -445,12 +445,9 @@ extern pgd_t swapper_pg_dir[PTRS_PER_PGD]; #define HAVE_ARCH_UNMAPPED_AREA /* - * remap a physical address `phys' of size `size' with page protection `prot' + * remap a physical page `pfn' of size `size' with page protection `prot' * into virtual address `from' */ -#define io_remap_page_range(vma,from,phys,size,prot) \ - remap_pfn_range(vma, from, (phys) >> PAGE_SHIFT, size, prot) - #define io_remap_pfn_range(vma,from,pfn,size,prot) \ remap_pfn_range(vma, from, pfn, size, prot) diff --git a/include/asm-arm/setup.h b/include/asm-arm/setup.h index adcbd79..ea3ed24 100644 --- a/include/asm-arm/setup.h +++ b/include/asm-arm/setup.h @@ -171,7 +171,7 @@ struct tagtable { int (*parse)(const struct tag *); }; -#define __tag __attribute_used__ __attribute__((__section__(".taglist"))) +#define __tag __attribute_used__ __attribute__((__section__(".taglist.init"))) #define __tagtable(tag, fn) \ static struct tagtable __tagtable_##fn __tag = { tag, fn } @@ -213,6 +213,6 @@ struct early_params { #define __early_param(name,fn) \ static struct early_params __early_##fn __attribute_used__ \ -__attribute__((__section__("__early_param"))) = { name, fn } +__attribute__((__section__(".early_param.init"))) = { name, fn } #endif diff --git a/include/asm-arm26/futex.h b/include/asm-arm26/futex.h index 2cac5ec..9feff4ce 100644 --- a/include/asm-arm26/futex.h +++ b/include/asm-arm26/futex.h @@ -14,7 +14,7 @@ futex_atomic_op_inuser (int encoded_op, int __user *uaddr) int cmp = (encoded_op >> 24) & 15; int oparg = (encoded_op << 8) >> 20; int cmparg = (encoded_op << 20) >> 20; - int oldval = 0, ret, tem; + int oldval = 0, ret; if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28)) oparg = 1 << oparg; diff --git a/include/asm-arm26/pgtable.h b/include/asm-arm26/pgtable.h index 4a0a00d..f602cf5 100644 --- a/include/asm-arm26/pgtable.h +++ b/include/asm-arm26/pgtable.h @@ -294,12 +294,9 @@ static inline pte_t mk_pte_phys(unsigned long physpage, pgprot_t pgprot) #include <asm-generic/pgtable.h> /* - * remap a physical address `phys' of size `size' with page protection `prot' + * remap a physical page `pfn' of size `size' with page protection `prot' * into virtual address `from' */ -#define io_remap_page_range(vma,from,phys,size,prot) \ - remap_pfn_range(vma, from, (phys) >> PAGE_SHIFT, size, prot) - #define io_remap_pfn_range(vma,from,pfn,size,prot) \ remap_pfn_range(vma, from, pfn, size, prot) diff --git a/include/asm-cris/futex.h b/include/asm-cris/futex.h index 2cac5ec..9feff4ce 100644 --- a/include/asm-cris/futex.h +++ b/include/asm-cris/futex.h @@ -14,7 +14,7 @@ futex_atomic_op_inuser (int encoded_op, int __user *uaddr) int cmp = (encoded_op >> 24) & 15; int oparg = (encoded_op << 8) >> 20; int cmparg = (encoded_op << 20) >> 20; - int oldval = 0, ret, tem; + int oldval = 0, ret; if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28)) oparg = 1 << oparg; diff --git a/include/asm-frv/futex.h b/include/asm-frv/futex.h index 2cac5ec..9feff4ce 100644 --- a/include/asm-frv/futex.h +++ b/include/asm-frv/futex.h @@ -14,7 +14,7 @@ futex_atomic_op_inuser (int encoded_op, int __user *uaddr) int cmp = (encoded_op >> 24) & 15; int oparg = (encoded_op << 8) >> 20; int cmparg = (encoded_op << 20) >> 20; - int oldval = 0, ret, tem; + int oldval = 0, ret; if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28)) oparg = 1 << oparg; diff --git a/include/asm-frv/pgtable.h b/include/asm-frv/pgtable.h index d0a9c2f..473fb4b 100644 --- a/include/asm-frv/pgtable.h +++ b/include/asm-frv/pgtable.h @@ -500,9 +500,6 @@ static inline int pte_file(pte_t pte) #define PageSkip(page) (0) #define kern_addr_valid(addr) (1) -#define io_remap_page_range(vma, vaddr, paddr, size, prot) \ - remap_pfn_range(vma, vaddr, (paddr) >> PAGE_SHIFT, size, prot) - #define io_remap_pfn_range(vma, vaddr, pfn, size, prot) \ remap_pfn_range(vma, vaddr, pfn, size, prot) diff --git a/include/asm-h8300/futex.h b/include/asm-h8300/futex.h index 2cac5ec..9feff4ce 100644 --- a/include/asm-h8300/futex.h +++ b/include/asm-h8300/futex.h @@ -14,7 +14,7 @@ futex_atomic_op_inuser (int encoded_op, int __user *uaddr) int cmp = (encoded_op >> 24) & 15; int oparg = (encoded_op << 8) >> 20; int cmparg = (encoded_op << 20) >> 20; - int oldval = 0, ret, tem; + int oldval = 0, ret; if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28)) oparg = 1 << oparg; diff --git a/include/asm-h8300/pgtable.h b/include/asm-h8300/pgtable.h index 69076eb..f6e296f 100644 --- a/include/asm-h8300/pgtable.h +++ b/include/asm-h8300/pgtable.h @@ -52,8 +52,6 @@ extern int is_in_rom(unsigned long); * No page table caches to initialise */ #define pgtable_cache_init() do { } while (0) -#define io_remap_page_range(vma, vaddr, paddr, size, prot) \ - remap_pfn_range(vma, vaddr, (paddr) >> PAGE_SHIFT, size, prot) #define io_remap_pfn_range(vma, vaddr, pfn, size, prot) \ remap_pfn_range(vma, vaddr, pfn, size, prot) diff --git a/include/asm-i386/futex.h b/include/asm-i386/futex.h index 44b9db8..e7a271d 100644 --- a/include/asm-i386/futex.h +++ b/include/asm-i386/futex.h @@ -61,7 +61,7 @@ futex_atomic_op_inuser (int encoded_op, int __user *uaddr) if (op == FUTEX_OP_SET) __futex_atomic_op1("xchgl %0, %2", ret, oldval, uaddr, oparg); else { -#ifndef CONFIG_X86_BSWAP +#if !defined(CONFIG_X86_BSWAP) && !defined(CONFIG_UML) if (boot_cpu_data.x86 == 3) ret = -ENOSYS; else diff --git a/include/asm-i386/pgtable.h b/include/asm-i386/pgtable.h index 47bc1ff..d101ac4 100644 --- a/include/asm-i386/pgtable.h +++ b/include/asm-i386/pgtable.h @@ -431,9 +431,6 @@ extern void noexec_setup(const char *str); #define kern_addr_valid(addr) (1) #endif /* CONFIG_FLATMEM */ -#define io_remap_page_range(vma, vaddr, paddr, size, prot) \ - remap_pfn_range(vma, vaddr, (paddr) >> PAGE_SHIFT, size, prot) - #define io_remap_pfn_range(vma, vaddr, pfn, size, prot) \ remap_pfn_range(vma, vaddr, pfn, size, prot) diff --git a/include/asm-ia64/futex.h b/include/asm-ia64/futex.h index 2cac5ec..9feff4ce 100644 --- a/include/asm-ia64/futex.h +++ b/include/asm-ia64/futex.h @@ -14,7 +14,7 @@ futex_atomic_op_inuser (int encoded_op, int __user *uaddr) int cmp = (encoded_op >> 24) & 15; int oparg = (encoded_op << 8) >> 20; int cmparg = (encoded_op << 20) >> 20; - int oldval = 0, ret, tem; + int oldval = 0, ret; if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28)) oparg = 1 << oparg; diff --git a/include/asm-ia64/mca.h b/include/asm-ia64/mca.h index 97a28b8..c7d9c9e 100644 --- a/include/asm-ia64/mca.h +++ b/include/asm-ia64/mca.h @@ -80,7 +80,12 @@ struct ia64_sal_os_state { u64 sal_ra; /* Return address in SAL, physical */ u64 sal_gp; /* GP of the SAL - physical */ pal_min_state_area_t *pal_min_state; /* from R17. physical in asm, virtual in C */ + /* Previous values of IA64_KR(CURRENT) and IA64_KR(CURRENT_STACK). + * Note: if the MCA/INIT recovery code wants to resume to a new context + * then it must change these values to reflect the new kernel stack. + */ u64 prev_IA64_KR_CURRENT; /* previous value of IA64_KR(CURRENT) */ + u64 prev_IA64_KR_CURRENT_STACK; struct task_struct *prev_task; /* previous task, NULL if it is not useful */ /* Some interrupt registers are not saved in minstate, pt_regs or * switch_stack. Because MCA/INIT can occur when interrupts are diff --git a/include/asm-ia64/pgtable.h b/include/asm-ia64/pgtable.h index 2e34c06..3339c7b 100644 --- a/include/asm-ia64/pgtable.h +++ b/include/asm-ia64/pgtable.h @@ -443,10 +443,6 @@ extern void paging_init (void); #define pte_to_pgoff(pte) ((pte_val(pte) << 1) >> 3) #define pgoff_to_pte(off) ((pte_t) { ((off) << 2) | _PAGE_FILE }) -/* XXX is this right? */ -#define io_remap_page_range(vma, vaddr, paddr, size, prot) \ - remap_pfn_range(vma, vaddr, (paddr) >> PAGE_SHIFT, size, prot) - #define io_remap_pfn_range(vma, vaddr, pfn, size, prot) \ remap_pfn_range(vma, vaddr, pfn, size, prot) diff --git a/include/asm-ia64/ptrace.h b/include/asm-ia64/ptrace.h index fc54492..a79d1a7 100644 --- a/include/asm-ia64/ptrace.h +++ b/include/asm-ia64/ptrace.h @@ -57,7 +57,9 @@ #include <linux/config.h> #include <asm/fpu.h> +#ifndef ASM_OFFSETS_C #include <asm/asm-offsets.h> +#endif /* * Base-2 logarithm of number of pages to allocate per task structure diff --git a/include/asm-ia64/thread_info.h b/include/asm-ia64/thread_info.h index cf4a950..171b220 100644 --- a/include/asm-ia64/thread_info.h +++ b/include/asm-ia64/thread_info.h @@ -5,7 +5,9 @@ #ifndef _ASM_IA64_THREAD_INFO_H #define _ASM_IA64_THREAD_INFO_H +#ifndef ASM_OFFSETS_C #include <asm/asm-offsets.h> +#endif #include <asm/processor.h> #include <asm/ptrace.h> @@ -51,9 +53,14 @@ struct thread_info { }, \ } +#ifndef ASM_OFFSETS_C /* how to get the thread information struct from C */ #define current_thread_info() ((struct thread_info *) ((char *) current + IA64_TASK_SIZE)) #define alloc_thread_info(tsk) ((struct thread_info *) ((char *) (tsk) + IA64_TASK_SIZE)) +#else +#define current_thread_info() ((struct thread_info *) 0) +#define alloc_thread_info(tsk) ((struct thread_info *) 0) +#endif #define free_thread_info(ti) /* nothing */ #define __HAVE_ARCH_TASK_STRUCT_ALLOCATOR diff --git a/include/asm-m32r/futex.h b/include/asm-m32r/futex.h index 2cac5ec..9feff4ce 100644 --- a/include/asm-m32r/futex.h +++ b/include/asm-m32r/futex.h @@ -14,7 +14,7 @@ futex_atomic_op_inuser (int encoded_op, int __user *uaddr) int cmp = (encoded_op >> 24) & 15; int oparg = (encoded_op << 8) >> 20; int cmparg = (encoded_op << 20) >> 20; - int oldval = 0, ret, tem; + int oldval = 0, ret; if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28)) oparg = 1 << oparg; diff --git a/include/asm-m32r/pgtable.h b/include/asm-m32r/pgtable.h index da805e9..388e5ee 100644 --- a/include/asm-m32r/pgtable.h +++ b/include/asm-m32r/pgtable.h @@ -378,9 +378,6 @@ static inline void pmd_set(pmd_t * pmdp, pte_t * ptep) /* Needs to be defined here and not in linux/mm.h, as it is arch dependent */ #define kern_addr_valid(addr) (1) -#define io_remap_page_range(vma, vaddr, paddr, size, prot) \ - remap_pfn_range(vma, vaddr, (paddr) >> PAGE_SHIFT, size, prot) - #define io_remap_pfn_range(vma, vaddr, pfn, size, prot) \ remap_pfn_range(vma, vaddr, pfn, size, prot) diff --git a/include/asm-m68k/futex.h b/include/asm-m68k/futex.h index 2cac5ec..9feff4ce 100644 --- a/include/asm-m68k/futex.h +++ b/include/asm-m68k/futex.h @@ -14,7 +14,7 @@ futex_atomic_op_inuser (int encoded_op, int __user *uaddr) int cmp = (encoded_op >> 24) & 15; int oparg = (encoded_op << 8) >> 20; int cmparg = (encoded_op << 20) >> 20; - int oldval = 0, ret, tem; + int oldval = 0, ret; if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28)) oparg = 1 << oparg; diff --git a/include/asm-m68k/pgtable.h b/include/asm-m68k/pgtable.h index 0c87fc8..add129e 100644 --- a/include/asm-m68k/pgtable.h +++ b/include/asm-m68k/pgtable.h @@ -141,9 +141,6 @@ static inline void update_mmu_cache(struct vm_area_struct *vma, #define kern_addr_valid(addr) (1) -#define io_remap_page_range(vma, vaddr, paddr, size, prot) \ - remap_pfn_range(vma, vaddr, (paddr) >> PAGE_SHIFT, size, prot) - #define io_remap_pfn_range(vma, vaddr, pfn, size, prot) \ remap_pfn_range(vma, vaddr, pfn, size, prot) diff --git a/include/asm-m68knommu/futex.h b/include/asm-m68knommu/futex.h index 2cac5ec..9feff4ce 100644 --- a/include/asm-m68knommu/futex.h +++ b/include/asm-m68knommu/futex.h @@ -14,7 +14,7 @@ futex_atomic_op_inuser (int encoded_op, int __user *uaddr) int cmp = (encoded_op >> 24) & 15; int oparg = (encoded_op << 8) >> 20; int cmparg = (encoded_op << 20) >> 20; - int oldval = 0, ret, tem; + int oldval = 0, ret; if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28)) oparg = 1 << oparg; diff --git a/include/asm-m68knommu/pgtable.h b/include/asm-m68knommu/pgtable.h index e2a69ff..0089305 100644 --- a/include/asm-m68knommu/pgtable.h +++ b/include/asm-m68knommu/pgtable.h @@ -56,8 +56,6 @@ extern int is_in_rom(unsigned long); * No page table caches to initialise. */ #define pgtable_cache_init() do { } while (0) -#define io_remap_page_range(vma, vaddr, paddr, size, prot) \ - remap_pfn_range(vma, vaddr, (paddr) >> PAGE_SHIFT, size, prot) #define io_remap_pfn_range(vma, vaddr, pfn, size, prot) \ remap_pfn_range(vma, vaddr, pfn, size, prot) diff --git a/include/asm-mips/pgtable.h b/include/asm-mips/pgtable.h index dbe13da..cbd1672 100644 --- a/include/asm-mips/pgtable.h +++ b/include/asm-mips/pgtable.h @@ -358,16 +358,6 @@ static inline void update_mmu_cache(struct vm_area_struct *vma, extern phys_t fixup_bigphys_addr(phys_t phys_addr, phys_t size); extern int remap_pfn_range(struct vm_area_struct *vma, unsigned long from, unsigned long pfn, unsigned long size, pgprot_t prot); -static inline int io_remap_page_range(struct vm_area_struct *vma, - unsigned long vaddr, - unsigned long paddr, - unsigned long size, - pgprot_t prot) -{ - phys_t phys_addr_high = fixup_bigphys_addr(paddr, size); - return remap_pfn_range(vma, vaddr, phys_addr_high >> PAGE_SHIFT, size, prot); -} - static inline int io_remap_pfn_range(struct vm_area_struct *vma, unsigned long vaddr, unsigned long pfn, @@ -378,8 +368,6 @@ static inline int io_remap_pfn_range(struct vm_area_struct *vma, return remap_pfn_range(vma, vaddr, pfn, size, prot); } #else -#define io_remap_page_range(vma, vaddr, paddr, size, prot) \ - remap_pfn_range(vma, vaddr, (paddr) >> PAGE_SHIFT, size, prot) #define io_remap_pfn_range(vma, vaddr, pfn, size, prot) \ remap_pfn_range(vma, vaddr, pfn, size, prot) #endif diff --git a/include/asm-parisc/futex.h b/include/asm-parisc/futex.h index 2cac5ec..9feff4ce 100644 --- a/include/asm-parisc/futex.h +++ b/include/asm-parisc/futex.h @@ -14,7 +14,7 @@ futex_atomic_op_inuser (int encoded_op, int __user *uaddr) int cmp = (encoded_op >> 24) & 15; int oparg = (encoded_op << 8) >> 20; int cmparg = (encoded_op << 20) >> 20; - int oldval = 0, ret, tem; + int oldval = 0, ret; if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28)) oparg = 1 << oparg; diff --git a/include/asm-parisc/pgtable.h b/include/asm-parisc/pgtable.h index f001bb0..820c6e7 100644 --- a/include/asm-parisc/pgtable.h +++ b/include/asm-parisc/pgtable.h @@ -498,9 +498,6 @@ static inline void ptep_set_wrprotect(struct mm_struct *mm, unsigned long addr, #endif /* !__ASSEMBLY__ */ -#define io_remap_page_range(vma, vaddr, paddr, size, prot) \ - remap_pfn_range(vma, vaddr, (paddr) >> PAGE_SHIFT, size, prot) - #define io_remap_pfn_range(vma, vaddr, pfn, size, prot) \ remap_pfn_range(vma, vaddr, pfn, size, prot) diff --git a/include/asm-ppc/futex.h b/include/asm-ppc/futex.h index 2cac5ec..9feff4ce 100644 --- a/include/asm-ppc/futex.h +++ b/include/asm-ppc/futex.h @@ -14,7 +14,7 @@ futex_atomic_op_inuser (int encoded_op, int __user *uaddr) int cmp = (encoded_op >> 24) & 15; int oparg = (encoded_op << 8) >> 20; int cmparg = (encoded_op << 20) >> 20; - int oldval = 0, ret, tem; + int oldval = 0, ret; if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28)) oparg = 1 << oparg; diff --git a/include/asm-ppc/irq.h b/include/asm-ppc/irq.h index 5575247..bd96748 100644 --- a/include/asm-ppc/irq.h +++ b/include/asm-ppc/irq.h @@ -138,6 +138,16 @@ irq_canonicalize(int irq) #define SIU_IRQ7 (14) #define SIU_LEVEL7 (15) +#define MPC8xx_INT_FEC1 SIU_LEVEL1 +#define MPC8xx_INT_FEC2 SIU_LEVEL3 + +#define MPC8xx_INT_SCC1 (CPM_IRQ_OFFSET + CPMVEC_SCC1) +#define MPC8xx_INT_SCC2 (CPM_IRQ_OFFSET + CPMVEC_SCC2) +#define MPC8xx_INT_SCC3 (CPM_IRQ_OFFSET + CPMVEC_SCC3) +#define MPC8xx_INT_SCC4 (CPM_IRQ_OFFSET + CPMVEC_SCC4) +#define MPC8xx_INT_SMC1 (CPM_IRQ_OFFSET + CPMVEC_SMC1) +#define MPC8xx_INT_SMC2 (CPM_IRQ_OFFSET + CPMVEC_SMC2) + /* The internal interrupts we can configure as we see fit. * My personal preference is CPM at level 2, which puts it above the * MBX PCI/ISA/IDE interrupts. diff --git a/include/asm-ppc/macio.h b/include/asm-ppc/macio.h index a481b77..b553dd4 100644 --- a/include/asm-ppc/macio.h +++ b/include/asm-ppc/macio.h @@ -1,7 +1,6 @@ #ifndef __MACIO_ASIC_H__ #define __MACIO_ASIC_H__ -#include <linux/mod_devicetable.h> #include <asm/of_device.h> extern struct bus_type macio_bus_type; diff --git a/include/asm-ppc/mpc8xx.h b/include/asm-ppc/mpc8xx.h index dc8e598..208a2e1 100644 --- a/include/asm-ppc/mpc8xx.h +++ b/include/asm-ppc/mpc8xx.h @@ -97,6 +97,22 @@ extern unsigned char __res[]; struct pt_regs; +enum ppc_sys_devices { + MPC8xx_CPM_FEC1, + MPC8xx_CPM_FEC2, + MPC8xx_CPM_I2C, + MPC8xx_CPM_SCC1, + MPC8xx_CPM_SCC2, + MPC8xx_CPM_SCC3, + MPC8xx_CPM_SCC4, + MPC8xx_CPM_SPI, + MPC8xx_CPM_MCC1, + MPC8xx_CPM_MCC2, + MPC8xx_CPM_SMC1, + MPC8xx_CPM_SMC2, + MPC8xx_CPM_USB, +}; + #endif /* !__ASSEMBLY__ */ #endif /* CONFIG_8xx */ #endif /* __CONFIG_8xx_DEFS */ diff --git a/include/asm-ppc/mv64x60.h b/include/asm-ppc/mv64x60.h index 835930d..75c2ffa 100644 --- a/include/asm-ppc/mv64x60.h +++ b/include/asm-ppc/mv64x60.h @@ -119,6 +119,14 @@ extern spinlock_t mv64x60_lock; #define MV64x60_64BIT_WIN_COUNT 24 +/* Watchdog Platform Device, Driver Data */ +#define MV64x60_WDT_NAME "wdt" + +struct mv64x60_wdt_pdata { + int timeout; /* watchdog expiry in seconds, default 10 */ + int bus_clk; /* bus clock in MHz, default 133 */ +}; + /* * Define a structure that's used to pass in config information to the * core routines. diff --git a/include/asm-ppc/of_device.h b/include/asm-ppc/of_device.h index 4b264cf..575bce4 100644 --- a/include/asm-ppc/of_device.h +++ b/include/asm-ppc/of_device.h @@ -2,6 +2,7 @@ #define __OF_DEVICE_H__ #include <linux/device.h> +#include <linux/mod_devicetable.h> #include <asm/prom.h> /* @@ -55,7 +56,9 @@ extern int of_register_driver(struct of_platform_driver *drv); extern void of_unregister_driver(struct of_platform_driver *drv); extern int of_device_register(struct of_device *ofdev); extern void of_device_unregister(struct of_device *ofdev); -extern struct of_device *of_platform_device_create(struct device_node *np, const char *bus_id); +extern struct of_device *of_platform_device_create(struct device_node *np, + const char *bus_id, + struct device *parent); extern void of_release_dev(struct device *dev); #endif /* __OF_DEVICE_H__ */ diff --git a/include/asm-ppc/pgtable.h b/include/asm-ppc/pgtable.h index 92f30b2..eee601b 100644 --- a/include/asm-ppc/pgtable.h +++ b/include/asm-ppc/pgtable.h @@ -812,15 +812,6 @@ extern void kernel_set_cachemode (unsigned long address, unsigned long size, #ifdef CONFIG_PHYS_64BIT extern int remap_pfn_range(struct vm_area_struct *vma, unsigned long from, unsigned long paddr, unsigned long size, pgprot_t prot); -static inline int io_remap_page_range(struct vm_area_struct *vma, - unsigned long vaddr, - unsigned long paddr, - unsigned long size, - pgprot_t prot) -{ - phys_addr_t paddr64 = fixup_bigphys_addr(paddr, size); - return remap_pfn_range(vma, vaddr, paddr64 >> PAGE_SHIFT, size, prot); -} static inline int io_remap_pfn_range(struct vm_area_struct *vma, unsigned long vaddr, @@ -832,8 +823,6 @@ static inline int io_remap_pfn_range(struct vm_area_struct *vma, return remap_pfn_range(vma, vaddr, paddr64 >> PAGE_SHIFT, size, prot); } #else -#define io_remap_page_range(vma, vaddr, paddr, size, prot) \ - remap_pfn_range(vma, vaddr, (paddr) >> PAGE_SHIFT, size, prot) #define io_remap_pfn_range(vma, vaddr, pfn, size, prot) \ remap_pfn_range(vma, vaddr, pfn, size, prot) #endif diff --git a/include/asm-ppc/ppc_sys.h b/include/asm-ppc/ppc_sys.h index 048f7c8..549f4484 100644 --- a/include/asm-ppc/ppc_sys.h +++ b/include/asm-ppc/ppc_sys.h @@ -27,6 +27,8 @@ #include <asm/mpc83xx.h> #elif defined(CONFIG_85xx) #include <asm/mpc85xx.h> +#elif defined(CONFIG_8xx) +#include <asm/mpc8xx.h> #elif defined(CONFIG_PPC_MPC52xx) #include <asm/mpc52xx.h> #elif defined(CONFIG_MPC10X_BRIDGE) diff --git a/include/asm-ppc/segment.h b/include/asm-ppc/segment.h deleted file mode 100644 index 0f2f742..0000000 --- a/include/asm-ppc/segment.h +++ /dev/null @@ -1 +0,0 @@ -#include <asm/uaccess.h> diff --git a/include/asm-ppc/tlbflush.h b/include/asm-ppc/tlbflush.h index 9850f53..9afee4f 100644 --- a/include/asm-ppc/tlbflush.h +++ b/include/asm-ppc/tlbflush.h @@ -72,7 +72,7 @@ static inline void flush_tlb_page(struct vm_area_struct *vma, static inline void flush_tlb_page_nohash(struct vm_area_struct *vma, unsigned long vmaddr) { _tlbie(vmaddr); } -static inline void flush_tlb_range(struct mm_struct *mm, +static inline void flush_tlb_range(struct vm_area_struct *vma, unsigned long start, unsigned long end) { __tlbia(); } static inline void flush_tlb_kernel_range(unsigned long start, diff --git a/include/asm-ppc64/smu.h b/include/asm-ppc64/smu.h index 10b4397..dee8eef 100644 --- a/include/asm-ppc64/smu.h +++ b/include/asm-ppc64/smu.h @@ -1,22 +1,379 @@ +#ifndef _SMU_H +#define _SMU_H + /* * Definitions for talking to the SMU chip in newer G5 PowerMacs */ #include <linux/config.h> +#include <linux/list.h> + +/* + * Known SMU commands + * + * Most of what is below comes from looking at the Open Firmware driver, + * though this is still incomplete and could use better documentation here + * or there... + */ + + +/* + * Partition info commands + * + * I do not know what those are for at this point + */ +#define SMU_CMD_PARTITION_COMMAND 0x3e + + +/* + * Fan control + * + * This is a "mux" for fan control commands, first byte is the + * "sub" command. + */ +#define SMU_CMD_FAN_COMMAND 0x4a + + +/* + * Battery access + * + * Same command number as the PMU, could it be same syntax ? + */ +#define SMU_CMD_BATTERY_COMMAND 0x6f +#define SMU_CMD_GET_BATTERY_INFO 0x00 + +/* + * Real time clock control + * + * This is a "mux", first data byte contains the "sub" command. + * The "RTC" part of the SMU controls the date, time, powerup + * timer, but also a PRAM + * + * Dates are in BCD format on 7 bytes: + * [sec] [min] [hour] [weekday] [month day] [month] [year] + * with month being 1 based and year minus 100 + */ +#define SMU_CMD_RTC_COMMAND 0x8e +#define SMU_CMD_RTC_SET_PWRUP_TIMER 0x00 /* i: 7 bytes date */ +#define SMU_CMD_RTC_GET_PWRUP_TIMER 0x01 /* o: 7 bytes date */ +#define SMU_CMD_RTC_STOP_PWRUP_TIMER 0x02 +#define SMU_CMD_RTC_SET_PRAM_BYTE_ACC 0x20 /* i: 1 byte (address?) */ +#define SMU_CMD_RTC_SET_PRAM_AUTOINC 0x21 /* i: 1 byte (data?) */ +#define SMU_CMD_RTC_SET_PRAM_LO_BYTES 0x22 /* i: 10 bytes */ +#define SMU_CMD_RTC_SET_PRAM_HI_BYTES 0x23 /* i: 10 bytes */ +#define SMU_CMD_RTC_GET_PRAM_BYTE 0x28 /* i: 1 bytes (address?) */ +#define SMU_CMD_RTC_GET_PRAM_LO_BYTES 0x29 /* o: 10 bytes */ +#define SMU_CMD_RTC_GET_PRAM_HI_BYTES 0x2a /* o: 10 bytes */ +#define SMU_CMD_RTC_SET_DATETIME 0x80 /* i: 7 bytes date */ +#define SMU_CMD_RTC_GET_DATETIME 0x81 /* o: 7 bytes date */ + + /* + * i2c commands + * + * To issue an i2c command, first is to send a parameter block to the + * the SMU. This is a command of type 0x9a with 9 bytes of header + * eventually followed by data for a write: + * + * 0: bus number (from device-tree usually, SMU has lots of busses !) + * 1: transfer type/format (see below) + * 2: device address. For combined and combined4 type transfers, this + * is the "write" version of the address (bit 0x01 cleared) + * 3: subaddress length (0..3) + * 4: subaddress byte 0 (or only byte for subaddress length 1) + * 5: subaddress byte 1 + * 6: subaddress byte 2 + * 7: combined address (device address for combined mode data phase) + * 8: data length + * + * The transfer types are the same good old Apple ones it seems, + * that is: + * - 0x00: Simple transfer + * - 0x01: Subaddress transfer (addr write + data tx, no restart) + * - 0x02: Combined transfer (addr write + restart + data tx) + * + * This is then followed by actual data for a write. + * + * At this point, the OF driver seems to have a limitation on transfer + * sizes of 0xd bytes on reads and 0x5 bytes on writes. I do not know + * wether this is just an OF limit due to some temporary buffer size + * or if this is an SMU imposed limit. This driver has the same limitation + * for now as I use a 0x10 bytes temporary buffer as well + * + * Once that is completed, a response is expected from the SMU. This is + * obtained via a command of type 0x9a with a length of 1 byte containing + * 0 as the data byte. OF also fills the rest of the data buffer with 0xff's + * though I can't tell yet if this is actually necessary. Once this command + * is complete, at this point, all I can tell is what OF does. OF tests + * byte 0 of the reply: + * - on read, 0xfe or 0xfc : bus is busy, wait (see below) or nak ? + * - on read, 0x00 or 0x01 : reply is in buffer (after the byte 0) + * - on write, < 0 -> failure (immediate exit) + * - else, OF just exists (without error, weird) + * + * So on read, there is this wait-for-busy thing when getting a 0xfc or + * 0xfe result. OF does a loop of up to 64 retries, waiting 20ms and + * doing the above again until either the retries expire or the result + * is no longer 0xfe or 0xfc + * + * The Darwin I2C driver is less subtle though. On any non-success status + * from the response command, it waits 5ms and tries again up to 20 times, + * it doesn't differenciate between fatal errors or "busy" status. + * + * This driver provides an asynchronous paramblock based i2c command + * interface to be used either directly by low level code or by a higher + * level driver interfacing to the linux i2c layer. The current + * implementation of this relies on working timers & timer interrupts + * though, so be careful of calling context for now. This may be "fixed" + * in the future by adding a polling facility. + */ +#define SMU_CMD_I2C_COMMAND 0x9a + /* transfer types */ +#define SMU_I2C_TRANSFER_SIMPLE 0x00 +#define SMU_I2C_TRANSFER_STDSUB 0x01 +#define SMU_I2C_TRANSFER_COMBINED 0x02 + +/* + * Power supply control + * + * The "sub" command is an ASCII string in the data, the + * data lenght is that of the string. + * + * The VSLEW command can be used to get or set the voltage slewing. + * - lenght 5 (only "VSLEW") : it returns "DONE" and 3 bytes of + * reply at data offset 6, 7 and 8. + * - lenght 8 ("VSLEWxyz") has 3 additional bytes appended, and is + * used to set the voltage slewing point. The SMU replies with "DONE" + * I yet have to figure out their exact meaning of those 3 bytes in + * both cases. + * + */ +#define SMU_CMD_POWER_COMMAND 0xaa +#define SMU_CMD_POWER_RESTART "RESTART" +#define SMU_CMD_POWER_SHUTDOWN "SHUTDOWN" +#define SMU_CMD_POWER_VOLTAGE_SLEW "VSLEW" + +/* Misc commands + * + * This command seem to be a grab bag of various things + */ +#define SMU_CMD_MISC_df_COMMAND 0xdf +#define SMU_CMD_MISC_df_SET_DISPLAY_LIT 0x02 /* i: 1 byte */ +#define SMU_CMD_MISC_df_NMI_OPTION 0x04 + +/* + * Version info commands + * + * I haven't quite tried to figure out how these work + */ +#define SMU_CMD_VERSION_COMMAND 0xea + + +/* + * Misc commands + * + * This command seem to be a grab bag of various things + */ +#define SMU_CMD_MISC_ee_COMMAND 0xee +#define SMU_CMD_MISC_ee_GET_DATABLOCK_REC 0x02 +#define SMU_CMD_MISC_ee_LEDS_CTRL 0x04 /* i: 00 (00,01) [00] */ +#define SMU_CMD_MISC_ee_GET_DATA 0x05 /* i: 00 , o: ?? */ + + + +/* + * - Kernel side interface - + */ + +#ifdef __KERNEL__ + +/* + * Asynchronous SMU commands + * + * Fill up this structure and submit it via smu_queue_command(), + * and get notified by the optional done() callback, or because + * status becomes != 1 + */ + +struct smu_cmd; + +struct smu_cmd +{ + /* public */ + u8 cmd; /* command */ + int data_len; /* data len */ + int reply_len; /* reply len */ + void *data_buf; /* data buffer */ + void *reply_buf; /* reply buffer */ + int status; /* command status */ + void (*done)(struct smu_cmd *cmd, void *misc); + void *misc; + + /* private */ + struct list_head link; +}; + +/* + * Queues an SMU command, all fields have to be initialized + */ +extern int smu_queue_cmd(struct smu_cmd *cmd); + +/* + * Simple command wrapper. This structure embeds a small buffer + * to ease sending simple SMU commands from the stack + */ +struct smu_simple_cmd +{ + struct smu_cmd cmd; + u8 buffer[16]; +}; + +/* + * Queues a simple command. All fields will be initialized by that + * function + */ +extern int smu_queue_simple(struct smu_simple_cmd *scmd, u8 command, + unsigned int data_len, + void (*done)(struct smu_cmd *cmd, void *misc), + void *misc, + ...); + +/* + * Completion helper. Pass it to smu_queue_simple or as 'done' + * member to smu_queue_cmd, it will call complete() on the struct + * completion passed in the "misc" argument + */ +extern void smu_done_complete(struct smu_cmd *cmd, void *misc); /* - * Basic routines for use by architecture. To be extended as - * we understand more of the chip + * Synchronous helpers. Will spin-wait for completion of a command + */ +extern void smu_spinwait_cmd(struct smu_cmd *cmd); + +static inline void smu_spinwait_simple(struct smu_simple_cmd *scmd) +{ + smu_spinwait_cmd(&scmd->cmd); +} + +/* + * Poll routine to call if blocked with irqs off + */ +extern void smu_poll(void); + + +/* + * Init routine, presence check.... */ extern int smu_init(void); extern int smu_present(void); +struct of_device; +extern struct of_device *smu_get_ofdev(void); + + +/* + * Common command wrappers + */ extern void smu_shutdown(void); extern void smu_restart(void); -extern int smu_get_rtc_time(struct rtc_time *time); -extern int smu_set_rtc_time(struct rtc_time *time); +struct rtc_time; +extern int smu_get_rtc_time(struct rtc_time *time, int spinwait); +extern int smu_set_rtc_time(struct rtc_time *time, int spinwait); /* * SMU command buffer absolute address, exported by pmac_setup, * this is allocated very early during boot. */ extern unsigned long smu_cmdbuf_abs; + + +/* + * Kenrel asynchronous i2c interface + */ + +/* SMU i2c header, exactly matches i2c header on wire */ +struct smu_i2c_param +{ + u8 bus; /* SMU bus ID (from device tree) */ + u8 type; /* i2c transfer type */ + u8 devaddr; /* device address (includes direction) */ + u8 sublen; /* subaddress length */ + u8 subaddr[3]; /* subaddress */ + u8 caddr; /* combined address, filled by SMU driver */ + u8 datalen; /* length of transfer */ + u8 data[7]; /* data */ +}; + +#define SMU_I2C_READ_MAX 0x0d +#define SMU_I2C_WRITE_MAX 0x05 + +struct smu_i2c_cmd +{ + /* public */ + struct smu_i2c_param info; + void (*done)(struct smu_i2c_cmd *cmd, void *misc); + void *misc; + int status; /* 1 = pending, 0 = ok, <0 = fail */ + + /* private */ + struct smu_cmd scmd; + int read; + int stage; + int retries; + u8 pdata[0x10]; + struct list_head link; +}; + +/* + * Call this to queue an i2c command to the SMU. You must fill info, + * including info.data for a write, done and misc. + * For now, no polling interface is provided so you have to use completion + * callback. + */ +extern int smu_queue_i2c(struct smu_i2c_cmd *cmd); + + +#endif /* __KERNEL__ */ + +/* + * - Userland interface - + */ + +/* + * A given instance of the device can be configured for 2 different + * things at the moment: + * + * - sending SMU commands (default at open() time) + * - receiving SMU events (not yet implemented) + * + * Commands are written with write() of a command block. They can be + * "driver" commands (for example to switch to event reception mode) + * or real SMU commands. They are made of a header followed by command + * data if any. + * + * For SMU commands (not for driver commands), you can then read() back + * a reply. The reader will be blocked or not depending on how the device + * file is opened. poll() isn't implemented yet. The reply will consist + * of a header as well, followed by the reply data if any. You should + * always provide a buffer large enough for the maximum reply data, I + * recommand one page. + * + * It is illegal to send SMU commands through a file descriptor configured + * for events reception + * + */ +struct smu_user_cmd_hdr +{ + __u32 cmdtype; +#define SMU_CMDTYPE_SMU 0 /* SMU command */ +#define SMU_CMDTYPE_WANTS_EVENTS 1 /* switch fd to events mode */ + + __u8 cmd; /* SMU command byte */ + __u32 data_len; /* Lenght of data following */ +}; + +struct smu_user_reply_hdr +{ + __u32 status; /* Command status */ + __u32 reply_len; /* Lenght of data follwing */ +}; + +#endif /* _SMU_H */ diff --git a/include/asm-s390/futex.h b/include/asm-s390/futex.h index 2cac5ec..9feff4ce 100644 --- a/include/asm-s390/futex.h +++ b/include/asm-s390/futex.h @@ -14,7 +14,7 @@ futex_atomic_op_inuser (int encoded_op, int __user *uaddr) int cmp = (encoded_op >> 24) & 15; int oparg = (encoded_op << 8) >> 20; int cmparg = (encoded_op << 20) >> 20; - int oldval = 0, ret, tem; + int oldval = 0, ret; if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28)) oparg = 1 << oparg; diff --git a/include/asm-sh/futex.h b/include/asm-sh/futex.h index 2cac5ec..9feff4ce 100644 --- a/include/asm-sh/futex.h +++ b/include/asm-sh/futex.h @@ -14,7 +14,7 @@ futex_atomic_op_inuser (int encoded_op, int __user *uaddr) int cmp = (encoded_op >> 24) & 15; int oparg = (encoded_op << 8) >> 20; int cmparg = (encoded_op << 20) >> 20; - int oldval = 0, ret, tem; + int oldval = 0, ret; if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28)) oparg = 1 << oparg; diff --git a/include/asm-sh/pgtable.h b/include/asm-sh/pgtable.h index ecb9095..0f4bcaa 100644 --- a/include/asm-sh/pgtable.h +++ b/include/asm-sh/pgtable.h @@ -277,9 +277,6 @@ typedef pte_t *pte_addr_t; #define kern_addr_valid(addr) (1) -#define io_remap_page_range(vma, vaddr, paddr, size, prot) \ - remap_pfn_range(vma, vaddr, (paddr) >> PAGE_SHIFT, size, prot) - #define io_remap_pfn_range(vma, vaddr, pfn, size, prot) \ remap_pfn_range(vma, vaddr, pfn, size, prot) diff --git a/include/asm-sh64/futex.h b/include/asm-sh64/futex.h index 2cac5ec..9feff4ce 100644 --- a/include/asm-sh64/futex.h +++ b/include/asm-sh64/futex.h @@ -14,7 +14,7 @@ futex_atomic_op_inuser (int encoded_op, int __user *uaddr) int cmp = (encoded_op >> 24) & 15; int oparg = (encoded_op << 8) >> 20; int cmparg = (encoded_op << 20) >> 20; - int oldval = 0, ret, tem; + int oldval = 0, ret; if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28)) oparg = 1 << oparg; diff --git a/include/asm-sh64/pgtable.h b/include/asm-sh64/pgtable.h index 78ac6be..51db430 100644 --- a/include/asm-sh64/pgtable.h +++ b/include/asm-sh64/pgtable.h @@ -482,9 +482,6 @@ extern void update_mmu_cache(struct vm_area_struct * vma, #define PageSkip(page) (0) #define kern_addr_valid(addr) (1) -#define io_remap_page_range(vma, vaddr, paddr, size, prot) \ - remap_pfn_range(vma, vaddr, (paddr) >> PAGE_SHIFT, size, prot) - #define io_remap_pfn_range(vma, vaddr, pfn, size, prot) \ remap_pfn_range(vma, vaddr, pfn, size, prot) diff --git a/include/asm-sparc/futex.h b/include/asm-sparc/futex.h index 2cac5ec..9feff4ce 100644 --- a/include/asm-sparc/futex.h +++ b/include/asm-sparc/futex.h @@ -14,7 +14,7 @@ futex_atomic_op_inuser (int encoded_op, int __user *uaddr) int cmp = (encoded_op >> 24) & 15; int oparg = (encoded_op << 8) >> 20; int cmparg = (encoded_op << 20) >> 20; - int oldval = 0, ret, tem; + int oldval = 0, ret; if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28)) oparg = 1 << oparg; diff --git a/include/asm-sparc64/cacheflush.h b/include/asm-sparc64/cacheflush.h index 51b26e81..ededd26 100644 --- a/include/asm-sparc64/cacheflush.h +++ b/include/asm-sparc64/cacheflush.h @@ -4,13 +4,6 @@ #include <linux/config.h> #include <asm/page.h> -/* Flushing for D-cache alias handling is only needed if - * the page size is smaller than 16K. - */ -#if PAGE_SHIFT < 14 -#define DCACHE_ALIASING_POSSIBLE -#endif - #ifndef __ASSEMBLY__ #include <linux/mm.h> diff --git a/include/asm-sparc64/futex.h b/include/asm-sparc64/futex.h index 2cac5ec..9feff4ce 100644 --- a/include/asm-sparc64/futex.h +++ b/include/asm-sparc64/futex.h @@ -14,7 +14,7 @@ futex_atomic_op_inuser (int encoded_op, int __user *uaddr) int cmp = (encoded_op >> 24) & 15; int oparg = (encoded_op << 8) >> 20; int cmparg = (encoded_op << 20) >> 20; - int oldval = 0, ret, tem; + int oldval = 0, ret; if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28)) oparg = 1 << oparg; diff --git a/include/asm-sparc64/ide.h b/include/asm-sparc64/ide.h index 4c10984..c393f81 100644 --- a/include/asm-sparc64/ide.h +++ b/include/asm-sparc64/ide.h @@ -15,6 +15,7 @@ #include <asm/io.h> #include <asm/spitfire.h> #include <asm/cacheflush.h> +#include <asm/page.h> #ifndef MAX_HWIFS # ifdef CONFIG_BLK_DEV_IDEPCI diff --git a/include/asm-sparc64/page.h b/include/asm-sparc64/page.h index c9f8ef2..7f8d764 100644 --- a/include/asm-sparc64/page.h +++ b/include/asm-sparc64/page.h @@ -21,6 +21,13 @@ #define PAGE_SIZE (_AC(1,UL) << PAGE_SHIFT) #define PAGE_MASK (~(PAGE_SIZE-1)) +/* Flushing for D-cache alias handling is only needed if + * the page size is smaller than 16K. + */ +#if PAGE_SHIFT < 14 +#define DCACHE_ALIASING_POSSIBLE +#endif + #ifdef __KERNEL__ #ifndef __ASSEMBLY__ diff --git a/include/asm-sparc64/pgalloc.h b/include/asm-sparc64/pgalloc.h index b9b1914..a96067c 100644 --- a/include/asm-sparc64/pgalloc.h +++ b/include/asm-sparc64/pgalloc.h @@ -10,6 +10,7 @@ #include <asm/spitfire.h> #include <asm/cpudata.h> #include <asm/cacheflush.h> +#include <asm/page.h> /* Page table allocation/freeing. */ #ifdef CONFIG_SMP diff --git a/include/asm-sparc64/pgtable.h b/include/asm-sparc64/pgtable.h index a2b4f5e..a297f61 100644 --- a/include/asm-sparc64/pgtable.h +++ b/include/asm-sparc64/pgtable.h @@ -24,21 +24,23 @@ #include <asm/processor.h> #include <asm/const.h> -/* The kernel image occupies 0x4000000 to 0x1000000 (4MB --> 16MB). - * The page copy blockops use 0x1000000 to 0x18000000 (16MB --> 24MB). +/* The kernel image occupies 0x4000000 to 0x1000000 (4MB --> 32MB). + * The page copy blockops can use 0x2000000 to 0x10000000. * The PROM resides in an area spanning 0xf0000000 to 0x100000000. - * The vmalloc area spans 0x140000000 to 0x200000000. + * The vmalloc area spans 0x100000000 to 0x200000000. + * Since modules need to be in the lowest 32-bits of the address space, + * we place them right before the OBP area from 0x10000000 to 0xf0000000. * There is a single static kernel PMD which maps from 0x0 to address * 0x400000000. */ -#define TLBTEMP_BASE _AC(0x0000000001000000,UL) -#define MODULES_VADDR _AC(0x0000000002000000,UL) -#define MODULES_LEN _AC(0x000000007e000000,UL) -#define MODULES_END _AC(0x0000000080000000,UL) -#define VMALLOC_START _AC(0x0000000140000000,UL) -#define VMALLOC_END _AC(0x0000000200000000,UL) +#define TLBTEMP_BASE _AC(0x0000000002000000,UL) +#define MODULES_VADDR _AC(0x0000000010000000,UL) +#define MODULES_LEN _AC(0x00000000e0000000,UL) +#define MODULES_END _AC(0x00000000f0000000,UL) #define LOW_OBP_ADDRESS _AC(0x00000000f0000000,UL) #define HI_OBP_ADDRESS _AC(0x0000000100000000,UL) +#define VMALLOC_START _AC(0x0000000100000000,UL) +#define VMALLOC_END _AC(0x0000000200000000,UL) /* XXX All of this needs to be rethought so we can take advantage * XXX cheetah's full 64-bit virtual address space, ie. no more hole diff --git a/include/asm-um/futex.h b/include/asm-um/futex.h index 2cac5ec..142ee2d 100644 --- a/include/asm-um/futex.h +++ b/include/asm-um/futex.h @@ -1,53 +1,12 @@ -#ifndef _ASM_FUTEX_H -#define _ASM_FUTEX_H - -#ifdef __KERNEL__ +#ifndef __UM_FUTEX_H +#define __UM_FUTEX_H #include <linux/futex.h> #include <asm/errno.h> +#include <asm/system.h> +#include <asm/processor.h> #include <asm/uaccess.h> -static inline int -futex_atomic_op_inuser (int encoded_op, int __user *uaddr) -{ - int op = (encoded_op >> 28) & 7; - int cmp = (encoded_op >> 24) & 15; - int oparg = (encoded_op << 8) >> 20; - int cmparg = (encoded_op << 20) >> 20; - int oldval = 0, ret, tem; - if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28)) - oparg = 1 << oparg; - - if (! access_ok (VERIFY_WRITE, uaddr, sizeof(int))) - return -EFAULT; - - inc_preempt_count(); - - switch (op) { - case FUTEX_OP_SET: - case FUTEX_OP_ADD: - case FUTEX_OP_OR: - case FUTEX_OP_ANDN: - case FUTEX_OP_XOR: - default: - ret = -ENOSYS; - } +#include "asm/arch/futex.h" - dec_preempt_count(); - - if (!ret) { - switch (cmp) { - case FUTEX_OP_CMP_EQ: ret = (oldval == cmparg); break; - case FUTEX_OP_CMP_NE: ret = (oldval != cmparg); break; - case FUTEX_OP_CMP_LT: ret = (oldval < cmparg); break; - case FUTEX_OP_CMP_GE: ret = (oldval >= cmparg); break; - case FUTEX_OP_CMP_LE: ret = (oldval <= cmparg); break; - case FUTEX_OP_CMP_GT: ret = (oldval > cmparg); break; - default: ret = -ENOSYS; - } - } - return ret; -} - -#endif #endif diff --git a/include/asm-um/pgtable.h b/include/asm-um/pgtable.h index ed06170..616d02b 100644 --- a/include/asm-um/pgtable.h +++ b/include/asm-um/pgtable.h @@ -346,7 +346,6 @@ static inline void set_pte(pte_t *pteptr, pte_t pteval) static inline pte_t pte_modify(pte_t pte, pgprot_t newprot) { pte_set_val(pte, (pte_val(pte) & _PAGE_CHG_MASK), newprot); - if(pte_present(pte)) pte = pte_mknewpage(pte_mknewprot(pte)); return pte; } diff --git a/include/asm-um/processor-generic.h b/include/asm-um/processor-generic.h index b2fc94f..2d24236 100644 --- a/include/asm-um/processor-generic.h +++ b/include/asm-um/processor-generic.h @@ -21,6 +21,7 @@ struct thread_struct { * copy_thread) to mark that we are begin called from userspace (fork / * vfork / clone), and reset to 0 after. It is left to 0 when called * from kernelspace (i.e. kernel_thread() or fork_idle(), as of 2.6.11). */ + struct task_struct *saved_task; int forking; int nsyscalls; struct pt_regs regs; diff --git a/include/asm-um/system-i386.h b/include/asm-um/system-i386.h index ea8381d..c436263 100644 --- a/include/asm-um/system-i386.h +++ b/include/asm-um/system-i386.h @@ -3,6 +3,4 @@ #include "asm/system-generic.h" -#define __HAVE_ARCH_CMPXCHG 1 - #endif diff --git a/include/asm-v850/futex.h b/include/asm-v850/futex.h index 2cac5ec..9feff4ce 100644 --- a/include/asm-v850/futex.h +++ b/include/asm-v850/futex.h @@ -14,7 +14,7 @@ futex_atomic_op_inuser (int encoded_op, int __user *uaddr) int cmp = (encoded_op >> 24) & 15; int oparg = (encoded_op << 8) >> 20; int cmparg = (encoded_op << 20) >> 20; - int oldval = 0, ret, tem; + int oldval = 0, ret; if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28)) oparg = 1 << oparg; diff --git a/include/asm-x86_64/desc.h b/include/asm-x86_64/desc.h index 594e610..68ac3c6 100644 --- a/include/asm-x86_64/desc.h +++ b/include/asm-x86_64/desc.h @@ -8,6 +8,8 @@ #ifndef __ASSEMBLY__ #include <linux/string.h> +#include <linux/smp.h> + #include <asm/segment.h> #include <asm/mmu.h> diff --git a/include/asm-x86_64/pgtable.h b/include/asm-x86_64/pgtable.h index 1dc110b..2cb4835 100644 --- a/include/asm-x86_64/pgtable.h +++ b/include/asm-x86_64/pgtable.h @@ -421,9 +421,6 @@ static inline pte_t pte_modify(pte_t pte, pgprot_t newprot) extern int kern_addr_valid(unsigned long addr); -#define io_remap_page_range(vma, vaddr, paddr, size, prot) \ - remap_pfn_range(vma, vaddr, (paddr) >> PAGE_SHIFT, size, prot) - #define io_remap_pfn_range(vma, vaddr, pfn, size, prot) \ remap_pfn_range(vma, vaddr, pfn, size, prot) diff --git a/include/asm-xtensa/atomic.h b/include/asm-xtensa/atomic.h index 24f86f0..12b5732 100644 --- a/include/asm-xtensa/atomic.h +++ b/include/asm-xtensa/atomic.h @@ -22,7 +22,7 @@ typedef struct { volatile int counter; } atomic_t; #include <asm/processor.h> #include <asm/system.h> -#define ATOMIC_INIT(i) ( (atomic_t) { (i) } ) +#define ATOMIC_INIT(i) { (i) } /* * This Xtensa implementation assumes that the right mechanism diff --git a/include/asm-xtensa/bitops.h b/include/asm-xtensa/bitops.h index d395ef2..e76ee88 100644 --- a/include/asm-xtensa/bitops.h +++ b/include/asm-xtensa/bitops.h @@ -174,7 +174,7 @@ static __inline__ int test_bit(int nr, const volatile void *addr) return 1UL & (((const volatile unsigned int *)addr)[nr>>5] >> (nr&31)); } -#if XCHAL_HAVE_NSAU +#if XCHAL_HAVE_NSA static __inline__ int __cntlz (unsigned long x) { diff --git a/include/asm-xtensa/hardirq.h b/include/asm-xtensa/hardirq.h index e07c76c..aa9c1ad 100644 --- a/include/asm-xtensa/hardirq.h +++ b/include/asm-xtensa/hardirq.h @@ -23,6 +23,7 @@ typedef struct { unsigned int __nmi_count; /* arch dependent */ } ____cacheline_aligned irq_cpustat_t; +void ack_bad_irq(unsigned int irq); #include <linux/irq_cpustat.h> /* Standard mappings for irq_cpustat_t above */ #endif /* _XTENSA_HARDIRQ_H */ diff --git a/include/asm-xtensa/pgtable.h b/include/asm-xtensa/pgtable.h index 883ebc2..987e3b8 100644 --- a/include/asm-xtensa/pgtable.h +++ b/include/asm-xtensa/pgtable.h @@ -441,11 +441,11 @@ extern void update_mmu_cache(struct vm_area_struct * vma, unsigned long address, pte_t pte); /* - * remap a physical address `phys' of size `size' with page protection `prot' + * remap a physical page `pfn' of size `size' with page protection `prot' * into virtual address `from' */ -#define io_remap_page_range(vma,from,phys,size,prot) \ - remap_pfn_range(vma, from, (phys) >> PAGE_SHIFT, size, prot) +#define io_remap_pfn_range(vma,from,pfn,size,prot) \ + remap_pfn_range(vma, from, pfn, size, prot) /* No page table caches to init */ diff --git a/include/asm-xtensa/semaphore.h b/include/asm-xtensa/semaphore.h index db740b8..09e89ab 100644 --- a/include/asm-xtensa/semaphore.h +++ b/include/asm-xtensa/semaphore.h @@ -20,28 +20,19 @@ struct semaphore { atomic_t count; int sleepers; wait_queue_head_t wait; -#if WAITQUEUE_DEBUG - long __magic; -#endif }; -#if WAITQUEUE_DEBUG -# define __SEM_DEBUG_INIT(name) \ - , (int)&(name).__magic -#else -# define __SEM_DEBUG_INIT(name) -#endif - -#define __SEMAPHORE_INITIALIZER(name,count) \ - { ATOMIC_INIT(count), \ - 0, \ - __WAIT_QUEUE_HEAD_INITIALIZER((name).wait) \ - __SEM_DEBUG_INIT(name) } +#define __SEMAPHORE_INITIALIZER(name,n) \ +{ \ + .count = ATOMIC_INIT(n), \ + .sleepers = 0, \ + .wait = __WAIT_QUEUE_HEAD_INITIALIZER((name).wait) \ +} -#define __MUTEX_INITIALIZER(name) \ +#define __MUTEX_INITIALIZER(name) \ __SEMAPHORE_INITIALIZER(name, 1) -#define __DECLARE_SEMAPHORE_GENERIC(name,count) \ +#define __DECLARE_SEMAPHORE_GENERIC(name,count) \ struct semaphore name = __SEMAPHORE_INITIALIZER(name,count) #define DECLARE_MUTEX(name) __DECLARE_SEMAPHORE_GENERIC(name,1) @@ -49,17 +40,8 @@ struct semaphore { static inline void sema_init (struct semaphore *sem, int val) { -/* - * *sem = (struct semaphore)__SEMAPHORE_INITIALIZER((*sem),val); - * - * i'd rather use the more flexible initialization above, but sadly - * GCC 2.7.2.3 emits a bogus warning. EGCS doesnt. Oh well. - */ atomic_set(&sem->count, val); init_waitqueue_head(&sem->wait); -#if WAITQUEUE_DEBUG - sem->__magic = (int)&sem->__magic; -#endif } static inline void init_MUTEX (struct semaphore *sem) @@ -81,9 +63,7 @@ extern spinlock_t semaphore_wake_lock; static inline void down(struct semaphore * sem) { -#if WAITQUEUE_DEBUG - CHECK_MAGIC(sem->__magic); -#endif + might_sleep(); if (atomic_sub_return(1, &sem->count) < 0) __down(sem); @@ -92,9 +72,8 @@ static inline void down(struct semaphore * sem) static inline int down_interruptible(struct semaphore * sem) { int ret = 0; -#if WAITQUEUE_DEBUG - CHECK_MAGIC(sem->__magic); -#endif + + might_sleep(); if (atomic_sub_return(1, &sem->count) < 0) ret = __down_interruptible(sem); @@ -104,9 +83,6 @@ static inline int down_interruptible(struct semaphore * sem) static inline int down_trylock(struct semaphore * sem) { int ret = 0; -#if WAITQUEUE_DEBUG - CHECK_MAGIC(sem->__magic); -#endif if (atomic_sub_return(1, &sem->count) < 0) ret = __down_trylock(sem); @@ -119,9 +95,6 @@ static inline int down_trylock(struct semaphore * sem) */ static inline void up(struct semaphore * sem) { -#if WAITQUEUE_DEBUG - CHECK_MAGIC(sem->__magic); -#endif if (atomic_add_return(1, &sem->count) <= 0) __up(sem); } diff --git a/include/asm-xtensa/system.h b/include/asm-xtensa/system.h index f093932..9284867 100644 --- a/include/asm-xtensa/system.h +++ b/include/asm-xtensa/system.h @@ -189,20 +189,6 @@ static inline unsigned long xchg_u32(volatile int * m, unsigned long val) #define tas(ptr) (xchg((ptr),1)) -#if ( __XCC__ == 1 ) - -/* xt-xcc processes __inline__ differently than xt-gcc and decides to - * insert an out-of-line copy of function __xchg. This presents the - * unresolved symbol at link time of __xchg_called_with_bad_pointer, - * even though such a function would never be called at run-time. - * xt-gcc always inlines __xchg, and optimizes away the undefined - * bad_pointer function. - */ - -#define xchg(ptr,x) xchg_u32(ptr,x) - -#else /* assume xt-gcc */ - #define xchg(ptr,x) ((__typeof__(*(ptr)))__xchg((unsigned long)(x),(ptr),sizeof(*(ptr)))) /* @@ -224,8 +210,6 @@ __xchg(unsigned long x, volatile void * ptr, int size) return x; } -#endif - extern void set_except_vector(int n, void *addr); static inline void spill_registers(void) diff --git a/include/linux/audit.h b/include/linux/audit.h index 68aba0c..b2a2509 100644 --- a/include/linux/audit.h +++ b/include/linux/audit.h @@ -51,7 +51,8 @@ #define AUDIT_WATCH_LIST 1009 /* List all file/dir watches */ #define AUDIT_SIGNAL_INFO 1010 /* Get info about sender of signal to auditd */ -#define AUDIT_FIRST_USER_MSG 1100 /* Userspace messages uninteresting to kernel */ +#define AUDIT_FIRST_USER_MSG 1100 /* Userspace messages mostly uninteresting to kernel */ +#define AUDIT_USER_AVC 1107 /* We filter this differently */ #define AUDIT_LAST_USER_MSG 1199 #define AUDIT_DAEMON_START 1200 /* Daemon startup record */ @@ -75,10 +76,15 @@ #define AUDIT_KERNEL 2000 /* Asynchronous audit record. NOT A REQUEST. */ /* Rule flags */ -#define AUDIT_PER_TASK 0x01 /* Apply rule at task creation (not syscall) */ -#define AUDIT_AT_ENTRY 0x02 /* Apply rule at syscall entry */ -#define AUDIT_AT_EXIT 0x04 /* Apply rule at syscall exit */ -#define AUDIT_PREPEND 0x10 /* Prepend to front of list */ +#define AUDIT_FILTER_USER 0x00 /* Apply rule to user-generated messages */ +#define AUDIT_FILTER_TASK 0x01 /* Apply rule at task creation (not syscall) */ +#define AUDIT_FILTER_ENTRY 0x02 /* Apply rule at syscall entry */ +#define AUDIT_FILTER_WATCH 0x03 /* Apply rule to file system watches */ +#define AUDIT_FILTER_EXIT 0x04 /* Apply rule at syscall exit */ + +#define AUDIT_NR_FILTERS 5 + +#define AUDIT_FILTER_PREPEND 0x10 /* Prepend to front of list */ /* Rule actions */ #define AUDIT_NEVER 0 /* Do not build context if rule matches */ @@ -199,6 +205,7 @@ struct audit_sig_info { struct audit_buffer; struct audit_context; struct inode; +struct netlink_skb_parms; #define AUDITSC_INVALID 0 #define AUDITSC_SUCCESS 1 @@ -215,7 +222,7 @@ extern void audit_syscall_entry(struct task_struct *task, int arch, extern void audit_syscall_exit(struct task_struct *task, int failed, long return_code); extern void audit_getname(const char *name); extern void audit_putname(const char *name); -extern void audit_inode(const char *name, const struct inode *inode); +extern void audit_inode(const char *name, const struct inode *inode, unsigned flags); /* Private API (for audit.c only) */ extern int audit_receive_filter(int type, int pid, int uid, int seq, @@ -230,6 +237,7 @@ extern int audit_socketcall(int nargs, unsigned long *args); extern int audit_sockaddr(int len, void *addr); extern int audit_avc_path(struct dentry *dentry, struct vfsmount *mnt); extern void audit_signal_info(int sig, struct task_struct *t); +extern int audit_filter_user(struct netlink_skb_parms *cb, int type); #else #define audit_alloc(t) ({ 0; }) #define audit_free(t) do { ; } while (0) @@ -237,7 +245,7 @@ extern void audit_signal_info(int sig, struct task_struct *t); #define audit_syscall_exit(t,f,r) do { ; } while (0) #define audit_getname(n) do { ; } while (0) #define audit_putname(n) do { ; } while (0) -#define audit_inode(n,i) do { ; } while (0) +#define audit_inode(n,i,f) do { ; } while (0) #define audit_receive_filter(t,p,u,s,d,l) ({ -EOPNOTSUPP; }) #define auditsc_get_stamp(c,t,s) do { BUG(); } while (0) #define audit_get_loginuid(c) ({ -1; }) @@ -246,16 +254,17 @@ extern void audit_signal_info(int sig, struct task_struct *t); #define audit_sockaddr(len, addr) ({ 0; }) #define audit_avc_path(dentry, mnt) ({ 0; }) #define audit_signal_info(s,t) do { ; } while (0) +#define audit_filter_user(cb,t) ({ 1; }) #endif #ifdef CONFIG_AUDIT /* These are defined in audit.c */ /* Public API */ -extern void audit_log(struct audit_context *ctx, int type, - const char *fmt, ...) - __attribute__((format(printf,3,4))); +extern void audit_log(struct audit_context *ctx, int gfp_mask, + int type, const char *fmt, ...) + __attribute__((format(printf,4,5))); -extern struct audit_buffer *audit_log_start(struct audit_context *ctx,int type); +extern struct audit_buffer *audit_log_start(struct audit_context *ctx, int gfp_mask, int type); extern void audit_log_format(struct audit_buffer *ab, const char *fmt, ...) __attribute__((format(printf,2,3))); @@ -274,9 +283,10 @@ extern void audit_send_reply(int pid, int seq, int type, int done, int multi, void *payload, int size); extern void audit_log_lost(const char *message); +extern struct semaphore audit_netlink_sem; #else -#define audit_log(c,t,f,...) do { ; } while (0) -#define audit_log_start(c,t) ({ NULL; }) +#define audit_log(c,g,t,f,...) do { ; } while (0) +#define audit_log_start(c,g,t) ({ NULL; }) #define audit_log_vformat(b,f,a) do { ; } while (0) #define audit_log_format(b,f,...) do { ; } while (0) #define audit_log_end(b) do { ; } while (0) diff --git a/include/linux/byteorder/generic.h b/include/linux/byteorder/generic.h index 5fde6f4..04bd756 100644 --- a/include/linux/byteorder/generic.h +++ b/include/linux/byteorder/generic.h @@ -5,6 +5,10 @@ * linux/byteorder_generic.h * Generic Byte-reordering support * + * The "... p" macros, like le64_to_cpup, can be used with pointers + * to unaligned data, but there will be a performance penalty on + * some architectures. Use get_unaligned for unaligned data. + * * Francois-Rene Rideau <fare@tunes.org> 19970707 * gathered all the good ideas from all asm-foo/byteorder.h into one file, * cleaned them up. diff --git a/include/linux/dccp.h b/include/linux/dccp.h index 8bf4bac..71fab43 100644 --- a/include/linux/dccp.h +++ b/include/linux/dccp.h @@ -4,16 +4,6 @@ #include <linux/types.h> #include <asm/byteorder.h> -/* Structure describing an Internet (DCCP) socket address. */ -struct sockaddr_dccp { - __u16 sdccp_family; /* Address family */ - __u16 sdccp_port; /* Port number */ - __u32 sdccp_addr; /* Internet address */ - __u32 sdccp_service; /* Service */ - /* Pad to size of `struct sockaddr': 16 bytes . */ - __u32 sdccp_pad; -}; - /** * struct dccp_hdr - generic part of DCCP packet header * @@ -188,6 +178,11 @@ enum { /* DCCP socket options */ #define DCCP_SOCKOPT_PACKET_SIZE 1 +#define DCCP_SOCKOPT_SERVICE 2 +#define DCCP_SOCKOPT_CCID_RX_INFO 128 +#define DCCP_SOCKOPT_CCID_TX_INFO 192 + +#define DCCP_SERVICE_LIST_MAX_LEN 32 #ifdef __KERNEL__ @@ -337,7 +332,8 @@ static inline unsigned int dccp_hdr_len(const struct sk_buff *skb) */ struct dccp_options { __u64 dccpo_sequence_window; - __u8 dccpo_ccid; + __u8 dccpo_rx_ccid; + __u8 dccpo_tx_ccid; __u8 dccpo_send_ack_vector; __u8 dccpo_send_ndp_count; }; @@ -360,14 +356,8 @@ static inline struct dccp_request_sock *dccp_rsk(const struct request_sock *req) extern struct inet_timewait_death_row dccp_death_row; -/* Read about the ECN nonce to see why it is 253 */ -#define DCCP_MAX_ACK_VECTOR_LEN 253 - struct dccp_options_received { - u32 dccpor_ndp:24, - dccpor_ack_vector_len:8; - u32 dccpor_ack_vector_idx:10; - /* 22 bits hole, try to pack */ + u32 dccpor_ndp; /* only 24 bits */ u32 dccpor_timestamp; u32 dccpor_timestamp_echo; u32 dccpor_elapsed_time; @@ -382,6 +372,27 @@ enum dccp_role { DCCP_ROLE_SERVER, }; +struct dccp_service_list { + __u32 dccpsl_nr; + __u32 dccpsl_list[0]; +}; + +#define DCCP_SERVICE_INVALID_VALUE htonl((__u32)-1) + +static inline int dccp_list_has_service(const struct dccp_service_list *sl, + const u32 service) +{ + if (likely(sl != NULL)) { + u32 i = sl->dccpsl_nr; + while (i--) + if (sl->dccpsl_list[i] == service) + return 1; + } + return 0; +} + +struct dccp_ackvec; + /** * struct dccp_sock - DCCP socket state * @@ -402,7 +413,7 @@ enum dccp_role { * @dccps_packet_size - Set thru setsockopt * @dccps_role - Role of this sock, one of %dccp_role * @dccps_ndp_count - number of Non Data Packets since last data packet - * @dccps_hc_rx_ackpkts - receiver half connection acked packets + * @dccps_hc_rx_ackvec - rx half connection ack vector */ struct dccp_sock { /* inet_connection_sock has to be the first member of dccp_sock */ @@ -417,7 +428,8 @@ struct dccp_sock { __u64 dccps_gss; __u64 dccps_gsr; __u64 dccps_gar; - unsigned long dccps_service; + __u32 dccps_service; + struct dccp_service_list *dccps_service_list; struct timeval dccps_timestamp_time; __u32 dccps_timestamp_echo; __u32 dccps_packet_size; @@ -426,7 +438,7 @@ struct dccp_sock { __u32 dccps_pmtu_cookie; __u32 dccps_mss_cache; struct dccp_options dccps_options; - struct dccp_ackpkts *dccps_hc_rx_ackpkts; + struct dccp_ackvec *dccps_hc_rx_ackvec; void *dccps_hc_rx_ccid_private; void *dccps_hc_tx_ccid_private; struct ccid *dccps_hc_rx_ccid; @@ -443,6 +455,11 @@ static inline struct dccp_sock *dccp_sk(const struct sock *sk) return (struct dccp_sock *)sk; } +static inline int dccp_service_not_initialized(const struct sock *sk) +{ + return dccp_sk(sk)->dccps_service == DCCP_SERVICE_INVALID_VALUE; +} + static inline const char *dccp_role(const struct sock *sk) { switch (dccp_sk(sk)->dccps_role) { diff --git a/include/linux/device.h b/include/linux/device.h index 06e5d42..95d607a 100644 --- a/include/linux/device.h +++ b/include/linux/device.h @@ -317,6 +317,11 @@ dev_set_drvdata (struct device *dev, void *data) dev->driver_data = data; } +static inline int device_is_registered(struct device *dev) +{ + return klist_node_attached(&dev->knode_bus); +} + /* * High level routines for use by the bus drivers */ diff --git a/include/linux/fb.h b/include/linux/fb.h index 82e39cd..c698055 100644 --- a/include/linux/fb.h +++ b/include/linux/fb.h @@ -619,7 +619,7 @@ struct fb_tilemap { __u32 height; /* height of each tile in scanlines */ __u32 depth; /* color depth of each tile */ __u32 length; /* number of tiles in the map */ - __u8 *data; /* actual tile map: a bitmap array, packed + const __u8 *data; /* actual tile map: a bitmap array, packed to the nearest byte */ }; diff --git a/include/linux/font.h b/include/linux/font.h index 8fc80a7..53b129f 100644 --- a/include/linux/font.h +++ b/include/linux/font.h @@ -15,9 +15,9 @@ struct font_desc { int idx; - char *name; + const char *name; int width, height; - void *data; + const void *data; int pref; }; @@ -32,7 +32,7 @@ struct font_desc { #define ACORN8x8_IDX 8 #define MINI4x6_IDX 9 -extern struct font_desc font_vga_8x8, +extern const struct font_desc font_vga_8x8, font_vga_8x16, font_pearl_8x8, font_vga_6x11, @@ -45,11 +45,11 @@ extern struct font_desc font_vga_8x8, /* Find a font with a specific name */ -extern struct font_desc *find_font(char *name); +extern const struct font_desc *find_font(const char *name); /* Get the default font for a specific screen size */ -extern struct font_desc *get_default_font(int xres, int yres); +extern const struct font_desc *get_default_font(int xres, int yres); /* Max. length for the name of a predefined font */ #define MAX_FONT_NAME 32 diff --git a/include/linux/i2c.h b/include/linux/i2c.h index be35332..3d49a30 100644 --- a/include/linux/i2c.h +++ b/include/linux/i2c.h @@ -230,11 +230,6 @@ struct i2c_adapter { struct device dev; /* the adapter device */ struct class_device class_dev; /* the class device */ -#ifdef CONFIG_PROC_FS - /* No need to set this when you initialize the adapter */ - int inode; -#endif /* def CONFIG_PROC_FS */ - int nr; struct list_head clients; struct list_head list; diff --git a/include/linux/if_vlan.h b/include/linux/if_vlan.h index 17d0c0d..eef0876 100644 --- a/include/linux/if_vlan.h +++ b/include/linux/if_vlan.h @@ -42,8 +42,8 @@ struct hlist_node; struct vlan_ethhdr { unsigned char h_dest[ETH_ALEN]; /* destination eth addr */ unsigned char h_source[ETH_ALEN]; /* source ether addr */ - unsigned short h_vlan_proto; /* Should always be 0x8100 */ - unsigned short h_vlan_TCI; /* Encapsulates priority and VLAN ID */ + __be16 h_vlan_proto; /* Should always be 0x8100 */ + __be16 h_vlan_TCI; /* Encapsulates priority and VLAN ID */ unsigned short h_vlan_encapsulated_proto; /* packet type ID field (or len) */ }; @@ -55,8 +55,8 @@ static inline struct vlan_ethhdr *vlan_eth_hdr(const struct sk_buff *skb) } struct vlan_hdr { - unsigned short h_vlan_TCI; /* Encapsulates priority and VLAN ID */ - unsigned short h_vlan_encapsulated_proto; /* packet type ID field (or len) */ + __be16 h_vlan_TCI; /* Encapsulates priority and VLAN ID */ + __be16 h_vlan_encapsulated_proto; /* packet type ID field (or len) */ }; #define VLAN_VID_MASK 0xfff diff --git a/include/linux/joystick.h b/include/linux/joystick.h index 06b9af7..5fd20dd 100644 --- a/include/linux/joystick.h +++ b/include/linux/joystick.h @@ -111,29 +111,30 @@ struct js_corr { #define JS_SET_ALL 8 struct JS_DATA_TYPE { - __s32 buttons; - __s32 x; - __s32 y; + int32_t buttons; + int32_t x; + int32_t y; }; struct JS_DATA_SAVE_TYPE_32 { - __s32 JS_TIMEOUT; - __s32 BUSY; - __s32 JS_EXPIRETIME; - __s32 JS_TIMELIMIT; + int32_t JS_TIMEOUT; + int32_t BUSY; + int32_t JS_EXPIRETIME; + int32_t JS_TIMELIMIT; struct JS_DATA_TYPE JS_SAVE; struct JS_DATA_TYPE JS_CORR; }; struct JS_DATA_SAVE_TYPE_64 { - __s32 JS_TIMEOUT; - __s32 BUSY; - __s64 JS_EXPIRETIME; - __s64 JS_TIMELIMIT; + int32_t JS_TIMEOUT; + int32_t BUSY; + int64_t JS_EXPIRETIME; + int64_t JS_TIMELIMIT; struct JS_DATA_TYPE JS_SAVE; struct JS_DATA_TYPE JS_CORR; }; +#ifdef __KERNEL__ #if BITS_PER_LONG == 64 #define JS_DATA_SAVE_TYPE JS_DATA_SAVE_TYPE_64 #elif BITS_PER_LONG == 32 @@ -141,5 +142,6 @@ struct JS_DATA_SAVE_TYPE_64 { #else #error Unexpected BITS_PER_LONG #endif +#endif #endif /* _LINUX_JOYSTICK_H */ diff --git a/include/linux/kernel.h b/include/linux/kernel.h index 687ba8c..4367ce4 100644 --- a/include/linux/kernel.h +++ b/include/linux/kernel.h @@ -307,8 +307,8 @@ struct sysinfo { char _f[20-2*sizeof(long)-sizeof(int)]; /* Padding: libc5 uses this.. */ }; -extern void BUILD_BUG(void); -#define BUILD_BUG_ON(condition) do { if (condition) BUILD_BUG(); } while(0) +/* Force a compilation error if condition is false */ +#define BUILD_BUG_ON(condition) ((void)sizeof(char[1 - 2*!!(condition)])) #ifdef CONFIG_SYSCTL extern int randomize_va_space; diff --git a/include/linux/libata.h b/include/linux/libata.h index f76f54a..7680b63 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -399,6 +399,7 @@ extern int ata_pci_init_one (struct pci_dev *pdev, struct ata_port_info **port_i extern void ata_pci_remove_one (struct pci_dev *pdev); #endif /* CONFIG_PCI */ extern int ata_device_add(struct ata_probe_ent *ent); +extern void ata_host_set_remove(struct ata_host_set *host_set); extern int ata_scsi_detect(Scsi_Host_Template *sht); extern int ata_scsi_ioctl(struct scsi_device *dev, int cmd, void __user *arg); extern int ata_scsi_queuecmd(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *)); diff --git a/include/linux/mm.h b/include/linux/mm.h index 82d7024..097b3a3 100644 --- a/include/linux/mm.h +++ b/include/linux/mm.h @@ -136,6 +136,7 @@ extern unsigned int kobjsize(const void *objp); #define VM_EXEC 0x00000004 #define VM_SHARED 0x00000008 +/* mprotect() hardcodes VM_MAYREAD >> 4 == VM_READ, and so for r/w/x bits. */ #define VM_MAYREAD 0x00000010 /* limits for mprotect() etc */ #define VM_MAYWRITE 0x00000020 #define VM_MAYEXEC 0x00000040 @@ -350,7 +351,8 @@ static inline void put_page(struct page *page) * only one copy in memory, at most, normally. * * For the non-reserved pages, page_count(page) denotes a reference count. - * page_count() == 0 means the page is free. + * page_count() == 0 means the page is free. page->lru is then used for + * freelist management in the buddy allocator. * page_count() == 1 means the page is used for exactly one purpose * (e.g. a private data page of one process). * @@ -376,10 +378,8 @@ static inline void put_page(struct page *page) * attaches, plus 1 if `private' contains something, plus one for * the page cache itself. * - * All pages belonging to an inode are in these doubly linked lists: - * mapping->clean_pages, mapping->dirty_pages and mapping->locked_pages; - * using the page->list list_head. These fields are also used for - * freelist managemet (when page_count()==0). + * Instead of keeping dirty/clean pages in per address-space lists, we instead + * now tag pages as dirty/under writeback in the radix tree. * * There is also a per-mapping radix tree mapping index to the page * in memory if present. The tree is rooted at mapping->root. diff --git a/include/linux/netfilter_ipv4/ip_conntrack.h b/include/linux/netfilter_ipv4/ip_conntrack.h index 7e033e9..4ced387 100644 --- a/include/linux/netfilter_ipv4/ip_conntrack.h +++ b/include/linux/netfilter_ipv4/ip_conntrack.h @@ -133,11 +133,13 @@ enum ip_conntrack_expect_events { #include <linux/netfilter_ipv4/ip_conntrack_tcp.h> #include <linux/netfilter_ipv4/ip_conntrack_icmp.h> +#include <linux/netfilter_ipv4/ip_conntrack_proto_gre.h> #include <linux/netfilter_ipv4/ip_conntrack_sctp.h> /* per conntrack: protocol private data */ union ip_conntrack_proto { /* insert conntrack proto private data here */ + struct ip_ct_gre gre; struct ip_ct_sctp sctp; struct ip_ct_tcp tcp; struct ip_ct_icmp icmp; @@ -148,6 +150,7 @@ union ip_conntrack_expect_proto { }; /* Add protocol helper include file here */ +#include <linux/netfilter_ipv4/ip_conntrack_pptp.h> #include <linux/netfilter_ipv4/ip_conntrack_amanda.h> #include <linux/netfilter_ipv4/ip_conntrack_ftp.h> #include <linux/netfilter_ipv4/ip_conntrack_irc.h> @@ -155,12 +158,20 @@ union ip_conntrack_expect_proto { /* per conntrack: application helper private data */ union ip_conntrack_help { /* insert conntrack helper private data (master) here */ + struct ip_ct_pptp_master ct_pptp_info; struct ip_ct_ftp_master ct_ftp_info; struct ip_ct_irc_master ct_irc_info; }; #ifdef CONFIG_IP_NF_NAT_NEEDED #include <linux/netfilter_ipv4/ip_nat.h> +#include <linux/netfilter_ipv4/ip_nat_pptp.h> + +/* per conntrack: nat application helper private data */ +union ip_conntrack_nat_help { + /* insert nat helper private data here */ + struct ip_nat_pptp nat_pptp_info; +}; #endif #include <linux/types.h> @@ -223,6 +234,7 @@ struct ip_conntrack #ifdef CONFIG_IP_NF_NAT_NEEDED struct { struct ip_nat_info info; + union ip_conntrack_nat_help help; #if defined(CONFIG_IP_NF_TARGET_MASQUERADE) || \ defined(CONFIG_IP_NF_TARGET_MASQUERADE_MODULE) int masq_index; @@ -320,11 +332,28 @@ extern void need_ip_conntrack(void); extern int invert_tuplepr(struct ip_conntrack_tuple *inverse, const struct ip_conntrack_tuple *orig); +extern void __ip_ct_refresh_acct(struct ip_conntrack *ct, + enum ip_conntrack_info ctinfo, + const struct sk_buff *skb, + unsigned long extra_jiffies, + int do_acct); + +/* Refresh conntrack for this many jiffies and do accounting */ +static inline void ip_ct_refresh_acct(struct ip_conntrack *ct, + enum ip_conntrack_info ctinfo, + const struct sk_buff *skb, + unsigned long extra_jiffies) +{ + __ip_ct_refresh_acct(ct, ctinfo, skb, extra_jiffies, 1); +} + /* Refresh conntrack for this many jiffies */ -extern void ip_ct_refresh_acct(struct ip_conntrack *ct, - enum ip_conntrack_info ctinfo, - const struct sk_buff *skb, - unsigned long extra_jiffies); +static inline void ip_ct_refresh(struct ip_conntrack *ct, + const struct sk_buff *skb, + unsigned long extra_jiffies) +{ + __ip_ct_refresh_acct(ct, 0, skb, extra_jiffies, 0); +} /* These are for NAT. Icky. */ /* Update TCP window tracking data when NAT mangles the packet */ @@ -372,7 +401,7 @@ extern struct ip_conntrack_expect * __ip_conntrack_expect_find(const struct ip_conntrack_tuple *tuple); extern struct ip_conntrack_expect * -ip_conntrack_expect_find_get(const struct ip_conntrack_tuple *tuple); +ip_conntrack_expect_find(const struct ip_conntrack_tuple *tuple); extern struct ip_conntrack_tuple_hash * __ip_conntrack_find(const struct ip_conntrack_tuple *tuple, diff --git a/include/linux/netfilter_ipv4/ip_conntrack_pptp.h b/include/linux/netfilter_ipv4/ip_conntrack_pptp.h new file mode 100644 index 0000000..816144c --- /dev/null +++ b/include/linux/netfilter_ipv4/ip_conntrack_pptp.h @@ -0,0 +1,325 @@ +/* PPTP constants and structs */ +#ifndef _CONNTRACK_PPTP_H +#define _CONNTRACK_PPTP_H + +/* state of the control session */ +enum pptp_ctrlsess_state { + PPTP_SESSION_NONE, /* no session present */ + PPTP_SESSION_ERROR, /* some session error */ + PPTP_SESSION_STOPREQ, /* stop_sess request seen */ + PPTP_SESSION_REQUESTED, /* start_sess request seen */ + PPTP_SESSION_CONFIRMED, /* session established */ +}; + +/* state of the call inside the control session */ +enum pptp_ctrlcall_state { + PPTP_CALL_NONE, + PPTP_CALL_ERROR, + PPTP_CALL_OUT_REQ, + PPTP_CALL_OUT_CONF, + PPTP_CALL_IN_REQ, + PPTP_CALL_IN_REP, + PPTP_CALL_IN_CONF, + PPTP_CALL_CLEAR_REQ, +}; + + +/* conntrack private data */ +struct ip_ct_pptp_master { + enum pptp_ctrlsess_state sstate; /* session state */ + + /* everything below is going to be per-expectation in newnat, + * since there could be more than one call within one session */ + enum pptp_ctrlcall_state cstate; /* call state */ + u_int16_t pac_call_id; /* call id of PAC, host byte order */ + u_int16_t pns_call_id; /* call id of PNS, host byte order */ + + /* in pre-2.6.11 this used to be per-expect. Now it is per-conntrack + * and therefore imposes a fixed limit on the number of maps */ + struct ip_ct_gre_keymap *keymap_orig, *keymap_reply; +}; + +/* conntrack_expect private member */ +struct ip_ct_pptp_expect { + enum pptp_ctrlcall_state cstate; /* call state */ + u_int16_t pac_call_id; /* call id of PAC */ + u_int16_t pns_call_id; /* call id of PNS */ +}; + + +#ifdef __KERNEL__ + +#define IP_CONNTR_PPTP PPTP_CONTROL_PORT + +#define PPTP_CONTROL_PORT 1723 + +#define PPTP_PACKET_CONTROL 1 +#define PPTP_PACKET_MGMT 2 + +#define PPTP_MAGIC_COOKIE 0x1a2b3c4d + +struct pptp_pkt_hdr { + __u16 packetLength; + __be16 packetType; + __be32 magicCookie; +}; + +/* PptpControlMessageType values */ +#define PPTP_START_SESSION_REQUEST 1 +#define PPTP_START_SESSION_REPLY 2 +#define PPTP_STOP_SESSION_REQUEST 3 +#define PPTP_STOP_SESSION_REPLY 4 +#define PPTP_ECHO_REQUEST 5 +#define PPTP_ECHO_REPLY 6 +#define PPTP_OUT_CALL_REQUEST 7 +#define PPTP_OUT_CALL_REPLY 8 +#define PPTP_IN_CALL_REQUEST 9 +#define PPTP_IN_CALL_REPLY 10 +#define PPTP_IN_CALL_CONNECT 11 +#define PPTP_CALL_CLEAR_REQUEST 12 +#define PPTP_CALL_DISCONNECT_NOTIFY 13 +#define PPTP_WAN_ERROR_NOTIFY 14 +#define PPTP_SET_LINK_INFO 15 + +#define PPTP_MSG_MAX 15 + +/* PptpGeneralError values */ +#define PPTP_ERROR_CODE_NONE 0 +#define PPTP_NOT_CONNECTED 1 +#define PPTP_BAD_FORMAT 2 +#define PPTP_BAD_VALUE 3 +#define PPTP_NO_RESOURCE 4 +#define PPTP_BAD_CALLID 5 +#define PPTP_REMOVE_DEVICE_ERROR 6 + +struct PptpControlHeader { + __be16 messageType; + __u16 reserved; +}; + +/* FramingCapability Bitmap Values */ +#define PPTP_FRAME_CAP_ASYNC 0x1 +#define PPTP_FRAME_CAP_SYNC 0x2 + +/* BearerCapability Bitmap Values */ +#define PPTP_BEARER_CAP_ANALOG 0x1 +#define PPTP_BEARER_CAP_DIGITAL 0x2 + +struct PptpStartSessionRequest { + __be16 protocolVersion; + __u8 reserved1; + __u8 reserved2; + __be32 framingCapability; + __be32 bearerCapability; + __be16 maxChannels; + __be16 firmwareRevision; + __u8 hostName[64]; + __u8 vendorString[64]; +}; + +/* PptpStartSessionResultCode Values */ +#define PPTP_START_OK 1 +#define PPTP_START_GENERAL_ERROR 2 +#define PPTP_START_ALREADY_CONNECTED 3 +#define PPTP_START_NOT_AUTHORIZED 4 +#define PPTP_START_UNKNOWN_PROTOCOL 5 + +struct PptpStartSessionReply { + __be16 protocolVersion; + __u8 resultCode; + __u8 generalErrorCode; + __be32 framingCapability; + __be32 bearerCapability; + __be16 maxChannels; + __be16 firmwareRevision; + __u8 hostName[64]; + __u8 vendorString[64]; +}; + +/* PptpStopReasons */ +#define PPTP_STOP_NONE 1 +#define PPTP_STOP_PROTOCOL 2 +#define PPTP_STOP_LOCAL_SHUTDOWN 3 + +struct PptpStopSessionRequest { + __u8 reason; +}; + +/* PptpStopSessionResultCode */ +#define PPTP_STOP_OK 1 +#define PPTP_STOP_GENERAL_ERROR 2 + +struct PptpStopSessionReply { + __u8 resultCode; + __u8 generalErrorCode; +}; + +struct PptpEchoRequest { + __be32 identNumber; +}; + +/* PptpEchoReplyResultCode */ +#define PPTP_ECHO_OK 1 +#define PPTP_ECHO_GENERAL_ERROR 2 + +struct PptpEchoReply { + __be32 identNumber; + __u8 resultCode; + __u8 generalErrorCode; + __u16 reserved; +}; + +/* PptpFramingType */ +#define PPTP_ASYNC_FRAMING 1 +#define PPTP_SYNC_FRAMING 2 +#define PPTP_DONT_CARE_FRAMING 3 + +/* PptpCallBearerType */ +#define PPTP_ANALOG_TYPE 1 +#define PPTP_DIGITAL_TYPE 2 +#define PPTP_DONT_CARE_BEARER_TYPE 3 + +struct PptpOutCallRequest { + __be16 callID; + __be16 callSerialNumber; + __be32 minBPS; + __be32 maxBPS; + __be32 bearerType; + __be32 framingType; + __be16 packetWindow; + __be16 packetProcDelay; + __u16 reserved1; + __be16 phoneNumberLength; + __u16 reserved2; + __u8 phoneNumber[64]; + __u8 subAddress[64]; +}; + +/* PptpCallResultCode */ +#define PPTP_OUTCALL_CONNECT 1 +#define PPTP_OUTCALL_GENERAL_ERROR 2 +#define PPTP_OUTCALL_NO_CARRIER 3 +#define PPTP_OUTCALL_BUSY 4 +#define PPTP_OUTCALL_NO_DIAL_TONE 5 +#define PPTP_OUTCALL_TIMEOUT 6 +#define PPTP_OUTCALL_DONT_ACCEPT 7 + +struct PptpOutCallReply { + __be16 callID; + __be16 peersCallID; + __u8 resultCode; + __u8 generalErrorCode; + __be16 causeCode; + __be32 connectSpeed; + __be16 packetWindow; + __be16 packetProcDelay; + __be32 physChannelID; +}; + +struct PptpInCallRequest { + __be16 callID; + __be16 callSerialNumber; + __be32 callBearerType; + __be32 physChannelID; + __be16 dialedNumberLength; + __be16 dialingNumberLength; + __u8 dialedNumber[64]; + __u8 dialingNumber[64]; + __u8 subAddress[64]; +}; + +/* PptpInCallResultCode */ +#define PPTP_INCALL_ACCEPT 1 +#define PPTP_INCALL_GENERAL_ERROR 2 +#define PPTP_INCALL_DONT_ACCEPT 3 + +struct PptpInCallReply { + __be16 callID; + __be16 peersCallID; + __u8 resultCode; + __u8 generalErrorCode; + __be16 packetWindow; + __be16 packetProcDelay; + __u16 reserved; +}; + +struct PptpInCallConnected { + __be16 peersCallID; + __u16 reserved; + __be32 connectSpeed; + __be16 packetWindow; + __be16 packetProcDelay; + __be32 callFramingType; +}; + +struct PptpClearCallRequest { + __be16 callID; + __u16 reserved; +}; + +struct PptpCallDisconnectNotify { + __be16 callID; + __u8 resultCode; + __u8 generalErrorCode; + __be16 causeCode; + __u16 reserved; + __u8 callStatistics[128]; +}; + +struct PptpWanErrorNotify { + __be16 peersCallID; + __u16 reserved; + __be32 crcErrors; + __be32 framingErrors; + __be32 hardwareOverRuns; + __be32 bufferOverRuns; + __be32 timeoutErrors; + __be32 alignmentErrors; +}; + +struct PptpSetLinkInfo { + __be16 peersCallID; + __u16 reserved; + __be32 sendAccm; + __be32 recvAccm; +}; + +union pptp_ctrl_union { + struct PptpStartSessionRequest sreq; + struct PptpStartSessionReply srep; + struct PptpStopSessionRequest streq; + struct PptpStopSessionReply strep; + struct PptpOutCallRequest ocreq; + struct PptpOutCallReply ocack; + struct PptpInCallRequest icreq; + struct PptpInCallReply icack; + struct PptpInCallConnected iccon; + struct PptpClearCallRequest clrreq; + struct PptpCallDisconnectNotify disc; + struct PptpWanErrorNotify wanerr; + struct PptpSetLinkInfo setlink; +}; + +extern int +(*ip_nat_pptp_hook_outbound)(struct sk_buff **pskb, + struct ip_conntrack *ct, + enum ip_conntrack_info ctinfo, + struct PptpControlHeader *ctlh, + union pptp_ctrl_union *pptpReq); + +extern int +(*ip_nat_pptp_hook_inbound)(struct sk_buff **pskb, + struct ip_conntrack *ct, + enum ip_conntrack_info ctinfo, + struct PptpControlHeader *ctlh, + union pptp_ctrl_union *pptpReq); + +extern int +(*ip_nat_pptp_hook_exp_gre)(struct ip_conntrack_expect *exp_orig, + struct ip_conntrack_expect *exp_reply); + +extern void +(*ip_nat_pptp_hook_expectfn)(struct ip_conntrack *ct, + struct ip_conntrack_expect *exp); +#endif /* __KERNEL__ */ +#endif /* _CONNTRACK_PPTP_H */ diff --git a/include/linux/netfilter_ipv4/ip_conntrack_proto_gre.h b/include/linux/netfilter_ipv4/ip_conntrack_proto_gre.h new file mode 100644 index 0000000..8d090ef --- /dev/null +++ b/include/linux/netfilter_ipv4/ip_conntrack_proto_gre.h @@ -0,0 +1,114 @@ +#ifndef _CONNTRACK_PROTO_GRE_H +#define _CONNTRACK_PROTO_GRE_H +#include <asm/byteorder.h> + +/* GRE PROTOCOL HEADER */ + +/* GRE Version field */ +#define GRE_VERSION_1701 0x0 +#define GRE_VERSION_PPTP 0x1 + +/* GRE Protocol field */ +#define GRE_PROTOCOL_PPTP 0x880B + +/* GRE Flags */ +#define GRE_FLAG_C 0x80 +#define GRE_FLAG_R 0x40 +#define GRE_FLAG_K 0x20 +#define GRE_FLAG_S 0x10 +#define GRE_FLAG_A 0x80 + +#define GRE_IS_C(f) ((f)&GRE_FLAG_C) +#define GRE_IS_R(f) ((f)&GRE_FLAG_R) +#define GRE_IS_K(f) ((f)&GRE_FLAG_K) +#define GRE_IS_S(f) ((f)&GRE_FLAG_S) +#define GRE_IS_A(f) ((f)&GRE_FLAG_A) + +/* GRE is a mess: Four different standards */ +struct gre_hdr { +#if defined(__LITTLE_ENDIAN_BITFIELD) + __u16 rec:3, + srr:1, + seq:1, + key:1, + routing:1, + csum:1, + version:3, + reserved:4, + ack:1; +#elif defined(__BIG_ENDIAN_BITFIELD) + __u16 csum:1, + routing:1, + key:1, + seq:1, + srr:1, + rec:3, + ack:1, + reserved:4, + version:3; +#else +#error "Adjust your <asm/byteorder.h> defines" +#endif + __u16 protocol; +}; + +/* modified GRE header for PPTP */ +struct gre_hdr_pptp { + __u8 flags; /* bitfield */ + __u8 version; /* should be GRE_VERSION_PPTP */ + __u16 protocol; /* should be GRE_PROTOCOL_PPTP */ + __u16 payload_len; /* size of ppp payload, not inc. gre header */ + __u16 call_id; /* peer's call_id for this session */ + __u32 seq; /* sequence number. Present if S==1 */ + __u32 ack; /* seq number of highest packet recieved by */ + /* sender in this session */ +}; + + +/* this is part of ip_conntrack */ +struct ip_ct_gre { + unsigned int stream_timeout; + unsigned int timeout; +}; + +#ifdef __KERNEL__ +struct ip_conntrack_expect; +struct ip_conntrack; + +/* structure for original <-> reply keymap */ +struct ip_ct_gre_keymap { + struct list_head list; + + struct ip_conntrack_tuple tuple; +}; + +/* add new tuple->key_reply pair to keymap */ +int ip_ct_gre_keymap_add(struct ip_conntrack *ct, + struct ip_conntrack_tuple *t, + int reply); + +/* delete keymap entries */ +void ip_ct_gre_keymap_destroy(struct ip_conntrack *ct); + + +/* get pointer to gre key, if present */ +static inline u_int32_t *gre_key(struct gre_hdr *greh) +{ + if (!greh->key) + return NULL; + if (greh->csum || greh->routing) + return (u_int32_t *) (greh+sizeof(*greh)+4); + return (u_int32_t *) (greh+sizeof(*greh)); +} + +/* get pointer ot gre csum, if present */ +static inline u_int16_t *gre_csum(struct gre_hdr *greh) +{ + if (!greh->csum) + return NULL; + return (u_int16_t *) (greh+sizeof(*greh)); +} + +#endif /* __KERNEL__ */ + +#endif /* _CONNTRACK_PROTO_GRE_H */ diff --git a/include/linux/netfilter_ipv4/ip_conntrack_tuple.h b/include/linux/netfilter_ipv4/ip_conntrack_tuple.h index c33f0b5..20e43f0 100644 --- a/include/linux/netfilter_ipv4/ip_conntrack_tuple.h +++ b/include/linux/netfilter_ipv4/ip_conntrack_tuple.h @@ -17,7 +17,7 @@ union ip_conntrack_manip_proto u_int16_t all; struct { - u_int16_t port; + __be16 port; } tcp; struct { u_int16_t port; @@ -28,6 +28,9 @@ union ip_conntrack_manip_proto struct { u_int16_t port; } sctp; + struct { + __be16 key; /* key is 32bit, pptp only uses 16 */ + } gre; }; /* The manipulable part of the tuple. */ @@ -61,6 +64,10 @@ struct ip_conntrack_tuple struct { u_int16_t port; } sctp; + struct { + __be16 key; /* key is 32bit, + * pptp only uses 16 */ + } gre; } u; /* The protocol. */ diff --git a/include/linux/netfilter_ipv4/ip_nat_pptp.h b/include/linux/netfilter_ipv4/ip_nat_pptp.h new file mode 100644 index 0000000..eaf66c2 --- /dev/null +++ b/include/linux/netfilter_ipv4/ip_nat_pptp.h @@ -0,0 +1,11 @@ +/* PPTP constants and structs */ +#ifndef _NAT_PPTP_H +#define _NAT_PPTP_H + +/* conntrack private data */ +struct ip_nat_pptp { + u_int16_t pns_call_id; /* NAT'ed PNS call id */ + u_int16_t pac_call_id; /* NAT'ed PAC call id */ +}; + +#endif /* _NAT_PPTP_H */ diff --git a/include/linux/netfilter_ipv6/ip6_tables.h b/include/linux/netfilter_ipv6/ip6_tables.h index 58c72a5..59f70b3 100644 --- a/include/linux/netfilter_ipv6/ip6_tables.h +++ b/include/linux/netfilter_ipv6/ip6_tables.h @@ -455,6 +455,9 @@ extern unsigned int ip6t_do_table(struct sk_buff **pskb, /* Check for an extension */ extern int ip6t_ext_hdr(u8 nexthdr); +/* find specified header and get offset to it */ +extern int ipv6_find_hdr(const struct sk_buff *skb, unsigned int *offset, + u8 target); #define IP6T_ALIGN(s) (((s) + (__alignof__(struct ip6t_entry)-1)) & ~(__alignof__(struct ip6t_entry)-1)) diff --git a/include/linux/netlink.h b/include/linux/netlink.h index 7bbd259..bdebdc5 100644 --- a/include/linux/netlink.h +++ b/include/linux/netlink.h @@ -20,6 +20,7 @@ #define NETLINK_IP6_FW 13 #define NETLINK_DNRTMSG 14 /* DECnet routing messages */ #define NETLINK_KOBJECT_UEVENT 15 /* Kernel messages to userspace */ +#define NETLINK_GENERIC 16 #define MAX_LINKS 32 diff --git a/include/linux/nfsd/xdr4.h b/include/linux/nfsd/xdr4.h index 4d24d65..8903688 100644 --- a/include/linux/nfsd/xdr4.h +++ b/include/linux/nfsd/xdr4.h @@ -438,17 +438,22 @@ extern int nfsd4_process_open1(struct nfsd4_open *open); extern int nfsd4_process_open2(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_open *open); extern int nfsd4_open_confirm(struct svc_rqst *rqstp, - struct svc_fh *current_fh, struct nfsd4_open_confirm *oc); + struct svc_fh *current_fh, struct nfsd4_open_confirm *oc, + struct nfs4_stateowner **); extern int nfsd4_close(struct svc_rqst *rqstp, struct svc_fh *current_fh, - struct nfsd4_close *close); + struct nfsd4_close *close, + struct nfs4_stateowner **replay_owner); extern int nfsd4_open_downgrade(struct svc_rqst *rqstp, - struct svc_fh *current_fh, struct nfsd4_open_downgrade *od); + struct svc_fh *current_fh, struct nfsd4_open_downgrade *od, + struct nfs4_stateowner **replay_owner); extern int nfsd4_lock(struct svc_rqst *rqstp, struct svc_fh *current_fh, - struct nfsd4_lock *lock); + struct nfsd4_lock *lock, + struct nfs4_stateowner **replay_owner); extern int nfsd4_lockt(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_lockt *lockt); extern int nfsd4_locku(struct svc_rqst *rqstp, struct svc_fh *current_fh, - struct nfsd4_locku *locku); + struct nfsd4_locku *locku, + struct nfs4_stateowner **replay_owner); extern int nfsd4_release_lockowner(struct svc_rqst *rqstp, struct nfsd4_release_lockowner *rlockowner); diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h index ee0ab7a5..b86a4b7 100644 --- a/include/linux/pci_ids.h +++ b/include/linux/pci_ids.h @@ -447,6 +447,10 @@ #define PCI_DEVICE_ID_CIRRUS_7542 0x1200 #define PCI_DEVICE_ID_CIRRUS_7543 0x1202 #define PCI_DEVICE_ID_CIRRUS_7541 0x1204 +#define PCI_DEVICE_ID_CIRRUS_4610 0x6001 +#define PCI_DEVICE_ID_CIRRUS_4612 0x6003 +#define PCI_DEVICE_ID_CIRRUS_4615 0x6004 +#define PCI_DEVICE_ID_CIRRUS_4281 0x6005 #define PCI_VENDOR_ID_IBM 0x1014 #define PCI_DEVICE_ID_IBM_FIRE_CORAL 0x000a @@ -487,6 +491,7 @@ #define PCI_DEVICE_ID_AMI_MEGARAID2 0x9060 #define PCI_VENDOR_ID_AMD 0x1022 +#define PCI_DEVICE_ID_AMD_K8_NB 0x1100 #define PCI_DEVICE_ID_AMD_LANCE 0x2000 #define PCI_DEVICE_ID_AMD_LANCE_HOME 0x2001 #define PCI_DEVICE_ID_AMD_SCSI 0x2020 @@ -682,7 +687,9 @@ #define PCI_DEVICE_ID_SI_6326 0x6326 #define PCI_DEVICE_ID_SI_7001 0x7001 #define PCI_DEVICE_ID_SI_7012 0x7012 +#define PCI_DEVICE_ID_SI_7013 0x7013 #define PCI_DEVICE_ID_SI_7016 0x7016 +#define PCI_DEVICE_ID_SI_7018 0x7018 #define PCI_VENDOR_ID_HP 0x103c #define PCI_DEVICE_ID_HP_VISUALIZE_EG 0x1005 @@ -713,10 +720,12 @@ #define PCI_DEVICE_ID_HP_DIVA_EVEREST 0x1282 #define PCI_DEVICE_ID_HP_DIVA_AUX 0x1290 #define PCI_DEVICE_ID_HP_DIVA_RMP3 0x1301 +#define PCI_DEVICE_ID_HP_CISS 0x3210 #define PCI_DEVICE_ID_HP_CISSA 0x3220 #define PCI_DEVICE_ID_HP_CISSB 0x3222 -#define PCI_DEVICE_ID_HP_ZX2_IOC 0x4031 #define PCI_DEVICE_ID_HP_CISSC 0x3230 +#define PCI_DEVICE_ID_HP_CISSD 0x3238 +#define PCI_DEVICE_ID_HP_ZX2_IOC 0x4031 #define PCI_VENDOR_ID_PCTECH 0x1042 #define PCI_DEVICE_ID_PCTECH_RZ1000 0x1000 @@ -991,6 +1000,7 @@ #define PCI_DEVICE_ID_BROOKTREE_849A 0x0351 #define PCI_DEVICE_ID_BROOKTREE_878_1 0x036e #define PCI_DEVICE_ID_BROOKTREE_878 0x0878 +#define PCI_DEVICE_ID_BROOKTREE_879 0x0879 #define PCI_DEVICE_ID_BROOKTREE_8474 0x8474 #define PCI_VENDOR_ID_SIERRA 0x10a8 @@ -1109,6 +1119,9 @@ #define PCI_DEVICE_ID_NEOMAGIC_MAGICGRAPH_NM2160 0x0004 #define PCI_DEVICE_ID_NEOMAGIC_MAGICMEDIA_256AV 0x0005 #define PCI_DEVICE_ID_NEOMAGIC_MAGICGRAPH_128ZVPLUS 0x0083 +#define PCI_DEVICE_ID_NEOMAGIC_NM256AV_AUDIO 0x8005 +#define PCI_DEVICE_ID_NEOMAGIC_NM256ZX_AUDIO 0x8006 +#define PCI_DEVICE_ID_NEOMAGIC_NM256XL_PLUS_AUDIO 0x8016 #define PCI_VENDOR_ID_ASP 0x10cd #define PCI_DEVICE_ID_ASP_ABP940 0x1200 @@ -1155,10 +1168,13 @@ #define PCI_DEVICE_ID_NVIDIA_NFORCE2_SMBUS 0x0064 #define PCI_DEVICE_ID_NVIDIA_NFORCE2_IDE 0x0065 #define PCI_DEVICE_ID_NVIDIA_NVENET_2 0x0066 +#define PCI_DEVICE_ID_NVIDIA_MCP2_MODEM 0x0069 #define PCI_DEVICE_ID_NVIDIA_MCP2_AUDIO 0x006a #define PCI_DEVICE_ID_NVIDIA_NFORCE2S_SMBUS 0x0084 #define PCI_DEVICE_ID_NVIDIA_NFORCE2S_IDE 0x0085 #define PCI_DEVICE_ID_NVIDIA_NVENET_4 0x0086 +#define PCI_DEVICE_ID_NVIDIA_MCP2S_MODEM 0x0089 +#define PCI_DEVICE_ID_NVIDIA_CK8_AUDIO 0x008a #define PCI_DEVICE_ID_NVIDIA_NVENET_5 0x008c #define PCI_DEVICE_ID_NVIDIA_NFORCE2S_SATA 0x008e #define PCI_DEVICE_ID_NVIDIA_ITNT2 0x00A0 @@ -1173,6 +1189,7 @@ #define PCI_DEVICE_ID_NVIDIA_NFORCE3_SMBUS 0x00d4 #define PCI_DEVICE_ID_NVIDIA_NFORCE3_IDE 0x00d5 #define PCI_DEVICE_ID_NVIDIA_NVENET_3 0x00d6 +#define PCI_DEVICE_ID_NVIDIA_MCP3_MODEM 0x00d9 #define PCI_DEVICE_ID_NVIDIA_MCP3_AUDIO 0x00da #define PCI_DEVICE_ID_NVIDIA_NVENET_7 0x00df #define PCI_DEVICE_ID_NVIDIA_NFORCE3S 0x00e1 @@ -1180,6 +1197,7 @@ #define PCI_DEVICE_ID_NVIDIA_NFORCE3S_SMBUS 0x00e4 #define PCI_DEVICE_ID_NVIDIA_NFORCE3S_IDE 0x00e5 #define PCI_DEVICE_ID_NVIDIA_NVENET_6 0x00e6 +#define PCI_DEVICE_ID_NVIDIA_CK8S_AUDIO 0x00ea #define PCI_DEVICE_ID_NVIDIA_NFORCE3S_SATA2 0x00ee #define PCI_DEVICE_ID_NVIDIA_GEFORCE_SDR 0x0100 #define PCI_DEVICE_ID_NVIDIA_GEFORCE_DDR 0x0101 @@ -1230,6 +1248,7 @@ #define PCI_DEVICE_ID_NVIDIA_MCP1_AUDIO 0x01b1 #define PCI_DEVICE_ID_NVIDIA_NFORCE_SMBUS 0x01b4 #define PCI_DEVICE_ID_NVIDIA_NFORCE_IDE 0x01bc +#define PCI_DEVICE_ID_NVIDIA_MCP1_MODEM 0x01c1 #define PCI_DEVICE_ID_NVIDIA_NVENET_1 0x01c3 #define PCI_DEVICE_ID_NVIDIA_NFORCE2 0x01e0 #define PCI_DEVICE_ID_NVIDIA_GEFORCE3 0x0200 @@ -1249,7 +1268,8 @@ #define PCI_DEVICE_ID_NVIDIA_NFORCE_MCP51_SATA 0x0266 #define PCI_DEVICE_ID_NVIDIA_NFORCE_MCP51_SATA2 0x0267 #define PCI_DEVICE_ID_NVIDIA_NFORCE_MCP55_IDE 0x036E -#define PCI_DEVICE_ID_NVIDIA_NFORCE_MCP55_SATA 0x036F +#define PCI_DEVICE_ID_NVIDIA_NFORCE_MCP55_SATA 0x037E +#define PCI_DEVICE_ID_NVIDIA_NFORCE_MCP55_SATA2 0x037F #define PCI_DEVICE_ID_NVIDIA_NVENET_12 0x0268 #define PCI_DEVICE_ID_NVIDIA_NVENET_13 0x0269 #define PCI_DEVICE_ID_NVIDIA_MCP51_AUDIO 0x026B @@ -1334,6 +1354,13 @@ #define PCI_DEVICE_ID_REALTEK_8169 0x8169 #define PCI_VENDOR_ID_XILINX 0x10ee +#define PCI_DEVICE_ID_RME_DIGI96 0x3fc0 +#define PCI_DEVICE_ID_RME_DIGI96_8 0x3fc1 +#define PCI_DEVICE_ID_RME_DIGI96_8_PRO 0x3fc2 +#define PCI_DEVICE_ID_RME_DIGI96_8_PAD_OR_PST 0x3fc3 +#define PCI_DEVICE_ID_XILINX_HAMMERFALL 0x3fc4 +#define PCI_DEVICE_ID_XILINX_HAMMERFALL_DSP 0x3fc5 +#define PCI_DEVICE_ID_XILINX_HAMMERFALL_DSP_MADI 0x3fc6 #define PCI_DEVICE_ID_TURBOPAM 0x4020 #define PCI_VENDOR_ID_TRUEVISION 0x10fa @@ -1809,6 +1836,14 @@ #define PCI_DEVICE_ID_ESS_ESS1968 0x1968 #define PCI_DEVICE_ID_ESS_AUDIOPCI 0x1969 #define PCI_DEVICE_ID_ESS_ESS1978 0x1978 +#define PCI_DEVICE_ID_ESS_ALLEGRO_1 0x1988 +#define PCI_DEVICE_ID_ESS_ALLEGRO 0x1989 +#define PCI_DEVICE_ID_ESS_CANYON3D_2LE 0x1990 +#define PCI_DEVICE_ID_ESS_CANYON3D_2 0x1992 +#define PCI_DEVICE_ID_ESS_MAESTRO3 0x1998 +#define PCI_DEVICE_ID_ESS_MAESTRO3_1 0x1999 +#define PCI_DEVICE_ID_ESS_MAESTRO3_HW 0x199a +#define PCI_DEVICE_ID_ESS_MAESTRO3_2 0x199b #define PCI_VENDOR_ID_SATSAGEM 0x1267 #define PCI_DEVICE_ID_SATSAGEM_NICCY 0x1016 @@ -1968,6 +2003,9 @@ #define PCI_DEVICE_ID_LMC_SSI 0x0005 #define PCI_DEVICE_ID_LMC_T1 0x0006 +#define PCI_VENDOR_ID_MARIAN 0x1382 +#define PCI_DEVICE_ID_MARIAN_PRODIF_PLUS 0x2048 + #define PCI_VENDOR_ID_NETGEAR 0x1385 #define PCI_DEVICE_ID_NETGEAR_GA620 0x620a #define PCI_DEVICE_ID_NETGEAR_GA622 0x622a @@ -2056,6 +2094,10 @@ #define PCI_VENDOR_ID_TIMEDIA 0x1409 #define PCI_DEVICE_ID_TIMEDIA_1889 0x7168 +#define PCI_VENDOR_ID_ICE 0x1412 +#define PCI_DEVICE_ID_ICE_1712 0x1712 +#define PCI_DEVICE_ID_VT1724 0x1724 + #define PCI_VENDOR_ID_OXSEMI 0x1415 #define PCI_DEVICE_ID_OXSEMI_12PCI840 0x8403 #define PCI_DEVICE_ID_OXSEMI_16PCI954 0x9501 @@ -2212,6 +2254,9 @@ #define PCI_VENDOR_ID_INFINICON 0x1820 +#define PCI_VENDOR_ID_SITECOM 0x182d +#define PCI_DEVICE_ID_SITECOM_DC105V2 0x3069 + #define PCI_VENDOR_ID_TOPSPIN 0x1867 #define PCI_VENDOR_ID_TDI 0x192E @@ -2536,6 +2581,7 @@ #define PCI_DEVICE_ID_INTEL_82443BX_1 0x7191 #define PCI_DEVICE_ID_INTEL_82443BX_2 0x7192 #define PCI_DEVICE_ID_INTEL_440MX 0x7195 +#define PCI_DEVICE_ID_INTEL_440MX_6 0x7196 #define PCI_DEVICE_ID_INTEL_82443MX_0 0x7198 #define PCI_DEVICE_ID_INTEL_82443MX_1 0x7199 #define PCI_DEVICE_ID_INTEL_82443MX_2 0x719a @@ -2642,6 +2688,11 @@ #define PCI_VENDOR_ID_TTTECH 0x0357 #define PCI_DEVICE_ID_TTTECH_MC322 0x000A +#define PCI_VENDOR_ID_XILINX_RME 0xea60 +#define PCI_DEVICE_ID_RME_DIGI32 0x9896 +#define PCI_DEVICE_ID_RME_DIGI32_PRO 0x9897 +#define PCI_DEVICE_ID_RME_DIGI32_8 0x9898 + #define PCI_VENDOR_ID_ARK 0xedd8 #define PCI_DEVICE_ID_ARK_STING 0xa091 #define PCI_DEVICE_ID_ARK_STINGARK 0xa099 diff --git a/include/linux/pktcdvd.h b/include/linux/pktcdvd.h index 4b32bce..2c177e4 100644 --- a/include/linux/pktcdvd.h +++ b/include/linux/pktcdvd.h @@ -166,6 +166,9 @@ struct packet_iosched /* * 32 buffers of 2048 bytes */ +#if (PAGE_SIZE % CD_FRAMESIZE) != 0 +#error "PAGE_SIZE must be a multiple of CD_FRAMESIZE" +#endif #define PACKET_MAX_SIZE 32 #define PAGES_PER_PACKET (PACKET_MAX_SIZE * CD_FRAMESIZE / PAGE_SIZE) #define PACKET_MAX_SECTORS (PACKET_MAX_SIZE * CD_FRAMESIZE >> 9) diff --git a/include/linux/reboot.h b/include/linux/reboot.h index 3b3266f..7ab2cdb 100644 --- a/include/linux/reboot.h +++ b/include/linux/reboot.h @@ -59,6 +59,10 @@ extern void machine_crash_shutdown(struct pt_regs *); * Architecture independent implemenations of sys_reboot commands. */ +extern void kernel_restart_prepare(char *cmd); +extern void kernel_halt_prepare(void); +extern void kernel_power_off_prepare(void); + extern void kernel_restart(char *cmd); extern void kernel_halt(void); extern void kernel_power_off(void); diff --git a/include/linux/sched.h b/include/linux/sched.h index 38c8654..49e617f 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h @@ -121,6 +121,17 @@ extern unsigned long nr_iowait(void); #define set_task_state(tsk, state_value) \ set_mb((tsk)->state, (state_value)) +/* + * set_current_state() includes a barrier so that the write of current->state + * is correctly serialised wrt the caller's subsequent test of whether to + * actually sleep: + * + * set_current_state(TASK_UNINTERRUPTIBLE); + * if (do_i_need_to_sleep()) + * schedule(); + * + * If the caller does not need such serialisation then use __set_current_state() + */ #define __set_current_state(state_value) \ do { current->state = (state_value); } while (0) #define set_current_state(state_value) \ diff --git a/include/linux/security.h b/include/linux/security.h index 55b02e1..0e43460 100644 --- a/include/linux/security.h +++ b/include/linux/security.h @@ -1907,6 +1907,11 @@ extern int register_security (struct security_operations *ops); extern int unregister_security (struct security_operations *ops); extern int mod_reg_security (const char *name, struct security_operations *ops); extern int mod_unreg_security (const char *name, struct security_operations *ops); +extern struct dentry *securityfs_create_file(const char *name, mode_t mode, + struct dentry *parent, void *data, + struct file_operations *fops); +extern struct dentry *securityfs_create_dir(const char *name, struct dentry *parent); +extern void securityfs_remove(struct dentry *dentry); #else /* CONFIG_SECURITY */ diff --git a/include/linux/syscalls.h b/include/linux/syscalls.h index 425f58c..a6f03e4 100644 --- a/include/linux/syscalls.h +++ b/include/linux/syscalls.h @@ -508,5 +508,7 @@ asmlinkage long sys_keyctl(int cmd, unsigned long arg2, unsigned long arg3, asmlinkage long sys_ioprio_set(int which, int who, int ioprio); asmlinkage long sys_ioprio_get(int which, int who); +asmlinkage long sys_set_mempolicy(int mode, unsigned long __user *nmask, + unsigned long maxnode); #endif diff --git a/include/linux/tfrc.h b/include/linux/tfrc.h new file mode 100644 index 0000000..7dab783 --- /dev/null +++ b/include/linux/tfrc.h @@ -0,0 +1,35 @@ +#ifndef _LINUX_TFRC_H_ +#define _LINUX_TFRC_H_ +/* + * include/linux/tfrc.h + * + * Copyright (c) 2005 The University of Waikato, Hamilton, New Zealand. + * Copyright (c) 2005 Ian McDonald <iam4@cs.waikato.ac.nz> + * Copyright (c) 2005 Arnaldo Carvalho de Melo <acme@conectiva.com.br> + * Copyright (c) 2003 Nils-Erik Mattsson, Joacim Haggmark, Magnus Erixzon + * + * This 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 <linux/types.h> + +struct tfrc_rx_info { + __u32 tfrcrx_x_recv; + __u32 tfrcrx_rtt; + __u32 tfrcrx_p; +}; + +struct tfrc_tx_info { + __u32 tfrctx_x; + __u32 tfrctx_x_recv; + __u32 tfrctx_x_calc; + __u32 tfrctx_rtt; + __u32 tfrctx_p; + __u32 tfrctx_rto; + __u32 tfrctx_ipi; +}; + +#endif /* _LINUX_TFRC_H_ */ diff --git a/include/linux/videodev2.h b/include/linux/videodev2.h index f623a33..89a0557 100644 --- a/include/linux/videodev2.h +++ b/include/linux/videodev2.h @@ -60,12 +60,17 @@ enum v4l2_field { (field) == V4L2_FIELD_SEQ_BT) enum v4l2_buf_type { - V4L2_BUF_TYPE_VIDEO_CAPTURE = 1, - V4L2_BUF_TYPE_VIDEO_OUTPUT = 2, - V4L2_BUF_TYPE_VIDEO_OVERLAY = 3, - V4L2_BUF_TYPE_VBI_CAPTURE = 4, - V4L2_BUF_TYPE_VBI_OUTPUT = 5, - V4L2_BUF_TYPE_PRIVATE = 0x80, + V4L2_BUF_TYPE_VIDEO_CAPTURE = 1, + V4L2_BUF_TYPE_VIDEO_OUTPUT = 2, + V4L2_BUF_TYPE_VIDEO_OVERLAY = 3, + V4L2_BUF_TYPE_VBI_CAPTURE = 4, + V4L2_BUF_TYPE_VBI_OUTPUT = 5, +#if 1 + /* Experimental Sliced VBI */ + V4L2_BUF_TYPE_SLICED_VBI_CAPTURE = 6, + V4L2_BUF_TYPE_SLICED_VBI_OUTPUT = 7, +#endif + V4L2_BUF_TYPE_PRIVATE = 0x80, }; enum v4l2_ctrl_type { @@ -149,20 +154,24 @@ struct v4l2_capability }; /* Values for 'capabilities' field */ -#define V4L2_CAP_VIDEO_CAPTURE 0x00000001 /* Is a video capture device */ -#define V4L2_CAP_VIDEO_OUTPUT 0x00000002 /* Is a video output device */ -#define V4L2_CAP_VIDEO_OVERLAY 0x00000004 /* Can do video overlay */ -#define V4L2_CAP_VBI_CAPTURE 0x00000010 /* Is a VBI capture device */ -#define V4L2_CAP_VBI_OUTPUT 0x00000020 /* Is a VBI output device */ -#define V4L2_CAP_RDS_CAPTURE 0x00000100 /* RDS data capture */ +#define V4L2_CAP_VIDEO_CAPTURE 0x00000001 /* Is a video capture device */ +#define V4L2_CAP_VIDEO_OUTPUT 0x00000002 /* Is a video output device */ +#define V4L2_CAP_VIDEO_OVERLAY 0x00000004 /* Can do video overlay */ +#define V4L2_CAP_VBI_CAPTURE 0x00000010 /* Is a raw VBI capture device */ +#define V4L2_CAP_VBI_OUTPUT 0x00000020 /* Is a raw VBI output device */ +#if 1 +#define V4L2_CAP_SLICED_VBI_CAPTURE 0x00000040 /* Is a sliced VBI capture device */ +#define V4L2_CAP_SLICED_VBI_OUTPUT 0x00000080 /* Is a sliced VBI output device */ +#endif +#define V4L2_CAP_RDS_CAPTURE 0x00000100 /* RDS data capture */ -#define V4L2_CAP_TUNER 0x00010000 /* has a tuner */ -#define V4L2_CAP_AUDIO 0x00020000 /* has audio support */ -#define V4L2_CAP_RADIO 0x00040000 /* is a radio device */ +#define V4L2_CAP_TUNER 0x00010000 /* has a tuner */ +#define V4L2_CAP_AUDIO 0x00020000 /* has audio support */ +#define V4L2_CAP_RADIO 0x00040000 /* is a radio device */ -#define V4L2_CAP_READWRITE 0x01000000 /* read/write systemcalls */ -#define V4L2_CAP_ASYNCIO 0x02000000 /* async I/O */ -#define V4L2_CAP_STREAMING 0x04000000 /* streaming I/O ioctls */ +#define V4L2_CAP_READWRITE 0x01000000 /* read/write systemcalls */ +#define V4L2_CAP_ASYNCIO 0x02000000 /* async I/O */ +#define V4L2_CAP_STREAMING 0x04000000 /* streaming I/O ioctls */ /* * V I D E O I M A G E F O R M A T @@ -809,6 +818,8 @@ struct v4l2_audioout * Data services API by Michael Schimek */ +/* Raw VBI */ + struct v4l2_vbi_format { __u32 sampling_rate; /* in 1 Hz */ @@ -825,6 +836,54 @@ struct v4l2_vbi_format #define V4L2_VBI_UNSYNC (1<< 0) #define V4L2_VBI_INTERLACED (1<< 1) +#if 1 +/* Sliced VBI + * + * This implements is a proposal V4L2 API to allow SLICED VBI + * required for some hardware encoders. It should change without + * notice in the definitive implementation. + */ + +struct v4l2_sliced_vbi_format +{ + __u16 service_set; + /* service_lines[0][...] specifies lines 0-23 (1-23 used) of the first field + service_lines[1][...] specifies lines 0-23 (1-23 used) of the second field + (equals frame lines 313-336 for 625 line video + standards, 263-286 for 525 line standards) */ + __u16 service_lines[2][24]; + __u32 io_size; + __u32 reserved[2]; /* must be zero */ +}; + +#define V4L2_SLICED_TELETEXT_B (0x0001) +#define V4L2_SLICED_VPS (0x0400) +#define V4L2_SLICED_CAPTION_525 (0x1000) +#define V4L2_SLICED_WSS_625 (0x4000) + +#define V4L2_SLICED_VBI_525 (V4L2_SLICED_CAPTION_525) +#define V4L2_SLICED_VBI_625 (V4L2_SLICED_TELETEXT_B | V4L2_SLICED_VPS | V4L2_SLICED_WSS_625) + +struct v4l2_sliced_vbi_cap +{ + __u16 service_set; + /* service_lines[0][...] specifies lines 0-23 (1-23 used) of the first field + service_lines[1][...] specifies lines 0-23 (1-23 used) of the second field + (equals frame lines 313-336 for 625 line video + standards, 263-286 for 525 line standards) */ + __u16 service_lines[2][24]; + __u32 reserved[4]; /* must be 0 */ +}; + +struct v4l2_sliced_vbi_data +{ + __u32 id; + __u32 field; /* 0: first field, 1: second field */ + __u32 line; /* 1-23 */ + __u32 reserved; /* must be 0 */ + __u8 data[48]; +}; +#endif /* * A G G R E G A T E S T R U C T U R E S @@ -837,10 +896,13 @@ struct v4l2_format enum v4l2_buf_type type; union { - struct v4l2_pix_format pix; // V4L2_BUF_TYPE_VIDEO_CAPTURE - struct v4l2_window win; // V4L2_BUF_TYPE_VIDEO_OVERLAY - struct v4l2_vbi_format vbi; // V4L2_BUF_TYPE_VBI_CAPTURE - __u8 raw_data[200]; // user-defined + struct v4l2_pix_format pix; // V4L2_BUF_TYPE_VIDEO_CAPTURE + struct v4l2_window win; // V4L2_BUF_TYPE_VIDEO_OVERLAY + struct v4l2_vbi_format vbi; // V4L2_BUF_TYPE_VBI_CAPTURE +#if 1 + struct v4l2_sliced_vbi_format sliced; // V4L2_BUF_TYPE_SLICED_VBI_CAPTURE +#endif + __u8 raw_data[200]; // user-defined } fmt; }; @@ -916,6 +978,9 @@ struct v4l2_streamparm #define VIDIOC_ENUMAUDOUT _IOWR ('V', 66, struct v4l2_audioout) #define VIDIOC_G_PRIORITY _IOR ('V', 67, enum v4l2_priority) #define VIDIOC_S_PRIORITY _IOW ('V', 68, enum v4l2_priority) +#if 1 +#define VIDIOC_G_SLICED_VBI_CAP _IOR ('V', 69, struct v4l2_sliced_vbi_cap) +#endif /* for compatibility, will go away some day */ #define VIDIOC_OVERLAY_OLD _IOWR ('V', 14, int) diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h index 371e7d3..fa2d12b 100644 --- a/include/net/bluetooth/hci.h +++ b/include/net/bluetooth/hci.h @@ -463,6 +463,17 @@ struct inquiry_info_with_rssi_and_pscan_mode { __s8 rssi; } __attribute__ ((packed)); +#define HCI_EV_EXTENDED_INQUIRY_RESULT 0x2F +struct extended_inquiry_info { + bdaddr_t bdaddr; + __u8 pscan_rep_mode; + __u8 pscan_period_mode; + __u8 dev_class[3]; + __u16 clock_offset; + __s8 rssi; + __u8 data[240]; +} __attribute__ ((packed)); + #define HCI_EV_CONN_COMPLETE 0x03 struct hci_ev_conn_complete { __u8 status; diff --git a/include/net/ip_vs.h b/include/net/ip_vs.h index e426641..06b4235 100644 --- a/include/net/ip_vs.h +++ b/include/net/ip_vs.h @@ -84,6 +84,7 @@ #define IP_VS_CONN_F_IN_SEQ 0x0400 /* must do input seq adjust */ #define IP_VS_CONN_F_SEQ_MASK 0x0600 /* in/out sequence mask */ #define IP_VS_CONN_F_NO_CPORT 0x0800 /* no client port set yet */ +#define IP_VS_CONN_F_TEMPLATE 0x1000 /* template, not connection */ /* Move it to better place one day, for now keep it unique */ #define NFC_IPVS_PROPERTY 0x10000 @@ -739,6 +740,8 @@ enum { extern struct ip_vs_conn *ip_vs_conn_in_get (int protocol, __u32 s_addr, __u16 s_port, __u32 d_addr, __u16 d_port); +extern struct ip_vs_conn *ip_vs_ct_in_get +(int protocol, __u32 s_addr, __u16 s_port, __u32 d_addr, __u16 d_port); extern struct ip_vs_conn *ip_vs_conn_out_get (int protocol, __u32 s_addr, __u16 s_port, __u32 d_addr, __u16 d_port); diff --git a/include/rdma/ib_mad.h b/include/rdma/ib_mad.h index 53184a3..0e293fe 100644 --- a/include/rdma/ib_mad.h +++ b/include/rdma/ib_mad.h @@ -108,6 +108,13 @@ #define IB_QP1_QKEY 0x80010000 #define IB_QP_SET_QKEY 0x80000000 +enum { + IB_MGMT_MAD_DATA = 232, + IB_MGMT_RMPP_DATA = 220, + IB_MGMT_VENDOR_DATA = 216, + IB_MGMT_SA_DATA = 200 +}; + struct ib_mad_hdr { u8 base_version; u8 mgmt_class; @@ -149,20 +156,20 @@ struct ib_sa_hdr { struct ib_mad { struct ib_mad_hdr mad_hdr; - u8 data[232]; + u8 data[IB_MGMT_MAD_DATA]; }; struct ib_rmpp_mad { struct ib_mad_hdr mad_hdr; struct ib_rmpp_hdr rmpp_hdr; - u8 data[220]; + u8 data[IB_MGMT_RMPP_DATA]; }; struct ib_sa_mad { struct ib_mad_hdr mad_hdr; struct ib_rmpp_hdr rmpp_hdr; struct ib_sa_hdr sa_hdr; - u8 data[200]; + u8 data[IB_MGMT_SA_DATA]; } __attribute__ ((packed)); struct ib_vendor_mad { @@ -170,7 +177,7 @@ struct ib_vendor_mad { struct ib_rmpp_hdr rmpp_hdr; u8 reserved; u8 oui[3]; - u8 data[216]; + u8 data[IB_MGMT_VENDOR_DATA]; }; struct ib_class_port_info diff --git a/include/scsi/scsi_host.h b/include/scsi/scsi_host.h index 916144b..69313ba 100644 --- a/include/scsi/scsi_host.h +++ b/include/scsi/scsi_host.h @@ -439,6 +439,8 @@ enum scsi_host_state { SHOST_CANCEL, SHOST_DEL, SHOST_RECOVERY, + SHOST_CANCEL_RECOVERY, + SHOST_DEL_RECOVERY, }; struct Scsi_Host { @@ -465,8 +467,6 @@ struct Scsi_Host { struct list_head eh_cmd_q; struct task_struct * ehandler; /* Error recovery thread. */ - struct semaphore * eh_wait; /* The error recovery thread waits - on this. */ struct semaphore * eh_action; /* Wait for specific actions on the host. */ unsigned int eh_active:1; /* Indicates the eh thread is awake and active if @@ -621,6 +621,13 @@ static inline struct Scsi_Host *dev_to_shost(struct device *dev) return container_of(dev, struct Scsi_Host, shost_gendev); } +static inline int scsi_host_in_recovery(struct Scsi_Host *shost) +{ + return shost->shost_state == SHOST_RECOVERY || + shost->shost_state == SHOST_CANCEL_RECOVERY || + shost->shost_state == SHOST_DEL_RECOVERY; +} + extern int scsi_queue_work(struct Scsi_Host *, struct work_struct *); extern void scsi_flush_work(struct Scsi_Host *); diff --git a/include/scsi/scsi_transport_fc.h b/include/scsi/scsi_transport_fc.h index 115db05..b0d4454 100644 --- a/include/scsi/scsi_transport_fc.h +++ b/include/scsi/scsi_transport_fc.h @@ -103,8 +103,8 @@ enum fc_port_state { incapable of reporting */ #define FC_PORTSPEED_1GBIT 1 #define FC_PORTSPEED_2GBIT 2 -#define FC_PORTSPEED_10GBIT 4 -#define FC_PORTSPEED_4GBIT 8 +#define FC_PORTSPEED_4GBIT 4 +#define FC_PORTSPEED_10GBIT 8 #define FC_PORTSPEED_NOT_NEGOTIATED (1 << 15) /* Speed not established */ /* diff --git a/include/sound/core.h b/include/sound/core.h index 3dc41fd..26160ad 100644 --- a/include/sound/core.h +++ b/include/sound/core.h @@ -168,6 +168,9 @@ struct _snd_card { wait_queue_head_t shutdown_sleep; struct work_struct free_workq; /* for free in workqueue */ struct device *dev; +#ifdef CONFIG_SND_GENERIC_DRIVER + struct snd_generic_device *generic_dev; +#endif #ifdef CONFIG_PM int (*pm_suspend)(snd_card_t *card, pm_message_t state); @@ -176,9 +179,6 @@ struct _snd_card { unsigned int power_state; /* power state */ struct semaphore power_lock; /* power lock */ wait_queue_head_t power_sleep; -#ifdef CONFIG_SND_GENERIC_PM - struct snd_generic_device *pm_dev; /* for ISA */ -#endif #endif #if defined(CONFIG_SND_MIXER_OSS) || defined(CONFIG_SND_MIXER_OSS_MODULE) @@ -348,6 +348,8 @@ int snd_card_file_remove(snd_card_t *card, struct file *file); #ifndef snd_card_set_dev #define snd_card_set_dev(card,devptr) ((card)->dev = (devptr)) #endif +/* register a generic device (for ISA, etc) */ +int snd_card_set_generic_dev(snd_card_t *card); /* device.c */ diff --git a/include/sound/cs46xx.h b/include/sound/cs46xx.h index 9b94510..b0c0e19 100644 --- a/include/sound/cs46xx.h +++ b/include/sound/cs46xx.h @@ -29,19 +29,6 @@ #include "ac97_codec.h" #include "cs46xx_dsp_spos.h" -#ifndef PCI_VENDOR_ID_CIRRUS -#define PCI_VENDOR_ID_CIRRUS 0x1013 -#endif -#ifndef PCI_DEVICE_ID_CIRRUS_4610 -#define PCI_DEVICE_ID_CIRRUS_4610 0x6001 -#endif -#ifndef PCI_DEVICE_ID_CIRRUS_4612 -#define PCI_DEVICE_ID_CIRRUS_4612 0x6003 -#endif -#ifndef PCI_DEVICE_ID_CIRRUS_4615 -#define PCI_DEVICE_ID_CIRRUS_4615 0x6004 -#endif - /* * Direct registers */ @@ -1715,7 +1702,6 @@ struct _snd_cs46xx { void (*active_ctrl)(cs46xx_t *, int); void (*mixer_init)(cs46xx_t *); - struct pci_dev *acpi_dev; int acpi_port; snd_kcontrol_t *eapd_switch; /* for amplifier hack */ int accept_valid; /* accept mmap valid (for OSS) */ diff --git a/include/sound/emu10k1.h b/include/sound/emu10k1.h index 4e3993d..67bf3f1 100644 --- a/include/sound/emu10k1.h +++ b/include/sound/emu10k1.h @@ -35,13 +35,6 @@ #include <linux/interrupt.h> #include <asm/io.h> -#ifndef PCI_VENDOR_ID_CREATIVE -#define PCI_VENDOR_ID_CREATIVE 0x1102 -#endif -#ifndef PCI_DEVICE_ID_CREATIVE_EMU10K1 -#define PCI_DEVICE_ID_CREATIVE_EMU10K1 0x0002 -#endif - /* ------------------- DEFINES -------------------- */ #define EMUPAGESIZE 4096 diff --git a/include/sound/pcm.h b/include/sound/pcm.h index d6361dab..2b23a59 100644 --- a/include/sound/pcm.h +++ b/include/sound/pcm.h @@ -903,13 +903,16 @@ int snd_pcm_format_unsigned(snd_pcm_format_t format); int snd_pcm_format_linear(snd_pcm_format_t format); int snd_pcm_format_little_endian(snd_pcm_format_t format); int snd_pcm_format_big_endian(snd_pcm_format_t format); -/* +#if 0 /* just for DocBook */ +/** * snd_pcm_format_cpu_endian - Check the PCM format is CPU-endian * @format: the format to check * * Returns 1 if the given PCM format is CPU-endian, 0 if * opposite, or a negative error code if endian not specified. */ +int snd_pcm_format_cpu_endian(snd_pcm_format_t format); +#endif /* DocBook */ #ifdef SNDRV_LITTLE_ENDIAN #define snd_pcm_format_cpu_endian(format) snd_pcm_format_little_endian(format) #else diff --git a/include/sound/pcm_oss.h b/include/sound/pcm_oss.h index 5187285..0b67c9d 100644 --- a/include/sound/pcm_oss.h +++ b/include/sound/pcm_oss.h @@ -32,7 +32,8 @@ struct _snd_pcm_oss_setup { block:1, nonblock:1, partialfrag:1, - nosilence:1; + nosilence:1, + buggyptr:1; unsigned int periods; unsigned int period_size; snd_pcm_oss_setup_t *next; diff --git a/include/sound/trident.h b/include/sound/trident.h index f5254ec..a408d39 100644 --- a/include/sound/trident.h +++ b/include/sound/trident.h @@ -33,23 +33,6 @@ //#include "ainstr_gf1.h" #include "ainstr_simple.h" -#ifndef PCI_VENDOR_ID_TRIDENT -#define PCI_VENDOR_ID_TRIDENT 0x1023 -#endif -#ifndef PCI_DEVICE_ID_TRIDENT_4DWAVE_DX -#define PCI_DEVICE_ID_TRIDENT_4DWAVE_DX 0x2000 -#endif -#ifndef PCI_DEVICE_ID_TRIDENT_4DWAVE_NX -#define PCI_DEVICE_ID_TRIDENT_4DWAVE_NX 0x2001 -#endif - -#ifndef PCI_VENDOR_ID_SI -#define PCI_VENDOR_ID_SI 0x1039 -#endif -#ifndef PCI_DEVICE_ID_SI_7018 -#define PCI_DEVICE_ID_SI_7018 0x7018 -#endif - #define TRIDENT_DEVICE_ID_DX ((PCI_VENDOR_ID_TRIDENT<<16)|PCI_DEVICE_ID_TRIDENT_4DWAVE_DX) #define TRIDENT_DEVICE_ID_NX ((PCI_VENDOR_ID_TRIDENT<<16)|PCI_DEVICE_ID_TRIDENT_4DWAVE_NX) #define TRIDENT_DEVICE_ID_SI7018 ((PCI_VENDOR_ID_SI<<16)|PCI_DEVICE_ID_SI_7018) diff --git a/include/sound/version.h b/include/sound/version.h index 8d19bfa..ee32af2 100644 --- a/include/sound/version.h +++ b/include/sound/version.h @@ -1,3 +1,3 @@ /* include/version.h. Generated by configure. */ #define CONFIG_SND_VERSION "1.0.10rc1" -#define CONFIG_SND_DATE " (Tue Aug 30 05:31:08 2005 UTC)" +#define CONFIG_SND_DATE " (Mon Sep 12 08:13:09 2005 UTC)" diff --git a/include/sound/ymfpci.h b/include/sound/ymfpci.h index 9a3c1e6..c3bccbfd 100644 --- a/include/sound/ymfpci.h +++ b/include/sound/ymfpci.h @@ -28,28 +28,6 @@ #include "timer.h" #include <linux/gameport.h> -#ifndef PCI_VENDOR_ID_YAMAHA -#define PCI_VENDOR_ID_YAMAHA 0x1073 -#endif -#ifndef PCI_DEVICE_ID_YAMAHA_724 -#define PCI_DEVICE_ID_YAMAHA_724 0x0004 -#endif -#ifndef PCI_DEVICE_ID_YAMAHA_724F -#define PCI_DEVICE_ID_YAMAHA_724F 0x000d -#endif -#ifndef PCI_DEVICE_ID_YAMAHA_740 -#define PCI_DEVICE_ID_YAMAHA_740 0x000a -#endif -#ifndef PCI_DEVICE_ID_YAMAHA_740C -#define PCI_DEVICE_ID_YAMAHA_740C 0x000c -#endif -#ifndef PCI_DEVICE_ID_YAMAHA_744 -#define PCI_DEVICE_ID_YAMAHA_744 0x0010 -#endif -#ifndef PCI_DEVICE_ID_YAMAHA_754 -#define PCI_DEVICE_ID_YAMAHA_754 0x0012 -#endif - /* * Direct registers */ diff --git a/include/video/pm3fb.h b/include/video/pm3fb.h index 8d3cef5..6f4ea80 100644 --- a/include/video/pm3fb.h +++ b/include/video/pm3fb.h @@ -1142,9 +1142,6 @@ /* do we want accelerated console */ #define PM3FB_USE_ACCEL 1 -/* useful ? */ -#define CHAR_IS_NUM(a) ((((a) >= '0') && ((a) <= '9')) ? 1 : 0) - /* for driver debugging ONLY */ /* 0 = assert only, 1 = error, 2 = info, 3+ = verbose */ /* define PM3FB_MASTER_DEBUG 1 */ diff --git a/include/video/w100fb.h b/include/video/w100fb.h index e6da2d7..677d403 100644 --- a/include/video/w100fb.h +++ b/include/video/w100fb.h @@ -19,6 +19,7 @@ struct w100fb_par; unsigned long w100fb_gpio_read(int port); void w100fb_gpio_write(int port, unsigned long value); +unsigned long w100fb_get_hsynclen(struct device *dev); /* LCD Specific Routines and Config */ struct w100_tg_info { diff --git a/init/initramfs.c b/init/initramfs.c index 02c5ce6..0c5d9a3 100644 --- a/init/initramfs.c +++ b/init/initramfs.c @@ -466,6 +466,14 @@ static char * __init unpack_to_rootfs(char *buf, unsigned len, int check_only) extern char __initramfs_start[], __initramfs_end[]; #ifdef CONFIG_BLK_DEV_INITRD #include <linux/initrd.h> + +static void __init free_initrd(void) +{ + free_initrd_mem(initrd_start, initrd_end); + initrd_start = 0; + initrd_end = 0; +} + #endif void __init populate_rootfs(void) @@ -484,7 +492,7 @@ void __init populate_rootfs(void) printk(" it is\n"); unpack_to_rootfs((char *)initrd_start, initrd_end - initrd_start, 0); - free_initrd_mem(initrd_start, initrd_end); + free_initrd(); return; } printk("it isn't (%s); looks like an initrd\n", err); @@ -493,7 +501,7 @@ void __init populate_rootfs(void) sys_write(fd, (char *)initrd_start, initrd_end - initrd_start); sys_close(fd); - free_initrd_mem(initrd_start, initrd_end); + free_initrd(); } } #endif diff --git a/kernel/audit.c b/kernel/audit.c index 7f06997..83096b6 100644 --- a/kernel/audit.c +++ b/kernel/audit.c @@ -79,6 +79,8 @@ static int audit_rate_limit; /* Number of outstanding audit_buffers allowed. */ static int audit_backlog_limit = 64; +static int audit_backlog_wait_time = 60 * HZ; +static int audit_backlog_wait_overflow = 0; /* The identity of the user shutting down the audit system. */ uid_t audit_sig_uid = -1; @@ -106,18 +108,12 @@ static LIST_HEAD(audit_freelist); static struct sk_buff_head audit_skb_queue; static struct task_struct *kauditd_task; static DECLARE_WAIT_QUEUE_HEAD(kauditd_wait); - -/* There are three lists of rules -- one to search at task creation - * time, one to search at syscall entry time, and another to search at - * syscall exit time. */ -static LIST_HEAD(audit_tsklist); -static LIST_HEAD(audit_entlist); -static LIST_HEAD(audit_extlist); +static DECLARE_WAIT_QUEUE_HEAD(audit_backlog_wait); /* The netlink socket is only to be read by 1 CPU, which lets us assume * that list additions and deletions never happen simultaneously in * auditsc.c */ -static DECLARE_MUTEX(audit_netlink_sem); +DECLARE_MUTEX(audit_netlink_sem); /* AUDIT_BUFSIZ is the size of the temporary buffer used for formatting * audit records. Since printk uses a 1024 byte buffer, this buffer @@ -137,6 +133,7 @@ struct audit_buffer { struct list_head list; struct sk_buff *skb; /* formatted skb ready to send */ struct audit_context *ctx; /* NULL or associated context */ + int gfp_mask; }; static void audit_set_pid(struct audit_buffer *ab, pid_t pid) @@ -145,11 +142,6 @@ static void audit_set_pid(struct audit_buffer *ab, pid_t pid) nlh->nlmsg_pid = pid; } -struct audit_entry { - struct list_head list; - struct audit_rule rule; -}; - static void audit_panic(const char *message) { switch (audit_failure) @@ -233,7 +225,7 @@ static int audit_set_rate_limit(int limit, uid_t loginuid) { int old = audit_rate_limit; audit_rate_limit = limit; - audit_log(NULL, AUDIT_CONFIG_CHANGE, + audit_log(NULL, GFP_KERNEL, AUDIT_CONFIG_CHANGE, "audit_rate_limit=%d old=%d by auid=%u", audit_rate_limit, old, loginuid); return old; @@ -243,7 +235,7 @@ static int audit_set_backlog_limit(int limit, uid_t loginuid) { int old = audit_backlog_limit; audit_backlog_limit = limit; - audit_log(NULL, AUDIT_CONFIG_CHANGE, + audit_log(NULL, GFP_KERNEL, AUDIT_CONFIG_CHANGE, "audit_backlog_limit=%d old=%d by auid=%u", audit_backlog_limit, old, loginuid); return old; @@ -255,7 +247,7 @@ static int audit_set_enabled(int state, uid_t loginuid) if (state != 0 && state != 1) return -EINVAL; audit_enabled = state; - audit_log(NULL, AUDIT_CONFIG_CHANGE, + audit_log(NULL, GFP_KERNEL, AUDIT_CONFIG_CHANGE, "audit_enabled=%d old=%d by auid=%u", audit_enabled, old, loginuid); return old; @@ -269,7 +261,7 @@ static int audit_set_failure(int state, uid_t loginuid) && state != AUDIT_FAIL_PANIC) return -EINVAL; audit_failure = state; - audit_log(NULL, AUDIT_CONFIG_CHANGE, + audit_log(NULL, GFP_KERNEL, AUDIT_CONFIG_CHANGE, "audit_failure=%d old=%d by auid=%u", audit_failure, old, loginuid); return old; @@ -281,6 +273,7 @@ int kauditd_thread(void *dummy) while (1) { skb = skb_dequeue(&audit_skb_queue); + wake_up(&audit_backlog_wait); if (skb) { if (audit_pid) { int err = netlink_unicast(audit_sock, skb, audit_pid, 0); @@ -290,7 +283,7 @@ int kauditd_thread(void *dummy) audit_pid = 0; } } else { - printk(KERN_ERR "%s\n", skb->data + NLMSG_SPACE(0)); + printk(KERN_NOTICE "%s\n", skb->data + NLMSG_SPACE(0)); kfree_skb(skb); } } else { @@ -423,7 +416,7 @@ static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh) if (status_get->mask & AUDIT_STATUS_PID) { int old = audit_pid; audit_pid = status_get->pid; - audit_log(NULL, AUDIT_CONFIG_CHANGE, + audit_log(NULL, GFP_KERNEL, AUDIT_CONFIG_CHANGE, "audit_pid=%d old=%d by auid=%u", audit_pid, old, loginuid); } @@ -435,15 +428,21 @@ static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh) break; case AUDIT_USER: case AUDIT_FIRST_USER_MSG...AUDIT_LAST_USER_MSG: - ab = audit_log_start(NULL, msg_type); - if (!ab) - break; /* audit_panic has been called */ - audit_log_format(ab, - "user pid=%d uid=%u auid=%u" - " msg='%.1024s'", - pid, uid, loginuid, (char *)data); - audit_set_pid(ab, pid); - audit_log_end(ab); + if (!audit_enabled && msg_type != AUDIT_USER_AVC) + return 0; + + err = audit_filter_user(&NETLINK_CB(skb), msg_type); + if (err == 1) { + err = 0; + ab = audit_log_start(NULL, GFP_KERNEL, msg_type); + if (ab) { + audit_log_format(ab, + "user pid=%d uid=%u auid=%u msg='%.1024s'", + pid, uid, loginuid, (char *)data); + audit_set_pid(ab, pid); + audit_log_end(ab); + } + } break; case AUDIT_ADD: case AUDIT_DEL: @@ -523,7 +522,7 @@ static int __init audit_init(void) skb_queue_head_init(&audit_skb_queue); audit_initialized = 1; audit_enabled = audit_default; - audit_log(NULL, AUDIT_KERNEL, "initialized"); + audit_log(NULL, GFP_KERNEL, AUDIT_KERNEL, "initialized"); return 0; } __initcall(audit_init); @@ -561,7 +560,7 @@ static void audit_buffer_free(struct audit_buffer *ab) } static struct audit_buffer * audit_buffer_alloc(struct audit_context *ctx, - int gfp_mask, int type) + unsigned int __nocast gfp_mask, int type) { unsigned long flags; struct audit_buffer *ab = NULL; @@ -587,6 +586,7 @@ static struct audit_buffer * audit_buffer_alloc(struct audit_context *ctx, goto err; ab->ctx = ctx; + ab->gfp_mask = gfp_mask; nlh = (struct nlmsghdr *)skb_put(ab->skb, NLMSG_SPACE(0)); nlh->nlmsg_type = type; nlh->nlmsg_flags = 0; @@ -606,26 +606,27 @@ err: * (timestamp,serial) tuple is unique for each syscall and is live from * syscall entry to syscall exit. * - * Atomic values are only guaranteed to be 24-bit, so we count down. - * * NOTE: Another possibility is to store the formatted records off the * audit context (for those records that have a context), and emit them * all at syscall exit. However, this could delay the reporting of * significant errors until syscall exit (or never, if the system * halts). */ + unsigned int audit_serial(void) { - static atomic_t serial = ATOMIC_INIT(0xffffff); - unsigned int a, b; + static spinlock_t serial_lock = SPIN_LOCK_UNLOCKED; + static unsigned int serial = 0; + + unsigned long flags; + unsigned int ret; + spin_lock_irqsave(&serial_lock, flags); do { - a = atomic_read(&serial); - if (atomic_dec_and_test(&serial)) - atomic_set(&serial, 0xffffff); - b = atomic_read(&serial); - } while (b != a - 1); + ret = ++serial; + } while (unlikely(!ret)); + spin_unlock_irqrestore(&serial_lock, flags); - return 0xffffff - b; + return ret; } static inline void audit_get_stamp(struct audit_context *ctx, @@ -645,17 +646,43 @@ static inline void audit_get_stamp(struct audit_context *ctx, * syscall, then the syscall is marked as auditable and an audit record * will be written at syscall exit. If there is no associated task, tsk * should be NULL. */ -struct audit_buffer *audit_log_start(struct audit_context *ctx, int type) + +struct audit_buffer *audit_log_start(struct audit_context *ctx, int gfp_mask, + int type) { struct audit_buffer *ab = NULL; struct timespec t; unsigned int serial; + int reserve; + unsigned long timeout_start = jiffies; if (!audit_initialized) return NULL; - if (audit_backlog_limit - && skb_queue_len(&audit_skb_queue) > audit_backlog_limit) { + if (gfp_mask & __GFP_WAIT) + reserve = 0; + else + reserve = 5; /* Allow atomic callers to go up to five + entries over the normal backlog limit */ + + while (audit_backlog_limit + && skb_queue_len(&audit_skb_queue) > audit_backlog_limit + reserve) { + if (gfp_mask & __GFP_WAIT && audit_backlog_wait_time + && time_before(jiffies, timeout_start + audit_backlog_wait_time)) { + + /* Wait for auditd to drain the queue a little */ + DECLARE_WAITQUEUE(wait, current); + set_current_state(TASK_INTERRUPTIBLE); + add_wait_queue(&audit_backlog_wait, &wait); + + if (audit_backlog_limit && + skb_queue_len(&audit_skb_queue) > audit_backlog_limit) + schedule_timeout(timeout_start + audit_backlog_wait_time - jiffies); + + __set_current_state(TASK_RUNNING); + remove_wait_queue(&audit_backlog_wait, &wait); + continue; + } if (audit_rate_check()) printk(KERN_WARNING "audit: audit_backlog=%d > " @@ -663,10 +690,12 @@ struct audit_buffer *audit_log_start(struct audit_context *ctx, int type) skb_queue_len(&audit_skb_queue), audit_backlog_limit); audit_log_lost("backlog limit exceeded"); + audit_backlog_wait_time = audit_backlog_wait_overflow; + wake_up(&audit_backlog_wait); return NULL; } - ab = audit_buffer_alloc(ctx, GFP_ATOMIC, type); + ab = audit_buffer_alloc(ctx, gfp_mask, type); if (!ab) { audit_log_lost("out of memory in audit_log_start"); return NULL; @@ -690,7 +719,7 @@ static inline int audit_expand(struct audit_buffer *ab, int extra) { struct sk_buff *skb = ab->skb; int ret = pskb_expand_head(skb, skb_headroom(skb), extra, - GFP_ATOMIC); + ab->gfp_mask); if (ret < 0) { audit_log_lost("out of memory in audit_expand"); return 0; @@ -809,7 +838,7 @@ void audit_log_d_path(struct audit_buffer *ab, const char *prefix, audit_log_format(ab, " %s", prefix); /* We will allow 11 spaces for ' (deleted)' to be appended */ - path = kmalloc(PATH_MAX+11, GFP_KERNEL); + path = kmalloc(PATH_MAX+11, ab->gfp_mask); if (!path) { audit_log_format(ab, "<no memory>"); return; @@ -841,7 +870,7 @@ void audit_log_end(struct audit_buffer *ab) ab->skb = NULL; wake_up_interruptible(&kauditd_wait); } else { - printk("%s\n", ab->skb->data + NLMSG_SPACE(0)); + printk(KERN_NOTICE "%s\n", ab->skb->data + NLMSG_SPACE(0)); } } audit_buffer_free(ab); @@ -850,12 +879,13 @@ void audit_log_end(struct audit_buffer *ab) /* Log an audit record. This is a convenience function that calls * audit_log_start, audit_log_vformat, and audit_log_end. It may be * called in any context. */ -void audit_log(struct audit_context *ctx, int type, const char *fmt, ...) +void audit_log(struct audit_context *ctx, int gfp_mask, int type, + const char *fmt, ...) { struct audit_buffer *ab; va_list args; - ab = audit_log_start(ctx, type); + ab = audit_log_start(ctx, gfp_mask, type); if (ab) { va_start(args, fmt); audit_log_vformat(ab, fmt, args); diff --git a/kernel/auditsc.c b/kernel/auditsc.c index e75f84e..88696f6 100644 --- a/kernel/auditsc.c +++ b/kernel/auditsc.c @@ -39,6 +39,9 @@ #include <linux/audit.h> #include <linux/personality.h> #include <linux/time.h> +#include <linux/kthread.h> +#include <linux/netlink.h> +#include <linux/compiler.h> #include <asm/unistd.h> /* 0 = no checking @@ -95,6 +98,7 @@ struct audit_names { uid_t uid; gid_t gid; dev_t rdev; + unsigned flags; }; struct audit_aux_data { @@ -167,9 +171,16 @@ struct audit_context { /* There are three lists of rules -- one to search at task creation * time, one to search at syscall entry time, and another to search at * syscall exit time. */ -static LIST_HEAD(audit_tsklist); -static LIST_HEAD(audit_entlist); -static LIST_HEAD(audit_extlist); +static struct list_head audit_filter_list[AUDIT_NR_FILTERS] = { + LIST_HEAD_INIT(audit_filter_list[0]), + LIST_HEAD_INIT(audit_filter_list[1]), + LIST_HEAD_INIT(audit_filter_list[2]), + LIST_HEAD_INIT(audit_filter_list[3]), + LIST_HEAD_INIT(audit_filter_list[4]), +#if AUDIT_NR_FILTERS != 5 +#error Fix audit_filter_list initialiser +#endif +}; struct audit_entry { struct list_head list; @@ -179,9 +190,36 @@ struct audit_entry { extern int audit_pid; +/* Copy rule from user-space to kernel-space. Called from + * audit_add_rule during AUDIT_ADD. */ +static inline int audit_copy_rule(struct audit_rule *d, struct audit_rule *s) +{ + int i; + + if (s->action != AUDIT_NEVER + && s->action != AUDIT_POSSIBLE + && s->action != AUDIT_ALWAYS) + return -1; + if (s->field_count < 0 || s->field_count > AUDIT_MAX_FIELDS) + return -1; + if ((s->flags & ~AUDIT_FILTER_PREPEND) >= AUDIT_NR_FILTERS) + return -1; + + d->flags = s->flags; + d->action = s->action; + d->field_count = s->field_count; + for (i = 0; i < d->field_count; i++) { + d->fields[i] = s->fields[i]; + d->values[i] = s->values[i]; + } + for (i = 0; i < AUDIT_BITMASK_SIZE; i++) d->mask[i] = s->mask[i]; + return 0; +} + /* Check to see if two rules are identical. It is called from + * audit_add_rule during AUDIT_ADD and * audit_del_rule during AUDIT_DEL. */ -static int audit_compare_rule(struct audit_rule *a, struct audit_rule *b) +static inline int audit_compare_rule(struct audit_rule *a, struct audit_rule *b) { int i; @@ -210,19 +248,37 @@ static int audit_compare_rule(struct audit_rule *a, struct audit_rule *b) /* Note that audit_add_rule and audit_del_rule are called via * audit_receive() in audit.c, and are protected by * audit_netlink_sem. */ -static inline int audit_add_rule(struct audit_entry *entry, - struct list_head *list) +static inline int audit_add_rule(struct audit_rule *rule, + struct list_head *list) { - if (entry->rule.flags & AUDIT_PREPEND) { - entry->rule.flags &= ~AUDIT_PREPEND; + struct audit_entry *entry; + + /* Do not use the _rcu iterator here, since this is the only + * addition routine. */ + list_for_each_entry(entry, list, list) { + if (!audit_compare_rule(rule, &entry->rule)) { + return -EEXIST; + } + } + + if (!(entry = kmalloc(sizeof(*entry), GFP_KERNEL))) + return -ENOMEM; + if (audit_copy_rule(&entry->rule, rule)) { + kfree(entry); + return -EINVAL; + } + + if (entry->rule.flags & AUDIT_FILTER_PREPEND) { + entry->rule.flags &= ~AUDIT_FILTER_PREPEND; list_add_rcu(&entry->list, list); } else { list_add_tail_rcu(&entry->list, list); } + return 0; } -static void audit_free_rule(struct rcu_head *head) +static inline void audit_free_rule(struct rcu_head *head) { struct audit_entry *e = container_of(head, struct audit_entry, rcu); kfree(e); @@ -245,82 +301,82 @@ static inline int audit_del_rule(struct audit_rule *rule, return 0; } } - return -EFAULT; /* No matching rule */ + return -ENOENT; /* No matching rule */ } -/* Copy rule from user-space to kernel-space. Called during - * AUDIT_ADD. */ -static int audit_copy_rule(struct audit_rule *d, struct audit_rule *s) +static int audit_list_rules(void *_dest) { + int pid, seq; + int *dest = _dest; + struct audit_entry *entry; int i; - if (s->action != AUDIT_NEVER - && s->action != AUDIT_POSSIBLE - && s->action != AUDIT_ALWAYS) - return -1; - if (s->field_count < 0 || s->field_count > AUDIT_MAX_FIELDS) - return -1; + pid = dest[0]; + seq = dest[1]; + kfree(dest); - d->flags = s->flags; - d->action = s->action; - d->field_count = s->field_count; - for (i = 0; i < d->field_count; i++) { - d->fields[i] = s->fields[i]; - d->values[i] = s->values[i]; + down(&audit_netlink_sem); + + /* The *_rcu iterators not needed here because we are + always called with audit_netlink_sem held. */ + for (i=0; i<AUDIT_NR_FILTERS; i++) { + list_for_each_entry(entry, &audit_filter_list[i], list) + audit_send_reply(pid, seq, AUDIT_LIST, 0, 1, + &entry->rule, sizeof(entry->rule)); } - for (i = 0; i < AUDIT_BITMASK_SIZE; i++) d->mask[i] = s->mask[i]; + audit_send_reply(pid, seq, AUDIT_LIST, 1, 1, NULL, 0); + + up(&audit_netlink_sem); return 0; } int audit_receive_filter(int type, int pid, int uid, int seq, void *data, uid_t loginuid) { - u32 flags; - struct audit_entry *entry; + struct task_struct *tsk; + int *dest; int err = 0; + unsigned listnr; switch (type) { case AUDIT_LIST: - /* The *_rcu iterators not needed here because we are - always called with audit_netlink_sem held. */ - list_for_each_entry(entry, &audit_tsklist, list) - audit_send_reply(pid, seq, AUDIT_LIST, 0, 1, - &entry->rule, sizeof(entry->rule)); - list_for_each_entry(entry, &audit_entlist, list) - audit_send_reply(pid, seq, AUDIT_LIST, 0, 1, - &entry->rule, sizeof(entry->rule)); - list_for_each_entry(entry, &audit_extlist, list) - audit_send_reply(pid, seq, AUDIT_LIST, 0, 1, - &entry->rule, sizeof(entry->rule)); - audit_send_reply(pid, seq, AUDIT_LIST, 1, 1, NULL, 0); + /* We can't just spew out the rules here because we might fill + * the available socket buffer space and deadlock waiting for + * auditctl to read from it... which isn't ever going to + * happen if we're actually running in the context of auditctl + * trying to _send_ the stuff */ + + dest = kmalloc(2 * sizeof(int), GFP_KERNEL); + if (!dest) + return -ENOMEM; + dest[0] = pid; + dest[1] = seq; + + tsk = kthread_run(audit_list_rules, dest, "audit_list_rules"); + if (IS_ERR(tsk)) { + kfree(dest); + err = PTR_ERR(tsk); + } break; case AUDIT_ADD: - if (!(entry = kmalloc(sizeof(*entry), GFP_KERNEL))) - return -ENOMEM; - if (audit_copy_rule(&entry->rule, data)) { - kfree(entry); + listnr =((struct audit_rule *)data)->flags & ~AUDIT_FILTER_PREPEND; + if (listnr >= AUDIT_NR_FILTERS) return -EINVAL; - } - flags = entry->rule.flags; - if (!err && (flags & AUDIT_PER_TASK)) - err = audit_add_rule(entry, &audit_tsklist); - if (!err && (flags & AUDIT_AT_ENTRY)) - err = audit_add_rule(entry, &audit_entlist); - if (!err && (flags & AUDIT_AT_EXIT)) - err = audit_add_rule(entry, &audit_extlist); - audit_log(NULL, AUDIT_CONFIG_CHANGE, - "auid=%u added an audit rule\n", loginuid); + + err = audit_add_rule(data, &audit_filter_list[listnr]); + if (!err) + audit_log(NULL, GFP_KERNEL, AUDIT_CONFIG_CHANGE, + "auid=%u added an audit rule\n", loginuid); break; case AUDIT_DEL: - flags =((struct audit_rule *)data)->flags; - if (!err && (flags & AUDIT_PER_TASK)) - err = audit_del_rule(data, &audit_tsklist); - if (!err && (flags & AUDIT_AT_ENTRY)) - err = audit_del_rule(data, &audit_entlist); - if (!err && (flags & AUDIT_AT_EXIT)) - err = audit_del_rule(data, &audit_extlist); - audit_log(NULL, AUDIT_CONFIG_CHANGE, - "auid=%u removed an audit rule\n", loginuid); + listnr =((struct audit_rule *)data)->flags & ~AUDIT_FILTER_PREPEND; + if (listnr >= AUDIT_NR_FILTERS) + return -EINVAL; + + err = audit_del_rule(data, &audit_filter_list[listnr]); + if (!err) + audit_log(NULL, GFP_KERNEL, AUDIT_CONFIG_CHANGE, + "auid=%u removed an audit rule\n", loginuid); break; default: return -EINVAL; @@ -384,8 +440,12 @@ static int audit_filter_rules(struct task_struct *tsk, result = (ctx->return_code == value); break; case AUDIT_SUCCESS: - if (ctx && ctx->return_valid) - result = (ctx->return_valid == AUDITSC_SUCCESS); + if (ctx && ctx->return_valid) { + if (value) + result = (ctx->return_valid == AUDITSC_SUCCESS); + else + result = (ctx->return_valid == AUDITSC_FAILURE); + } break; case AUDIT_DEVMAJOR: if (ctx) { @@ -454,7 +514,7 @@ static enum audit_state audit_filter_task(struct task_struct *tsk) enum audit_state state; rcu_read_lock(); - list_for_each_entry_rcu(e, &audit_tsklist, list) { + list_for_each_entry_rcu(e, &audit_filter_list[AUDIT_FILTER_TASK], list) { if (audit_filter_rules(tsk, &e->rule, NULL, &state)) { rcu_read_unlock(); return state; @@ -474,20 +534,84 @@ static enum audit_state audit_filter_syscall(struct task_struct *tsk, struct list_head *list) { struct audit_entry *e; + enum audit_state state; + + if (audit_pid && tsk->tgid == audit_pid) + return AUDIT_DISABLED; + + rcu_read_lock(); + if (!list_empty(list)) { + int word = AUDIT_WORD(ctx->major); + int bit = AUDIT_BIT(ctx->major); + + list_for_each_entry_rcu(e, list, list) { + if ((e->rule.mask[word] & bit) == bit + && audit_filter_rules(tsk, &e->rule, ctx, &state)) { + rcu_read_unlock(); + return state; + } + } + } + rcu_read_unlock(); + return AUDIT_BUILD_CONTEXT; +} + +static int audit_filter_user_rules(struct netlink_skb_parms *cb, + struct audit_rule *rule, + enum audit_state *state) +{ + int i; + + for (i = 0; i < rule->field_count; i++) { + u32 field = rule->fields[i] & ~AUDIT_NEGATE; + u32 value = rule->values[i]; + int result = 0; + + switch (field) { + case AUDIT_PID: + result = (cb->creds.pid == value); + break; + case AUDIT_UID: + result = (cb->creds.uid == value); + break; + case AUDIT_GID: + result = (cb->creds.gid == value); + break; + case AUDIT_LOGINUID: + result = (cb->loginuid == value); + break; + } + + if (rule->fields[i] & AUDIT_NEGATE) + result = !result; + if (!result) + return 0; + } + switch (rule->action) { + case AUDIT_NEVER: *state = AUDIT_DISABLED; break; + case AUDIT_POSSIBLE: *state = AUDIT_BUILD_CONTEXT; break; + case AUDIT_ALWAYS: *state = AUDIT_RECORD_CONTEXT; break; + } + return 1; +} + +int audit_filter_user(struct netlink_skb_parms *cb, int type) +{ + struct audit_entry *e; enum audit_state state; - int word = AUDIT_WORD(ctx->major); - int bit = AUDIT_BIT(ctx->major); + int ret = 1; rcu_read_lock(); - list_for_each_entry_rcu(e, list, list) { - if ((e->rule.mask[word] & bit) == bit - && audit_filter_rules(tsk, &e->rule, ctx, &state)) { - rcu_read_unlock(); - return state; + list_for_each_entry_rcu(e, &audit_filter_list[AUDIT_FILTER_USER], list) { + if (audit_filter_user_rules(cb, &e->rule, &state)) { + if (state == AUDIT_DISABLED) + ret = 0; + break; } } rcu_read_unlock(); - return AUDIT_BUILD_CONTEXT; + + return ret; /* Audit by default */ } /* This should be called with task_lock() held. */ @@ -504,7 +628,7 @@ static inline struct audit_context *audit_get_context(struct task_struct *tsk, if (context->in_syscall && !context->auditable) { enum audit_state state; - state = audit_filter_syscall(tsk, context, &audit_extlist); + state = audit_filter_syscall(tsk, context, &audit_filter_list[AUDIT_FILTER_EXIT]); if (state == AUDIT_RECORD_CONTEXT) context->auditable = 1; } @@ -679,13 +803,13 @@ static void audit_log_task_info(struct audit_buffer *ab) up_read(&mm->mmap_sem); } -static void audit_log_exit(struct audit_context *context) +static void audit_log_exit(struct audit_context *context, unsigned int gfp_mask) { int i; struct audit_buffer *ab; struct audit_aux_data *aux; - ab = audit_log_start(context, AUDIT_SYSCALL); + ab = audit_log_start(context, gfp_mask, AUDIT_SYSCALL); if (!ab) return; /* audit_panic has been called */ audit_log_format(ab, "arch=%x syscall=%d", @@ -717,7 +841,7 @@ static void audit_log_exit(struct audit_context *context) for (aux = context->aux; aux; aux = aux->next) { - ab = audit_log_start(context, aux->type); + ab = audit_log_start(context, GFP_KERNEL, aux->type); if (!ab) continue; /* audit_panic has been called */ @@ -754,14 +878,14 @@ static void audit_log_exit(struct audit_context *context) } if (context->pwd && context->pwdmnt) { - ab = audit_log_start(context, AUDIT_CWD); + ab = audit_log_start(context, GFP_KERNEL, AUDIT_CWD); if (ab) { audit_log_d_path(ab, "cwd=", context->pwd, context->pwdmnt); audit_log_end(ab); } } for (i = 0; i < context->name_count; i++) { - ab = audit_log_start(context, AUDIT_PATH); + ab = audit_log_start(context, GFP_KERNEL, AUDIT_PATH); if (!ab) continue; /* audit_panic has been called */ @@ -770,6 +894,8 @@ static void audit_log_exit(struct audit_context *context) audit_log_format(ab, " name="); audit_log_untrustedstring(ab, context->names[i].name); } + audit_log_format(ab, " flags=%x\n", context->names[i].flags); + if (context->names[i].ino != (unsigned long)-1) audit_log_format(ab, " inode=%lu dev=%02x:%02x mode=%#o" " ouid=%u ogid=%u rdev=%02x:%02x", @@ -799,9 +925,11 @@ void audit_free(struct task_struct *tsk) return; /* Check for system calls that do not go through the exit - * function (e.g., exit_group), then free context block. */ - if (context->in_syscall && context->auditable && context->pid != audit_pid) - audit_log_exit(context); + * function (e.g., exit_group), then free context block. + * We use GFP_ATOMIC here because we might be doing this + * in the context of the idle thread */ + if (context->in_syscall && context->auditable) + audit_log_exit(context, GFP_ATOMIC); audit_free_context(context); } @@ -876,11 +1004,11 @@ void audit_syscall_entry(struct task_struct *tsk, int arch, int major, state = context->state; if (state == AUDIT_SETUP_CONTEXT || state == AUDIT_BUILD_CONTEXT) - state = audit_filter_syscall(tsk, context, &audit_entlist); + state = audit_filter_syscall(tsk, context, &audit_filter_list[AUDIT_FILTER_ENTRY]); if (likely(state == AUDIT_DISABLED)) return; - context->serial = audit_serial(); + context->serial = 0; context->ctime = CURRENT_TIME; context->in_syscall = 1; context->auditable = !!(state == AUDIT_RECORD_CONTEXT); @@ -903,10 +1031,10 @@ void audit_syscall_exit(struct task_struct *tsk, int valid, long return_code) /* Not having a context here is ok, since the parent may have * called __put_task_struct. */ if (likely(!context)) - return; + goto out; - if (context->in_syscall && context->auditable && context->pid != audit_pid) - audit_log_exit(context); + if (context->in_syscall && context->auditable) + audit_log_exit(context, GFP_KERNEL); context->in_syscall = 0; context->auditable = 0; @@ -919,9 +1047,9 @@ void audit_syscall_exit(struct task_struct *tsk, int valid, long return_code) } else { audit_free_names(context); audit_free_aux(context); - audit_zero_context(context, context->state); tsk->audit_context = context; } + out: put_task_struct(tsk); } @@ -996,7 +1124,7 @@ void audit_putname(const char *name) /* Store the inode and device from a lookup. Called from * fs/namei.c:path_lookup(). */ -void audit_inode(const char *name, const struct inode *inode) +void audit_inode(const char *name, const struct inode *inode, unsigned flags) { int idx; struct audit_context *context = current->audit_context; @@ -1022,17 +1150,20 @@ void audit_inode(const char *name, const struct inode *inode) ++context->ino_count; #endif } - context->names[idx].ino = inode->i_ino; - context->names[idx].dev = inode->i_sb->s_dev; - context->names[idx].mode = inode->i_mode; - context->names[idx].uid = inode->i_uid; - context->names[idx].gid = inode->i_gid; - context->names[idx].rdev = inode->i_rdev; + context->names[idx].flags = flags; + context->names[idx].ino = inode->i_ino; + context->names[idx].dev = inode->i_sb->s_dev; + context->names[idx].mode = inode->i_mode; + context->names[idx].uid = inode->i_uid; + context->names[idx].gid = inode->i_gid; + context->names[idx].rdev = inode->i_rdev; } void auditsc_get_stamp(struct audit_context *ctx, struct timespec *t, unsigned int *serial) { + if (!ctx->serial) + ctx->serial = audit_serial(); t->tv_sec = ctx->ctime.tv_sec; t->tv_nsec = ctx->ctime.tv_nsec; *serial = ctx->serial; @@ -1044,7 +1175,7 @@ int audit_set_loginuid(struct task_struct *task, uid_t loginuid) if (task->audit_context) { struct audit_buffer *ab; - ab = audit_log_start(NULL, AUDIT_LOGIN); + ab = audit_log_start(NULL, GFP_KERNEL, AUDIT_LOGIN); if (ab) { audit_log_format(ab, "login pid=%d uid=%u " "old auid=%u new auid=%u", @@ -1153,7 +1284,7 @@ void audit_signal_info(int sig, struct task_struct *t) extern pid_t audit_sig_pid; extern uid_t audit_sig_uid; - if (unlikely(audit_pid && t->pid == audit_pid)) { + if (unlikely(audit_pid && t->tgid == audit_pid)) { if (sig == SIGTERM || sig == SIGHUP) { struct audit_context *ctx = current->audit_context; audit_sig_pid = current->pid; diff --git a/kernel/exit.c b/kernel/exit.c index 6d2089a..ee6d8b8 100644 --- a/kernel/exit.c +++ b/kernel/exit.c @@ -371,6 +371,12 @@ static inline void close_files(struct files_struct * files) struct fdtable *fdt; j = 0; + + /* + * It is safe to dereference the fd table without RCU or + * ->file_lock because this is the last reference to the + * files structure. + */ fdt = files_fdtable(files); for (;;) { unsigned long set; diff --git a/kernel/fork.c b/kernel/fork.c index 8149f36..533ce27 100644 --- a/kernel/fork.c +++ b/kernel/fork.c @@ -1062,7 +1062,8 @@ static task_t *copy_process(unsigned long clone_flags, * parent's CPU). This avoids alot of nasty races. */ p->cpus_allowed = current->cpus_allowed; - if (unlikely(!cpu_isset(task_cpu(p), p->cpus_allowed))) + if (unlikely(!cpu_isset(task_cpu(p), p->cpus_allowed) || + !cpu_online(task_cpu(p)))) set_task_cpu(p, smp_processor_id()); /* diff --git a/kernel/module.c b/kernel/module.c index 4b39d37..ff5c500 100644 --- a/kernel/module.c +++ b/kernel/module.c @@ -20,6 +20,7 @@ #include <linux/module.h> #include <linux/moduleloader.h> #include <linux/init.h> +#include <linux/kernel.h> #include <linux/slab.h> #include <linux/vmalloc.h> #include <linux/elf.h> @@ -498,7 +499,7 @@ static inline int try_force(unsigned int flags) { int ret = (flags & O_TRUNC); if (ret) - tainted |= TAINT_FORCED_MODULE; + add_taint(TAINT_FORCED_MODULE); return ret; } #else @@ -897,7 +898,7 @@ static int check_version(Elf_Shdr *sechdrs, if (!(tainted & TAINT_FORCED_MODULE)) { printk("%s: no version for \"%s\" found: kernel tainted.\n", mod->name, symname); - tainted |= TAINT_FORCED_MODULE; + add_taint(TAINT_FORCED_MODULE); } return 1; } @@ -1352,7 +1353,7 @@ static void set_license(struct module *mod, const char *license) if (!mod->license_gplok && !(tainted & TAINT_PROPRIETARY_MODULE)) { printk(KERN_WARNING "%s: module license '%s' taints kernel.\n", mod->name, license); - tainted |= TAINT_PROPRIETARY_MODULE; + add_taint(TAINT_PROPRIETARY_MODULE); } } @@ -1610,7 +1611,7 @@ static struct module *load_module(void __user *umod, modmagic = get_modinfo(sechdrs, infoindex, "vermagic"); /* This is allowed: modprobe --force will invalidate it. */ if (!modmagic) { - tainted |= TAINT_FORCED_MODULE; + add_taint(TAINT_FORCED_MODULE); printk(KERN_WARNING "%s: no version magic, tainting kernel.\n", mod->name); } else if (!same_magic(modmagic, vermagic)) { @@ -1739,7 +1740,7 @@ static struct module *load_module(void __user *umod, (mod->num_gpl_syms && !gplcrcindex)) { printk(KERN_WARNING "%s: No versions for exported symbols." " Tainting kernel.\n", mod->name); - tainted |= TAINT_FORCED_MODULE; + add_taint(TAINT_FORCED_MODULE); } #endif diff --git a/kernel/power/Kconfig b/kernel/power/Kconfig index 396c787..46a5e5a 100644 --- a/kernel/power/Kconfig +++ b/kernel/power/Kconfig @@ -29,7 +29,7 @@ config PM_DEBUG config SOFTWARE_SUSPEND bool "Software Suspend" - depends on PM && SWAP && (X86 || ((FVR || PPC32) && !SMP)) + depends on PM && SWAP && (X86 && (!SMP || SUSPEND_SMP)) || ((FVR || PPC32) && !SMP) ---help--- Enable the possibility of suspending the machine. It doesn't need APM. diff --git a/kernel/power/disk.c b/kernel/power/disk.c index 2d8bf05..761956e 100644 --- a/kernel/power/disk.c +++ b/kernel/power/disk.c @@ -17,12 +17,12 @@ #include <linux/delay.h> #include <linux/fs.h> #include <linux/mount.h> +#include <linux/pm.h> #include "power.h" extern suspend_disk_method_t pm_disk_mode; -extern struct pm_ops * pm_ops; extern int swsusp_suspend(void); extern int swsusp_write(void); @@ -49,13 +49,11 @@ dev_t swsusp_resume_device; static void power_down(suspend_disk_method_t mode) { - unsigned long flags; int error = 0; - local_irq_save(flags); switch(mode) { case PM_DISK_PLATFORM: - device_shutdown(); + kernel_power_off_prepare(); error = pm_ops->enter(PM_SUSPEND_DISK); break; case PM_DISK_SHUTDOWN: diff --git a/kernel/power/power.h b/kernel/power/power.h index cd6a349..9c9167d 100644 --- a/kernel/power/power.h +++ b/kernel/power/power.h @@ -1,7 +1,7 @@ #include <linux/suspend.h> #include <linux/utsname.h> -/* With SUSPEND_CONSOLE defined, it suspend looks *really* cool, but +/* With SUSPEND_CONSOLE defined suspend looks *really* cool, but we probably do not take enough locks for switching consoles, etc, so bad things might happen. */ diff --git a/kernel/power/swsusp.c b/kernel/power/swsusp.c index d967e87..1cc9ff2 100644 --- a/kernel/power/swsusp.c +++ b/kernel/power/swsusp.c @@ -363,7 +363,7 @@ static void lock_swapdevices(void) } /** - * write_swap_page - Write one page to a fresh swap location. + * write_page - Write one page to a fresh swap location. * @addr: Address we're writing. * @loc: Place to store the entry we used. * @@ -863,6 +863,9 @@ static int alloc_image_pages(void) return 0; } +/* Free pages we allocated for suspend. Suspend pages are alocated + * before atomic copy, so we need to free them after resume. + */ void swsusp_free(void) { BUG_ON(PageNosave(virt_to_page(pagedir_save))); @@ -918,6 +921,7 @@ static int swsusp_alloc(void) pagedir_nosave = NULL; nr_copy_pages = calc_nr(nr_copy_pages); + nr_copy_pages_check = nr_copy_pages; pr_debug("suspend: (pages needed: %d + %d free: %d)\n", nr_copy_pages, PAGES_FOR_IO, nr_free_pages()); @@ -940,7 +944,6 @@ static int swsusp_alloc(void) return error; } - nr_copy_pages_check = nr_copy_pages; return 0; } @@ -1213,8 +1216,9 @@ static struct pbe * swsusp_pagedir_relocate(struct pbe *pblist) free_pagedir(pblist); free_eaten_memory(); pblist = NULL; - } - else + /* Is this even worth handling? It should never ever happen, and we + have just lost user's state, anyway... */ + } else printk("swsusp: Relocated %d pages\n", rel); return pblist; diff --git a/kernel/printk.c b/kernel/printk.c index a967605..4b8f0f9 100644 --- a/kernel/printk.c +++ b/kernel/printk.c @@ -488,6 +488,11 @@ static int __init printk_time_setup(char *str) __setup("time", printk_time_setup); +__attribute__((weak)) unsigned long long printk_clock(void) +{ + return sched_clock(); +} + /* * This is printk. It can be called from any context. We want it to work. * @@ -565,7 +570,7 @@ asmlinkage int vprintk(const char *fmt, va_list args) loglev_char = default_message_loglevel + '0'; } - t = sched_clock(); + t = printk_clock(); nanosec_rem = do_div(t, 1000000000); tlen = sprintf(tbuf, "<%c>[%5lu.%06lu] ", diff --git a/kernel/sched.c b/kernel/sched.c index 81b3a96..1f31a52 100644 --- a/kernel/sched.c +++ b/kernel/sched.c @@ -294,6 +294,10 @@ static inline void prepare_lock_switch(runqueue_t *rq, task_t *next) static inline void finish_lock_switch(runqueue_t *rq, task_t *prev) { +#ifdef CONFIG_DEBUG_SPINLOCK + /* this is a valid case when another task releases the spinlock */ + rq->lock.owner = current; +#endif spin_unlock_irq(&rq->lock); } @@ -1529,10 +1533,6 @@ static inline void finish_task_switch(runqueue_t *rq, task_t *prev) * Manfred Spraul <manfred@colorfullife.com> */ prev_task_flags = prev->flags; -#ifdef CONFIG_DEBUG_SPINLOCK - /* this is a valid case when another task releases the spinlock */ - rq->lock.owner = current; -#endif finish_arch_switch(prev); finish_lock_switch(rq, prev); if (mm) diff --git a/kernel/signal.c b/kernel/signal.c index b92c3c9..5a27470 100644 --- a/kernel/signal.c +++ b/kernel/signal.c @@ -936,34 +936,31 @@ force_sig_specific(int sig, struct task_struct *t) * as soon as they're available, so putting the signal on the shared queue * will be equivalent to sending it to one such thread. */ -#define wants_signal(sig, p, mask) \ - (!sigismember(&(p)->blocked, sig) \ - && !((p)->state & mask) \ - && !((p)->flags & PF_EXITING) \ - && (task_curr(p) || !signal_pending(p))) - +static inline int wants_signal(int sig, struct task_struct *p) +{ + if (sigismember(&p->blocked, sig)) + return 0; + if (p->flags & PF_EXITING) + return 0; + if (sig == SIGKILL) + return 1; + if (p->state & (TASK_STOPPED | TASK_TRACED)) + return 0; + return task_curr(p) || !signal_pending(p); +} static void __group_complete_signal(int sig, struct task_struct *p) { - unsigned int mask; struct task_struct *t; /* - * Don't bother traced and stopped tasks (but - * SIGKILL will punch through that). - */ - mask = TASK_STOPPED | TASK_TRACED; - if (sig == SIGKILL) - mask = 0; - - /* * Now find a thread we can wake up to take the signal off the queue. * * If the main thread wants the signal, it gets first crack. * Probably the least surprising to the average bear. */ - if (wants_signal(sig, p, mask)) + if (wants_signal(sig, p)) t = p; else if (thread_group_empty(p)) /* @@ -981,7 +978,7 @@ __group_complete_signal(int sig, struct task_struct *p) t = p->signal->curr_target = p; BUG_ON(t->tgid != p->tgid); - while (!wants_signal(sig, t, mask)) { + while (!wants_signal(sig, t)) { t = next_thread(t); if (t == p->signal->curr_target) /* diff --git a/kernel/sys.c b/kernel/sys.c index c80412b..2fa1ed1 100644 --- a/kernel/sys.c +++ b/kernel/sys.c @@ -361,17 +361,35 @@ out_unlock: return retval; } +/** + * emergency_restart - reboot the system + * + * Without shutting down any hardware or taking any locks + * reboot the system. This is called when we know we are in + * trouble so this is our best effort to reboot. This is + * safe to call in interrupt context. + */ void emergency_restart(void) { machine_emergency_restart(); } EXPORT_SYMBOL_GPL(emergency_restart); -void kernel_restart(char *cmd) +/** + * kernel_restart - reboot the system + * + * Shutdown everything and perform a clean reboot. + * This is not safe to call in interrupt context. + */ +void kernel_restart_prepare(char *cmd) { notifier_call_chain(&reboot_notifier_list, SYS_RESTART, cmd); system_state = SYSTEM_RESTART; device_shutdown(); +} +void kernel_restart(char *cmd) +{ + kernel_restart_prepare(cmd); if (!cmd) { printk(KERN_EMERG "Restarting system.\n"); } else { @@ -382,6 +400,12 @@ void kernel_restart(char *cmd) } EXPORT_SYMBOL_GPL(kernel_restart); +/** + * kernel_kexec - reboot the system + * + * Move into place and start executing a preloaded standalone + * executable. If nothing was preloaded return an error. + */ void kernel_kexec(void) { #ifdef CONFIG_KEXEC @@ -390,9 +414,7 @@ void kernel_kexec(void) if (!image) { return; } - notifier_call_chain(&reboot_notifier_list, SYS_RESTART, NULL); - system_state = SYSTEM_RESTART; - device_shutdown(); + kernel_restart_prepare(NULL); printk(KERN_EMERG "Starting new kernel\n"); machine_shutdown(); machine_kexec(image); @@ -400,21 +422,39 @@ void kernel_kexec(void) } EXPORT_SYMBOL_GPL(kernel_kexec); -void kernel_halt(void) +/** + * kernel_halt - halt the system + * + * Shutdown everything and perform a clean system halt. + */ +void kernel_halt_prepare(void) { notifier_call_chain(&reboot_notifier_list, SYS_HALT, NULL); system_state = SYSTEM_HALT; device_shutdown(); +} +void kernel_halt(void) +{ + kernel_halt_prepare(); printk(KERN_EMERG "System halted.\n"); machine_halt(); } EXPORT_SYMBOL_GPL(kernel_halt); -void kernel_power_off(void) +/** + * kernel_power_off - power_off the system + * + * Shutdown everything and perform a clean system power_off. + */ +void kernel_power_off_prepare(void) { notifier_call_chain(&reboot_notifier_list, SYS_POWER_OFF, NULL); system_state = SYSTEM_POWER_OFF; device_shutdown(); +} +void kernel_power_off(void) +{ + kernel_power_off_prepare(); printk(KERN_EMERG "Power down.\n"); machine_power_off(); } @@ -1728,8 +1768,7 @@ asmlinkage long sys_prctl(int option, unsigned long arg2, unsigned long arg3, error = put_user(current->pdeath_signal, (int __user *)arg2); break; case PR_GET_DUMPABLE: - if (current->mm->dumpable) - error = 1; + error = current->mm->dumpable; break; case PR_SET_DUMPABLE: if (arg2 < 0 || arg2 > 2) { diff --git a/kernel/timer.c b/kernel/timer.c index f4152fc..3ba10fa 100644 --- a/kernel/timer.c +++ b/kernel/timer.c @@ -1151,19 +1151,22 @@ fastcall signed long __sched schedule_timeout(signed long timeout) out: return timeout < 0 ? 0 : timeout; } - EXPORT_SYMBOL(schedule_timeout); +/* + * We can use __set_current_state() here because schedule_timeout() calls + * schedule() unconditionally. + */ signed long __sched schedule_timeout_interruptible(signed long timeout) { - set_current_state(TASK_INTERRUPTIBLE); + __set_current_state(TASK_INTERRUPTIBLE); return schedule_timeout(timeout); } EXPORT_SYMBOL(schedule_timeout_interruptible); signed long __sched schedule_timeout_uninterruptible(signed long timeout) { - set_current_state(TASK_UNINTERRUPTIBLE); + __set_current_state(TASK_UNINTERRUPTIBLE); return schedule_timeout(timeout); } EXPORT_SYMBOL(schedule_timeout_uninterruptible); diff --git a/lib/dec_and_lock.c b/lib/dec_and_lock.c index 2377af0..305a966 100644 --- a/lib/dec_and_lock.c +++ b/lib/dec_and_lock.c @@ -1,7 +1,41 @@ #include <linux/module.h> #include <linux/spinlock.h> #include <asm/atomic.h> +#include <asm/system.h> +#ifdef __HAVE_ARCH_CMPXCHG +/* + * This is an implementation of the notion of "decrement a + * reference count, and return locked if it decremented to zero". + * + * This implementation can be used on any architecture that + * has a cmpxchg, and where atomic->value is an int holding + * the value of the atomic (i.e. the high bits aren't used + * for a lock or anything like that). + */ +int _atomic_dec_and_lock(atomic_t *atomic, spinlock_t *lock) +{ + int counter; + int newcount; + + for (;;) { + counter = atomic_read(atomic); + newcount = counter - 1; + if (!newcount) + break; /* do it the slow way */ + + newcount = cmpxchg(&atomic->counter, counter, newcount); + if (newcount == counter) + return 0; + } + + spin_lock(lock); + if (atomic_dec_and_test(atomic)) + return 1; + spin_unlock(lock); + return 0; +} +#else /* * This is an architecture-neutral, but slow, * implementation of the notion of "decrement @@ -33,5 +67,6 @@ int _atomic_dec_and_lock(atomic_t *atomic, spinlock_t *lock) spin_unlock(lock); return 0; } +#endif EXPORT_SYMBOL(_atomic_dec_and_lock); @@ -29,7 +29,7 @@ config FLATMEM_MANUAL If unsure, choose this option (Flat Memory) over any other. config DISCONTIGMEM_MANUAL - bool "Discontigious Memory" + bool "Discontiguous Memory" depends on ARCH_DISCONTIGMEM_ENABLE help This option provides enhanced support for discontiguous @@ -52,7 +52,7 @@ config SPARSEMEM_MANUAL memory hotplug systems. This is normal. For many other systems, this will be an alternative to - "Discontigious Memory". This option provides some potential + "Discontiguous Memory". This option provides some potential performance benefits, along with decreased code complexity, but it is newer, and more experimental. diff --git a/mm/mempolicy.c b/mm/mempolicy.c index afa06e1..9033f08 100644 --- a/mm/mempolicy.c +++ b/mm/mempolicy.c @@ -333,8 +333,13 @@ check_range(struct mm_struct *mm, unsigned long start, unsigned long end, if (prev && prev->vm_end < vma->vm_start) return ERR_PTR(-EFAULT); if ((flags & MPOL_MF_STRICT) && !is_vm_hugetlb_page(vma)) { + unsigned long endvma = vma->vm_end; + if (endvma > end) + endvma = end; + if (vma->vm_start > start) + start = vma->vm_start; err = check_pgd_range(vma->vm_mm, - vma->vm_start, vma->vm_end, nodes); + start, endvma, nodes); if (err) { first = ERR_PTR(err); break; @@ -1640,7 +1640,7 @@ static void unmap_vma_list(struct mm_struct *mm, struct vm_area_struct *vma) /* * Get rid of page table information in the indicated region. * - * Called with the page table lock held. + * Called with the mm semaphore held. */ static void unmap_region(struct mm_struct *mm, struct vm_area_struct *vma, struct vm_area_struct *prev, @@ -1993,6 +1993,9 @@ int insert_vm_struct(struct mm_struct * mm, struct vm_area_struct * vma) __vma = find_vma_prepare(mm,vma->vm_start,&prev,&rb_link,&rb_parent); if (__vma && __vma->vm_start < vma->vm_end) return -ENOMEM; + if ((vma->vm_flags & VM_ACCOUNT) && + security_vm_enough_memory(vma_pages(vma))) + return -ENOMEM; vma_link(mm, vma, prev, rb_link, rb_parent); return 0; } diff --git a/mm/mprotect.c b/mm/mprotect.c index e9fbd01..57577f6 100644 --- a/mm/mprotect.c +++ b/mm/mprotect.c @@ -248,7 +248,8 @@ sys_mprotect(unsigned long start, size_t len, unsigned long prot) newflags = vm_flags | (vma->vm_flags & ~(VM_READ | VM_WRITE | VM_EXEC)); - if ((newflags & ~(newflags >> 4)) & 0xf) { + /* newflags >> 4 shift VM_MAY% in place of VM_% */ + if ((newflags & ~(newflags >> 4)) & (VM_READ | VM_WRITE | VM_EXEC)) { error = -EACCES; goto out; } diff --git a/mm/page_alloc.c b/mm/page_alloc.c index c5823c3..ae29033 100644 --- a/mm/page_alloc.c +++ b/mm/page_alloc.c @@ -22,6 +22,7 @@ #include <linux/pagemap.h> #include <linux/bootmem.h> #include <linux/compiler.h> +#include <linux/kernel.h> #include <linux/module.h> #include <linux/suspend.h> #include <linux/pagevec.h> @@ -117,7 +118,7 @@ static void bad_page(const char *function, struct page *page) set_page_count(page, 0); reset_page_mapcount(page); page->mapping = NULL; - tainted |= TAINT_BAD_PAGE; + add_taint(TAINT_BAD_PAGE); } #ifndef CONFIG_HUGETLB_PAGE @@ -308,12 +308,12 @@ struct kmem_list3 __initdata initkmem_list3[NUM_INIT_LISTS]; #define SIZE_L3 (1 + MAX_NUMNODES) /* - * This function may be completely optimized away if + * This function must be completely optimized away if * a constant is passed to it. Mostly the same as * what is in linux/slab.h except it returns an * index. */ -static inline int index_of(const size_t size) +static __always_inline int index_of(const size_t size) { if (__builtin_constant_p(size)) { int i = 0; @@ -329,7 +329,8 @@ static inline int index_of(const size_t size) extern void __bad_size(void); __bad_size(); } - } + } else + BUG(); return 0; } @@ -639,7 +640,7 @@ static enum { static DEFINE_PER_CPU(struct work_struct, reap_work); -static void free_block(kmem_cache_t* cachep, void** objpp, int len); +static void free_block(kmem_cache_t* cachep, void** objpp, int len, int node); static void enable_cpucache (kmem_cache_t *cachep); static void cache_reap (void *unused); static int __node_shrink(kmem_cache_t *cachep, int node); @@ -659,7 +660,7 @@ static inline kmem_cache_t *__find_general_cachep(size_t size, * kmem_cache_create(), or __kmalloc(), before * the generic caches are initialized. */ - BUG_ON(csizep->cs_cachep == NULL); + BUG_ON(malloc_sizes[INDEX_AC].cs_cachep == NULL); #endif while (size > csizep->cs_size) csizep++; @@ -804,7 +805,7 @@ static inline void __drain_alien_cache(kmem_cache_t *cachep, struct array_cache if (ac->avail) { spin_lock(&rl3->list_lock); - free_block(cachep, ac->entry, ac->avail); + free_block(cachep, ac->entry, ac->avail, node); ac->avail = 0; spin_unlock(&rl3->list_lock); } @@ -925,7 +926,7 @@ static int __devinit cpuup_callback(struct notifier_block *nfb, /* Free limit for this kmem_list3 */ l3->free_limit -= cachep->batchcount; if (nc) - free_block(cachep, nc->entry, nc->avail); + free_block(cachep, nc->entry, nc->avail, node); if (!cpus_empty(mask)) { spin_unlock(&l3->list_lock); @@ -934,7 +935,7 @@ static int __devinit cpuup_callback(struct notifier_block *nfb, if (l3->shared) { free_block(cachep, l3->shared->entry, - l3->shared->avail); + l3->shared->avail, node); kfree(l3->shared); l3->shared = NULL; } @@ -1882,12 +1883,13 @@ static void do_drain(void *arg) { kmem_cache_t *cachep = (kmem_cache_t*)arg; struct array_cache *ac; + int node = numa_node_id(); check_irq_off(); ac = ac_data(cachep); - spin_lock(&cachep->nodelists[numa_node_id()]->list_lock); - free_block(cachep, ac->entry, ac->avail); - spin_unlock(&cachep->nodelists[numa_node_id()]->list_lock); + spin_lock(&cachep->nodelists[node]->list_lock); + free_block(cachep, ac->entry, ac->avail, node); + spin_unlock(&cachep->nodelists[node]->list_lock); ac->avail = 0; } @@ -2608,7 +2610,7 @@ done: /* * Caller needs to acquire correct kmem_list's list_lock */ -static void free_block(kmem_cache_t *cachep, void **objpp, int nr_objects) +static void free_block(kmem_cache_t *cachep, void **objpp, int nr_objects, int node) { int i; struct kmem_list3 *l3; @@ -2617,14 +2619,12 @@ static void free_block(kmem_cache_t *cachep, void **objpp, int nr_objects) void *objp = objpp[i]; struct slab *slabp; unsigned int objnr; - int nodeid = 0; slabp = GET_PAGE_SLAB(virt_to_page(objp)); - nodeid = slabp->nodeid; - l3 = cachep->nodelists[nodeid]; + l3 = cachep->nodelists[node]; list_del(&slabp->list); objnr = (objp - slabp->s_mem) / cachep->objsize; - check_spinlock_acquired_node(cachep, nodeid); + check_spinlock_acquired_node(cachep, node); check_slabp(cachep, slabp); @@ -2664,13 +2664,14 @@ static void cache_flusharray(kmem_cache_t *cachep, struct array_cache *ac) { int batchcount; struct kmem_list3 *l3; + int node = numa_node_id(); batchcount = ac->batchcount; #if DEBUG BUG_ON(!batchcount || batchcount > ac->avail); #endif check_irq_off(); - l3 = cachep->nodelists[numa_node_id()]; + l3 = cachep->nodelists[node]; spin_lock(&l3->list_lock); if (l3->shared) { struct array_cache *shared_array = l3->shared; @@ -2686,7 +2687,7 @@ static void cache_flusharray(kmem_cache_t *cachep, struct array_cache *ac) } } - free_block(cachep, ac->entry, batchcount); + free_block(cachep, ac->entry, batchcount, node); free_done: #if STATS { @@ -2751,7 +2752,7 @@ static inline void __cache_free(kmem_cache_t *cachep, void *objp) } else { spin_lock(&(cachep->nodelists[nodeid])-> list_lock); - free_block(cachep, &objp, 1); + free_block(cachep, &objp, 1, nodeid); spin_unlock(&(cachep->nodelists[nodeid])-> list_lock); } @@ -2844,7 +2845,7 @@ void *kmem_cache_alloc_node(kmem_cache_t *cachep, unsigned int __nocast flags, i unsigned long save_flags; void *ptr; - if (nodeid == numa_node_id() || nodeid == -1) + if (nodeid == -1) return __cache_alloc(cachep, flags); if (unlikely(!cachep->nodelists[nodeid])) { @@ -3079,7 +3080,7 @@ static int alloc_kmemlist(kmem_cache_t *cachep) if ((nc = cachep->nodelists[node]->shared)) free_block(cachep, nc->entry, - nc->avail); + nc->avail, node); l3->shared = new; if (!cachep->nodelists[node]->alien) { @@ -3160,7 +3161,7 @@ static int do_tune_cpucache(kmem_cache_t *cachep, int limit, int batchcount, if (!ccold) continue; spin_lock_irq(&cachep->nodelists[cpu_to_node(i)]->list_lock); - free_block(cachep, ccold->entry, ccold->avail); + free_block(cachep, ccold->entry, ccold->avail, cpu_to_node(i)); spin_unlock_irq(&cachep->nodelists[cpu_to_node(i)]->list_lock); kfree(ccold); } @@ -3240,7 +3241,7 @@ static void drain_array_locked(kmem_cache_t *cachep, if (tofree > ac->avail) { tofree = (ac->avail+1)/2; } - free_block(cachep, ac->entry, tofree); + free_block(cachep, ac->entry, tofree, node); ac->avail -= tofree; memmove(ac->entry, &(ac->entry[tofree]), sizeof(void*)*ac->avail); diff --git a/mm/swapfile.c b/mm/swapfile.c index 0184f51..1dcaeda 100644 --- a/mm/swapfile.c +++ b/mm/swapfile.c @@ -1381,6 +1381,7 @@ asmlinkage long sys_swapon(const char __user * specialfile, int swap_flags) error = bd_claim(bdev, sys_swapon); if (error < 0) { bdev = NULL; + error = -EINVAL; goto bad_swap; } p->old_block_size = block_size(bdev); diff --git a/mm/vmscan.c b/mm/vmscan.c index a740778..0ea71e8 100644 --- a/mm/vmscan.c +++ b/mm/vmscan.c @@ -1258,9 +1258,9 @@ void wakeup_kswapd(struct zone *zone, int order) pgdat->kswapd_max_order = order; if (!cpuset_zone_allowed(zone, __GFP_HARDWALL)) return; - if (!waitqueue_active(&zone->zone_pgdat->kswapd_wait)) + if (!waitqueue_active(&pgdat->kswapd_wait)) return; - wake_up_interruptible(&zone->zone_pgdat->kswapd_wait); + wake_up_interruptible(&pgdat->kswapd_wait); } #ifdef CONFIG_PM diff --git a/net/8021q/vlan_dev.c b/net/8021q/vlan_dev.c index 145f5cd..b748648 100644 --- a/net/8021q/vlan_dev.c +++ b/net/8021q/vlan_dev.c @@ -120,7 +120,7 @@ int vlan_skb_recv(struct sk_buff *skb, struct net_device *dev, unsigned short vid; struct net_device_stats *stats; unsigned short vlan_TCI; - unsigned short proto; + __be16 proto; /* vlan_TCI = ntohs(get_unaligned(&vhdr->h_vlan_TCI)); */ vlan_TCI = ntohs(vhdr->h_vlan_TCI); diff --git a/net/Kconfig b/net/Kconfig index 2bdd562..60f6f32 100644 --- a/net/Kconfig +++ b/net/Kconfig @@ -140,6 +140,7 @@ config BRIDGE_NETFILTER If unsure, say N. +source "net/netfilter/Kconfig" source "net/ipv4/netfilter/Kconfig" source "net/ipv6/netfilter/Kconfig" source "net/decnet/netfilter/Kconfig" @@ -206,8 +207,6 @@ config NET_PKTGEN To compile this code as a module, choose M here: the module will be called pktgen. -source "net/netfilter/Kconfig" - endmenu endmenu diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index d6da093..b61b4e8 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -558,6 +558,35 @@ static inline void hci_inquiry_result_with_rssi_evt(struct hci_dev *hdev, struct hci_dev_unlock(hdev); } +/* Extended Inquiry Result */ +static inline void hci_extended_inquiry_result_evt(struct hci_dev *hdev, struct sk_buff *skb) +{ + struct inquiry_data data; + struct extended_inquiry_info *info = (struct extended_inquiry_info *) (skb->data + 1); + int num_rsp = *((__u8 *) skb->data); + + BT_DBG("%s num_rsp %d", hdev->name, num_rsp); + + if (!num_rsp) + return; + + hci_dev_lock(hdev); + + for (; num_rsp; num_rsp--) { + bacpy(&data.bdaddr, &info->bdaddr); + data.pscan_rep_mode = info->pscan_rep_mode; + data.pscan_period_mode = info->pscan_period_mode; + data.pscan_mode = 0x00; + memcpy(data.dev_class, info->dev_class, 3); + data.clock_offset = info->clock_offset; + data.rssi = info->rssi; + info++; + hci_inquiry_cache_update(hdev, &data); + } + + hci_dev_unlock(hdev); +} + /* Connect Request */ static inline void hci_conn_request_evt(struct hci_dev *hdev, struct sk_buff *skb) { @@ -940,6 +969,10 @@ void hci_event_packet(struct hci_dev *hdev, struct sk_buff *skb) hci_inquiry_result_with_rssi_evt(hdev, skb); break; + case HCI_EV_EXTENDED_INQUIRY_RESULT: + hci_extended_inquiry_result_evt(hdev, skb); + break; + case HCI_EV_CONN_REQUEST: hci_conn_request_evt(hdev, skb); break; diff --git a/net/bluetooth/rfcomm/sock.c b/net/bluetooth/rfcomm/sock.c index 90e19eb..f49e7e9 100644 --- a/net/bluetooth/rfcomm/sock.c +++ b/net/bluetooth/rfcomm/sock.c @@ -363,6 +363,11 @@ static int rfcomm_sock_bind(struct socket *sock, struct sockaddr *addr, int addr goto done; } + if (sk->sk_type != SOCK_STREAM) { + err = -EINVAL; + goto done; + } + write_lock_bh(&rfcomm_sk_list.lock); if (sa->rc_channel && __rfcomm_get_sock_by_addr(sa->rc_channel, &sa->rc_bdaddr)) { @@ -393,13 +398,17 @@ static int rfcomm_sock_connect(struct socket *sock, struct sockaddr *addr, int a if (addr->sa_family != AF_BLUETOOTH || alen < sizeof(struct sockaddr_rc)) return -EINVAL; - if (sk->sk_state != BT_OPEN && sk->sk_state != BT_BOUND) - return -EBADFD; + lock_sock(sk); - if (sk->sk_type != SOCK_STREAM) - return -EINVAL; + if (sk->sk_state != BT_OPEN && sk->sk_state != BT_BOUND) { + err = -EBADFD; + goto done; + } - lock_sock(sk); + if (sk->sk_type != SOCK_STREAM) { + err = -EINVAL; + goto done; + } sk->sk_state = BT_CONNECT; bacpy(&bt_sk(sk)->dst, &sa->rc_bdaddr); @@ -410,6 +419,7 @@ static int rfcomm_sock_connect(struct socket *sock, struct sockaddr *addr, int a err = bt_sock_wait_state(sk, BT_CONNECTED, sock_sndtimeo(sk, flags & O_NONBLOCK)); +done: release_sock(sk); return err; } @@ -428,6 +438,11 @@ static int rfcomm_sock_listen(struct socket *sock, int backlog) goto done; } + if (sk->sk_type != SOCK_STREAM) { + err = -EINVAL; + goto done; + } + if (!rfcomm_pi(sk)->channel) { bdaddr_t *src = &bt_sk(sk)->src; u8 channel; @@ -472,6 +487,11 @@ static int rfcomm_sock_accept(struct socket *sock, struct socket *newsock, int f goto done; } + if (sk->sk_type != SOCK_STREAM) { + err = -EINVAL; + goto done; + } + timeo = sock_rcvtimeo(sk, flags & O_NONBLOCK); BT_DBG("sk %p timeo %ld", sk, timeo); diff --git a/net/bridge/br_forward.c b/net/bridge/br_forward.c index 069253f..2d24fb4 100644 --- a/net/bridge/br_forward.c +++ b/net/bridge/br_forward.c @@ -31,7 +31,8 @@ static inline int should_deliver(const struct net_bridge_port *p, int br_dev_queue_push_xmit(struct sk_buff *skb) { - if (skb->len > skb->dev->mtu) + /* drop mtu oversized packets except tso */ + if (skb->len > skb->dev->mtu && !skb_shinfo(skb)->tso_size) kfree_skb(skb); else { #ifdef CONFIG_BRIDGE_NETFILTER diff --git a/net/bridge/br_netfilter.c b/net/bridge/br_netfilter.c index 2d52fee..d8e36b7 100644 --- a/net/bridge/br_netfilter.c +++ b/net/bridge/br_netfilter.c @@ -214,9 +214,11 @@ static int br_nf_pre_routing_finish(struct sk_buff *skb) .tos = RT_TOS(iph->tos)} }, .proto = 0}; if (!ip_route_output_key(&rt, &fl)) { - /* Bridged-and-DNAT'ed traffic doesn't - * require ip_forwarding. */ - if (((struct dst_entry *)rt)->dev == dev) { + /* - Bridged-and-DNAT'ed traffic doesn't + * require ip_forwarding. + * - Deal with redirected traffic. */ + if (((struct dst_entry *)rt)->dev == dev || + rt->rt_type == RTN_LOCAL) { skb->dst = (struct dst_entry *)rt; goto bridged_dnat; } diff --git a/net/dccp/Makefile b/net/dccp/Makefile index fb97bb0..344a8da 100644 --- a/net/dccp/Makefile +++ b/net/dccp/Makefile @@ -3,6 +3,8 @@ obj-$(CONFIG_IP_DCCP) += dccp.o dccp-y := ccid.o input.o ipv4.o minisocks.o options.o output.o proto.o \ timer.o +dccp-$(CONFIG_IP_DCCP_ACKVEC) += ackvec.o + obj-$(CONFIG_INET_DCCP_DIAG) += dccp_diag.o dccp_diag-y := diag.o diff --git a/net/dccp/ackvec.c b/net/dccp/ackvec.c new file mode 100644 index 0000000..6530283 --- /dev/null +++ b/net/dccp/ackvec.c @@ -0,0 +1,419 @@ +/* + * net/dccp/ackvec.c + * + * An implementation of the DCCP protocol + * Copyright (c) 2005 Arnaldo Carvalho de Melo <acme@ghostprotocols.net> + * + * This 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 of the License; + */ + +#include "ackvec.h" +#include "dccp.h" + +#include <linux/dccp.h> +#include <linux/skbuff.h> + +#include <net/sock.h> + +int dccp_insert_option_ackvec(struct sock *sk, struct sk_buff *skb) +{ + struct dccp_sock *dp = dccp_sk(sk); + struct dccp_ackvec *av = dp->dccps_hc_rx_ackvec; + int len = av->dccpav_vec_len + 2; + struct timeval now; + u32 elapsed_time; + unsigned char *to, *from; + + dccp_timestamp(sk, &now); + elapsed_time = timeval_delta(&now, &av->dccpav_time) / 10; + + if (elapsed_time != 0) + dccp_insert_option_elapsed_time(sk, skb, elapsed_time); + + if (DCCP_SKB_CB(skb)->dccpd_opt_len + len > DCCP_MAX_OPT_LEN) + return -1; + + /* + * XXX: now we have just one ack vector sent record, so + * we have to wait for it to be cleared. + * + * Of course this is not acceptable, but this is just for + * basic testing now. + */ + if (av->dccpav_ack_seqno != DCCP_MAX_SEQNO + 1) + return -1; + + DCCP_SKB_CB(skb)->dccpd_opt_len += len; + + to = skb_push(skb, len); + *to++ = DCCPO_ACK_VECTOR_0; + *to++ = len; + + len = av->dccpav_vec_len; + from = av->dccpav_buf + av->dccpav_buf_head; + + /* Check if buf_head wraps */ + if (av->dccpav_buf_head + len > av->dccpav_vec_len) { + const u32 tailsize = (av->dccpav_vec_len - av->dccpav_buf_head); + + memcpy(to, from, tailsize); + to += tailsize; + len -= tailsize; + from = av->dccpav_buf; + } + + memcpy(to, from, len); + /* + * From draft-ietf-dccp-spec-11.txt: + * + * For each acknowledgement it sends, the HC-Receiver will add an + * acknowledgement record. ack_seqno will equal the HC-Receiver + * sequence number it used for the ack packet; ack_ptr will equal + * buf_head; ack_ackno will equal buf_ackno; and ack_nonce will + * equal buf_nonce. + * + * This implemention uses just one ack record for now. + */ + av->dccpav_ack_seqno = DCCP_SKB_CB(skb)->dccpd_seq; + av->dccpav_ack_ptr = av->dccpav_buf_head; + av->dccpav_ack_ackno = av->dccpav_buf_ackno; + av->dccpav_ack_nonce = av->dccpav_buf_nonce; + av->dccpav_sent_len = av->dccpav_vec_len; + + dccp_pr_debug("%sACK Vector 0, len=%d, ack_seqno=%llu, " + "ack_ackno=%llu\n", + debug_prefix, av->dccpav_sent_len, + (unsigned long long)av->dccpav_ack_seqno, + (unsigned long long)av->dccpav_ack_ackno); + return -1; +} + +struct dccp_ackvec *dccp_ackvec_alloc(const unsigned int len, + const unsigned int __nocast priority) +{ + struct dccp_ackvec *av = kmalloc(sizeof(*av) + len, priority); + + if (av != NULL) { + av->dccpav_buf_len = len; + av->dccpav_buf_head = + av->dccpav_buf_tail = av->dccpav_buf_len - 1; + av->dccpav_buf_ackno = + av->dccpav_ack_ackno = av->dccpav_ack_seqno = ~0LLU; + av->dccpav_buf_nonce = av->dccpav_buf_nonce = 0; + av->dccpav_ack_ptr = 0; + av->dccpav_time.tv_sec = 0; + av->dccpav_time.tv_usec = 0; + av->dccpav_sent_len = av->dccpav_vec_len = 0; + } + + return av; +} + +void dccp_ackvec_free(struct dccp_ackvec *av) +{ + kfree(av); +} + +static inline u8 dccp_ackvec_state(const struct dccp_ackvec *av, + const unsigned int index) +{ + return av->dccpav_buf[index] & DCCP_ACKVEC_STATE_MASK; +} + +static inline u8 dccp_ackvec_len(const struct dccp_ackvec *av, + const unsigned int index) +{ + return av->dccpav_buf[index] & DCCP_ACKVEC_LEN_MASK; +} + +/* + * If several packets are missing, the HC-Receiver may prefer to enter multiple + * bytes with run length 0, rather than a single byte with a larger run length; + * this simplifies table updates if one of the missing packets arrives. + */ +static inline int dccp_ackvec_set_buf_head_state(struct dccp_ackvec *av, + const unsigned int packets, + const unsigned char state) +{ + unsigned int gap; + signed long new_head; + + if (av->dccpav_vec_len + packets > av->dccpav_buf_len) + return -ENOBUFS; + + gap = packets - 1; + new_head = av->dccpav_buf_head - packets; + + if (new_head < 0) { + if (gap > 0) { + memset(av->dccpav_buf, DCCP_ACKVEC_STATE_NOT_RECEIVED, + gap + new_head + 1); + gap = -new_head; + } + new_head += av->dccpav_buf_len; + } + + av->dccpav_buf_head = new_head; + + if (gap > 0) + memset(av->dccpav_buf + av->dccpav_buf_head + 1, + DCCP_ACKVEC_STATE_NOT_RECEIVED, gap); + + av->dccpav_buf[av->dccpav_buf_head] = state; + av->dccpav_vec_len += packets; + return 0; +} + +/* + * Implements the draft-ietf-dccp-spec-11.txt Appendix A + */ +int dccp_ackvec_add(struct dccp_ackvec *av, const struct sock *sk, + const u64 ackno, const u8 state) +{ + /* + * Check at the right places if the buffer is full, if it is, tell the + * caller to start dropping packets till the HC-Sender acks our ACK + * vectors, when we will free up space in dccpav_buf. + * + * We may well decide to do buffer compression, etc, but for now lets + * just drop. + * + * From Appendix A: + * + * Of course, the circular buffer may overflow, either when the + * HC-Sender is sending data at a very high rate, when the + * HC-Receiver's acknowledgements are not reaching the HC-Sender, + * or when the HC-Sender is forgetting to acknowledge those acks + * (so the HC-Receiver is unable to clean up old state). In this + * case, the HC-Receiver should either compress the buffer (by + * increasing run lengths when possible), transfer its state to + * a larger buffer, or, as a last resort, drop all received + * packets, without processing them whatsoever, until its buffer + * shrinks again. + */ + + /* See if this is the first ackno being inserted */ + if (av->dccpav_vec_len == 0) { + av->dccpav_buf[av->dccpav_buf_head] = state; + av->dccpav_vec_len = 1; + } else if (after48(ackno, av->dccpav_buf_ackno)) { + const u64 delta = dccp_delta_seqno(av->dccpav_buf_ackno, + ackno); + + /* + * Look if the state of this packet is the same as the + * previous ackno and if so if we can bump the head len. + */ + if (delta == 1 && + dccp_ackvec_state(av, av->dccpav_buf_head) == state && + (dccp_ackvec_len(av, av->dccpav_buf_head) < + DCCP_ACKVEC_LEN_MASK)) + av->dccpav_buf[av->dccpav_buf_head]++; + else if (dccp_ackvec_set_buf_head_state(av, delta, state)) + return -ENOBUFS; + } else { + /* + * A.1.2. Old Packets + * + * When a packet with Sequence Number S arrives, and + * S <= buf_ackno, the HC-Receiver will scan the table + * for the byte corresponding to S. (Indexing structures + * could reduce the complexity of this scan.) + */ + u64 delta = dccp_delta_seqno(ackno, av->dccpav_buf_ackno); + unsigned int index = av->dccpav_buf_head; + + while (1) { + const u8 len = dccp_ackvec_len(av, index); + const u8 state = dccp_ackvec_state(av, index); + /* + * valid packets not yet in dccpav_buf have a reserved + * entry, with a len equal to 0. + */ + if (state == DCCP_ACKVEC_STATE_NOT_RECEIVED && + len == 0 && delta == 0) { /* Found our + reserved seat! */ + dccp_pr_debug("Found %llu reserved seat!\n", + (unsigned long long)ackno); + av->dccpav_buf[index] = state; + goto out; + } + /* len == 0 means one packet */ + if (delta < len + 1) + goto out_duplicate; + + delta -= len + 1; + if (++index == av->dccpav_buf_len) + index = 0; + } + } + + av->dccpav_buf_ackno = ackno; + dccp_timestamp(sk, &av->dccpav_time); +out: + dccp_pr_debug(""); + return 0; + +out_duplicate: + /* Duplicate packet */ + dccp_pr_debug("Received a dup or already considered lost " + "packet: %llu\n", (unsigned long long)ackno); + return -EILSEQ; +} + +#ifdef CONFIG_IP_DCCP_DEBUG +void dccp_ackvector_print(const u64 ackno, const unsigned char *vector, int len) +{ + if (!dccp_debug) + return; + + printk("ACK vector len=%d, ackno=%llu |", len, + (unsigned long long)ackno); + + while (len--) { + const u8 state = (*vector & DCCP_ACKVEC_STATE_MASK) >> 6; + const u8 rl = *vector & DCCP_ACKVEC_LEN_MASK; + + printk("%d,%d|", state, rl); + ++vector; + } + + printk("\n"); +} + +void dccp_ackvec_print(const struct dccp_ackvec *av) +{ + dccp_ackvector_print(av->dccpav_buf_ackno, + av->dccpav_buf + av->dccpav_buf_head, + av->dccpav_vec_len); +} +#endif + +static void dccp_ackvec_trow_away_ack_record(struct dccp_ackvec *av) +{ + /* + * As we're keeping track of the ack vector size (dccpav_vec_len) and + * the sent ack vector size (dccpav_sent_len) we don't need + * dccpav_buf_tail at all, but keep this code here as in the future + * we'll implement a vector of ack records, as suggested in + * draft-ietf-dccp-spec-11.txt Appendix A. -acme + */ +#if 0 + av->dccpav_buf_tail = av->dccpav_ack_ptr + 1; + if (av->dccpav_buf_tail >= av->dccpav_vec_len) + av->dccpav_buf_tail -= av->dccpav_vec_len; +#endif + av->dccpav_vec_len -= av->dccpav_sent_len; +} + +void dccp_ackvec_check_rcv_ackno(struct dccp_ackvec *av, struct sock *sk, + const u64 ackno) +{ + /* Check if we actually sent an ACK vector */ + if (av->dccpav_ack_seqno == DCCP_MAX_SEQNO + 1) + return; + + if (ackno == av->dccpav_ack_seqno) { +#ifdef CONFIG_IP_DCCP_DEBUG + struct dccp_sock *dp = dccp_sk(sk); + const char *debug_prefix = dp->dccps_role == DCCP_ROLE_CLIENT ? + "CLIENT rx ack: " : "server rx ack: "; +#endif + dccp_pr_debug("%sACK packet 0, len=%d, ack_seqno=%llu, " + "ack_ackno=%llu, ACKED!\n", + debug_prefix, 1, + (unsigned long long)av->dccpav_ack_seqno, + (unsigned long long)av->dccpav_ack_ackno); + dccp_ackvec_trow_away_ack_record(av); + av->dccpav_ack_seqno = DCCP_MAX_SEQNO + 1; + } +} + +static void dccp_ackvec_check_rcv_ackvector(struct dccp_ackvec *av, + struct sock *sk, u64 ackno, + const unsigned char len, + const unsigned char *vector) +{ + unsigned char i; + + /* Check if we actually sent an ACK vector */ + if (av->dccpav_ack_seqno == DCCP_MAX_SEQNO + 1) + return; + /* + * We're in the receiver half connection, so if the received an ACK + * vector ackno (e.g. 50) before dccpav_ack_seqno (e.g. 52), we're + * not interested. + * + * Extra explanation with example: + * + * if we received an ACK vector with ackno 50, it can only be acking + * 50, 49, 48, etc, not 52 (the seqno for the ACK vector we sent). + */ + /* dccp_pr_debug("is %llu < %llu? ", ackno, av->dccpav_ack_seqno); */ + if (before48(ackno, av->dccpav_ack_seqno)) { + /* dccp_pr_debug_cat("yes\n"); */ + return; + } + /* dccp_pr_debug_cat("no\n"); */ + + i = len; + while (i--) { + const u8 rl = *vector & DCCP_ACKVEC_LEN_MASK; + u64 ackno_end_rl; + + dccp_set_seqno(&ackno_end_rl, ackno - rl); + + /* + * dccp_pr_debug("is %llu <= %llu <= %llu? ", ackno_end_rl, + * av->dccpav_ack_seqno, ackno); + */ + if (between48(av->dccpav_ack_seqno, ackno_end_rl, ackno)) { + const u8 state = (*vector & + DCCP_ACKVEC_STATE_MASK) >> 6; + /* dccp_pr_debug_cat("yes\n"); */ + + if (state != DCCP_ACKVEC_STATE_NOT_RECEIVED) { +#ifdef CONFIG_IP_DCCP_DEBUG + struct dccp_sock *dp = dccp_sk(sk); + const char *debug_prefix = + dp->dccps_role == DCCP_ROLE_CLIENT ? + "CLIENT rx ack: " : "server rx ack: "; +#endif + dccp_pr_debug("%sACK vector 0, len=%d, " + "ack_seqno=%llu, ack_ackno=%llu, " + "ACKED!\n", + debug_prefix, len, + (unsigned long long) + av->dccpav_ack_seqno, + (unsigned long long) + av->dccpav_ack_ackno); + dccp_ackvec_trow_away_ack_record(av); + } + /* + * If dccpav_ack_seqno was not received, no problem + * we'll send another ACK vector. + */ + av->dccpav_ack_seqno = DCCP_MAX_SEQNO + 1; + break; + } + /* dccp_pr_debug_cat("no\n"); */ + + dccp_set_seqno(&ackno, ackno_end_rl - 1); + ++vector; + } +} + +int dccp_ackvec_parse(struct sock *sk, const struct sk_buff *skb, + const u8 opt, const u8 *value, const u8 len) +{ + if (len > DCCP_MAX_ACKVEC_LEN) + return -1; + + /* dccp_ackvector_print(DCCP_SKB_CB(skb)->dccpd_ack_seq, value, len); */ + dccp_ackvec_check_rcv_ackvector(dccp_sk(sk)->dccps_hc_rx_ackvec, sk, + DCCP_SKB_CB(skb)->dccpd_ack_seq, + len, value); + return 0; +} diff --git a/net/dccp/ackvec.h b/net/dccp/ackvec.h new file mode 100644 index 0000000..8ca51c9 --- /dev/null +++ b/net/dccp/ackvec.h @@ -0,0 +1,133 @@ +#ifndef _ACKVEC_H +#define _ACKVEC_H +/* + * net/dccp/ackvec.h + * + * An implementation of the DCCP protocol + * Copyright (c) 2005 Arnaldo Carvalho de Melo <acme@mandriva.com> + * + * This program is free software; you can 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 <linux/config.h> +#include <linux/compiler.h> +#include <linux/time.h> +#include <linux/types.h> + +/* Read about the ECN nonce to see why it is 253 */ +#define DCCP_MAX_ACKVEC_LEN 253 + +#define DCCP_ACKVEC_STATE_RECEIVED 0 +#define DCCP_ACKVEC_STATE_ECN_MARKED (1 << 6) +#define DCCP_ACKVEC_STATE_NOT_RECEIVED (3 << 6) + +#define DCCP_ACKVEC_STATE_MASK 0xC0 /* 11000000 */ +#define DCCP_ACKVEC_LEN_MASK 0x3F /* 00111111 */ + +/** struct dccp_ackvec - ack vector + * + * This data structure is the one defined in the DCCP draft + * Appendix A. + * + * @dccpav_buf_head - circular buffer head + * @dccpav_buf_tail - circular buffer tail + * @dccpav_buf_ackno - ack # of the most recent packet acknowledgeable in the + * buffer (i.e. %dccpav_buf_head) + * @dccpav_buf_nonce - the one-bit sum of the ECN Nonces on all packets acked + * by the buffer with State 0 + * + * Additionally, the HC-Receiver must keep some information about the + * Ack Vectors it has recently sent. For each packet sent carrying an + * Ack Vector, it remembers four variables: + * + * @dccpav_ack_seqno - the Sequence Number used for the packet + * (HC-Receiver seqno) + * @dccpav_ack_ptr - the value of buf_head at the time of acknowledgement. + * @dccpav_ack_ackno - the Acknowledgement Number used for the packet + * (HC-Sender seqno) + * @dccpav_ack_nonce - the one-bit sum of the ECN Nonces for all State 0. + * + * @dccpav_buf_len - circular buffer length + * @dccpav_time - the time in usecs + * @dccpav_buf - circular buffer of acknowledgeable packets + */ +struct dccp_ackvec { + unsigned int dccpav_buf_head; + unsigned int dccpav_buf_tail; + u64 dccpav_buf_ackno; + u64 dccpav_ack_seqno; + u64 dccpav_ack_ackno; + unsigned int dccpav_ack_ptr; + unsigned int dccpav_sent_len; + unsigned int dccpav_vec_len; + unsigned int dccpav_buf_len; + struct timeval dccpav_time; + u8 dccpav_buf_nonce; + u8 dccpav_ack_nonce; + u8 dccpav_buf[0]; +}; + +struct sock; +struct sk_buff; + +#ifdef CONFIG_IP_DCCP_ACKVEC +extern struct dccp_ackvec *dccp_ackvec_alloc(unsigned int len, + const unsigned int __nocast priority); +extern void dccp_ackvec_free(struct dccp_ackvec *av); + +extern int dccp_ackvec_add(struct dccp_ackvec *av, const struct sock *sk, + const u64 ackno, const u8 state); + +extern void dccp_ackvec_check_rcv_ackno(struct dccp_ackvec *av, + struct sock *sk, const u64 ackno); +extern int dccp_ackvec_parse(struct sock *sk, const struct sk_buff *skb, + const u8 opt, const u8 *value, const u8 len); + +extern int dccp_insert_option_ackvec(struct sock *sk, struct sk_buff *skb); + +static inline int dccp_ackvec_pending(const struct dccp_ackvec *av) +{ + return av->dccpav_sent_len != av->dccpav_vec_len; +} +#else /* CONFIG_IP_DCCP_ACKVEC */ +static inline struct dccp_ackvec *dccp_ackvec_alloc(unsigned int len, + const unsigned int __nocast priority) +{ + return NULL; +} + +static inline void dccp_ackvec_free(struct dccp_ackvec *av) +{ +} + +static inline int dccp_ackvec_add(struct dccp_ackvec *av, const struct sock *sk, + const u64 ackno, const u8 state) +{ + return -1; +} + +static inline void dccp_ackvec_check_rcv_ackno(struct dccp_ackvec *av, + struct sock *sk, const u64 ackno) +{ +} + +static inline int dccp_ackvec_parse(struct sock *sk, const struct sk_buff *skb, + const u8 opt, const u8 *value, const u8 len) +{ + return -1; +} + +static inline int dccp_insert_option_ackvec(const struct sock *sk, + const struct sk_buff *skb) +{ + return -1; +} + +static inline int dccp_ackvec_pending(const struct dccp_ackvec *av) +{ + return 0; +} +#endif /* CONFIG_IP_DCCP_ACKVEC */ +#endif /* _ACKVEC_H */ diff --git a/net/dccp/ccid.h b/net/dccp/ccid.h index 962f1e9..21e5514 100644 --- a/net/dccp/ccid.h +++ b/net/dccp/ccid.h @@ -14,6 +14,7 @@ */ #include <net/sock.h> +#include <linux/compiler.h> #include <linux/dccp.h> #include <linux/list.h> #include <linux/module.h> @@ -54,6 +55,14 @@ struct ccid { struct tcp_info *info); void (*ccid_hc_tx_get_info)(struct sock *sk, struct tcp_info *info); + int (*ccid_hc_rx_getsockopt)(struct sock *sk, + const int optname, int len, + u32 __user *optval, + int __user *optlen); + int (*ccid_hc_tx_getsockopt)(struct sock *sk, + const int optname, int len, + u32 __user *optval, + int __user *optlen); }; extern int ccid_register(struct ccid *ccid); @@ -177,4 +186,26 @@ static inline void ccid_hc_tx_get_info(struct ccid *ccid, struct sock *sk, if (ccid->ccid_hc_tx_get_info != NULL) ccid->ccid_hc_tx_get_info(sk, info); } + +static inline int ccid_hc_rx_getsockopt(struct ccid *ccid, struct sock *sk, + const int optname, int len, + u32 __user *optval, int __user *optlen) +{ + int rc = -ENOPROTOOPT; + if (ccid->ccid_hc_rx_getsockopt != NULL) + rc = ccid->ccid_hc_rx_getsockopt(sk, optname, len, + optval, optlen); + return rc; +} + +static inline int ccid_hc_tx_getsockopt(struct ccid *ccid, struct sock *sk, + const int optname, int len, + u32 __user *optval, int __user *optlen) +{ + int rc = -ENOPROTOOPT; + if (ccid->ccid_hc_tx_getsockopt != NULL) + rc = ccid->ccid_hc_tx_getsockopt(sk, optname, len, + optval, optlen); + return rc; +} #endif /* _CCID_H */ diff --git a/net/dccp/ccids/ccid3.c b/net/dccp/ccids/ccid3.c index 38aa849..aa68e0a 100644 --- a/net/dccp/ccids/ccid3.c +++ b/net/dccp/ccids/ccid3.c @@ -1120,6 +1120,60 @@ static void ccid3_hc_tx_get_info(struct sock *sk, struct tcp_info *info) info->tcpi_rtt = hctx->ccid3hctx_rtt; } +static int ccid3_hc_rx_getsockopt(struct sock *sk, const int optname, int len, + u32 __user *optval, int __user *optlen) +{ + const struct ccid3_hc_rx_sock *hcrx = ccid3_hc_rx_sk(sk); + const void *val; + + /* Listen socks doesn't have a private CCID block */ + if (sk->sk_state == DCCP_LISTEN) + return -EINVAL; + + switch (optname) { + case DCCP_SOCKOPT_CCID_RX_INFO: + if (len < sizeof(hcrx->ccid3hcrx_tfrc)) + return -EINVAL; + len = sizeof(hcrx->ccid3hcrx_tfrc); + val = &hcrx->ccid3hcrx_tfrc; + break; + default: + return -ENOPROTOOPT; + } + + if (put_user(len, optlen) || copy_to_user(optval, val, len)) + return -EFAULT; + + return 0; +} + +static int ccid3_hc_tx_getsockopt(struct sock *sk, const int optname, int len, + u32 __user *optval, int __user *optlen) +{ + const struct ccid3_hc_tx_sock *hctx = ccid3_hc_tx_sk(sk); + const void *val; + + /* Listen socks doesn't have a private CCID block */ + if (sk->sk_state == DCCP_LISTEN) + return -EINVAL; + + switch (optname) { + case DCCP_SOCKOPT_CCID_TX_INFO: + if (len < sizeof(hctx->ccid3hctx_tfrc)) + return -EINVAL; + len = sizeof(hctx->ccid3hctx_tfrc); + val = &hctx->ccid3hctx_tfrc; + break; + default: + return -ENOPROTOOPT; + } + + if (put_user(len, optlen) || copy_to_user(optval, val, len)) + return -EFAULT; + + return 0; +} + static struct ccid ccid3 = { .ccid_id = 3, .ccid_name = "ccid3", @@ -1139,6 +1193,8 @@ static struct ccid ccid3 = { .ccid_hc_rx_packet_recv = ccid3_hc_rx_packet_recv, .ccid_hc_rx_get_info = ccid3_hc_rx_get_info, .ccid_hc_tx_get_info = ccid3_hc_tx_get_info, + .ccid_hc_rx_getsockopt = ccid3_hc_rx_getsockopt, + .ccid_hc_tx_getsockopt = ccid3_hc_tx_getsockopt, }; module_param(ccid3_debug, int, 0444); diff --git a/net/dccp/ccids/ccid3.h b/net/dccp/ccids/ccid3.h index eb24877..0bde458 100644 --- a/net/dccp/ccids/ccid3.h +++ b/net/dccp/ccids/ccid3.h @@ -40,6 +40,7 @@ #include <linux/list.h> #include <linux/time.h> #include <linux/types.h> +#include <linux/tfrc.h> #define TFRC_MIN_PACKET_SIZE 16 #define TFRC_STD_PACKET_SIZE 256 @@ -93,12 +94,15 @@ struct ccid3_options_received { * @ccid3hctx_hist - Packet history */ struct ccid3_hc_tx_sock { - u32 ccid3hctx_x; - u32 ccid3hctx_x_recv; - u32 ccid3hctx_x_calc; + struct tfrc_tx_info ccid3hctx_tfrc; +#define ccid3hctx_x ccid3hctx_tfrc.tfrctx_x +#define ccid3hctx_x_recv ccid3hctx_tfrc.tfrctx_x_recv +#define ccid3hctx_x_calc ccid3hctx_tfrc.tfrctx_x_calc +#define ccid3hctx_rtt ccid3hctx_tfrc.tfrctx_rtt +#define ccid3hctx_p ccid3hctx_tfrc.tfrctx_p +#define ccid3hctx_t_rto ccid3hctx_tfrc.tfrctx_rto +#define ccid3hctx_t_ipi ccid3hctx_tfrc.tfrctx_ipi u16 ccid3hctx_s; - u32 ccid3hctx_rtt; - u32 ccid3hctx_p; u8 ccid3hctx_state; u8 ccid3hctx_last_win_count; u8 ccid3hctx_idle; @@ -106,19 +110,19 @@ struct ccid3_hc_tx_sock { struct timer_list ccid3hctx_no_feedback_timer; struct timeval ccid3hctx_t_ld; struct timeval ccid3hctx_t_nom; - u32 ccid3hctx_t_rto; - u32 ccid3hctx_t_ipi; u32 ccid3hctx_delta; struct list_head ccid3hctx_hist; struct ccid3_options_received ccid3hctx_options_received; }; struct ccid3_hc_rx_sock { + struct tfrc_rx_info ccid3hcrx_tfrc; +#define ccid3hcrx_x_recv ccid3hcrx_tfrc.tfrcrx_x_recv +#define ccid3hcrx_rtt ccid3hcrx_tfrc.tfrcrx_rtt +#define ccid3hcrx_p ccid3hcrx_tfrc.tfrcrx_p u64 ccid3hcrx_seqno_last_counter:48, ccid3hcrx_state:8, ccid3hcrx_last_counter:4; - u32 ccid3hcrx_rtt; - u32 ccid3hcrx_p; u32 ccid3hcrx_bytes_recv; struct timeval ccid3hcrx_tstamp_last_feedback; struct timeval ccid3hcrx_tstamp_last_ack; @@ -127,7 +131,6 @@ struct ccid3_hc_rx_sock { u16 ccid3hcrx_s; u32 ccid3hcrx_pinv; u32 ccid3hcrx_elapsed_time; - u32 ccid3hcrx_x_recv; }; static inline struct ccid3_hc_tx_sock *ccid3_hc_tx_sk(const struct sock *sk) diff --git a/net/dccp/dccp.h b/net/dccp/dccp.h index 95c4630b..5871c02 100644 --- a/net/dccp/dccp.h +++ b/net/dccp/dccp.h @@ -17,6 +17,7 @@ #include <net/snmp.h> #include <net/sock.h> #include <net/tcp.h> +#include "ackvec.h" #ifdef CONFIG_IP_DCCP_DEBUG extern int dccp_debug; @@ -258,13 +259,12 @@ extern int dccp_v4_send_reset(struct sock *sk, extern void dccp_send_close(struct sock *sk, const int active); struct dccp_skb_cb { - __u8 dccpd_type; - __u8 dccpd_reset_code; - __u8 dccpd_service; - __u8 dccpd_ccval; + __u8 dccpd_type:4; + __u8 dccpd_ccval:4; + __u8 dccpd_reset_code; + __u16 dccpd_opt_len; __u64 dccpd_seq; __u64 dccpd_ack_seq; - int dccpd_opt_len; }; #define DCCP_SKB_CB(__skb) ((struct dccp_skb_cb *)&((__skb)->cb[0])) @@ -359,6 +359,17 @@ static inline void dccp_update_gss(struct sock *sk, u64 seq) (dp->dccps_gss - dp->dccps_options.dccpo_sequence_window + 1)); } + +static inline int dccp_ack_pending(const struct sock *sk) +{ + const struct dccp_sock *dp = dccp_sk(sk); + return dp->dccps_timestamp_echo != 0 || +#ifdef CONFIG_IP_DCCP_ACKVEC + (dp->dccps_options.dccpo_send_ack_vector && + dccp_ackvec_pending(dp->dccps_hc_rx_ackvec)) || +#endif + inet_csk_ack_scheduled(sk); +} extern void dccp_insert_options(struct sock *sk, struct sk_buff *skb); extern void dccp_insert_option_elapsed_time(struct sock *sk, @@ -372,65 +383,6 @@ extern void dccp_insert_option(struct sock *sk, struct sk_buff *skb, extern struct socket *dccp_ctl_socket; -#define DCCP_ACKPKTS_STATE_RECEIVED 0 -#define DCCP_ACKPKTS_STATE_ECN_MARKED (1 << 6) -#define DCCP_ACKPKTS_STATE_NOT_RECEIVED (3 << 6) - -#define DCCP_ACKPKTS_STATE_MASK 0xC0 /* 11000000 */ -#define DCCP_ACKPKTS_LEN_MASK 0x3F /* 00111111 */ - -/** struct dccp_ackpkts - acknowledgeable packets - * - * This data structure is the one defined in the DCCP draft - * Appendix A. - * - * @dccpap_buf_head - circular buffer head - * @dccpap_buf_tail - circular buffer tail - * @dccpap_buf_ackno - ack # of the most recent packet acknowledgeable in the - * buffer (i.e. %dccpap_buf_head) - * @dccpap_buf_nonce - the one-bit sum of the ECN Nonces on all packets acked - * by the buffer with State 0 - * - * Additionally, the HC-Receiver must keep some information about the - * Ack Vectors it has recently sent. For each packet sent carrying an - * Ack Vector, it remembers four variables: - * - * @dccpap_ack_seqno - the Sequence Number used for the packet - * (HC-Receiver seqno) - * @dccpap_ack_ptr - the value of buf_head at the time of acknowledgement. - * @dccpap_ack_ackno - the Acknowledgement Number used for the packet - * (HC-Sender seqno) - * @dccpap_ack_nonce - the one-bit sum of the ECN Nonces for all State 0. - * - * @dccpap_buf_len - circular buffer length - * @dccpap_time - the time in usecs - * @dccpap_buf - circular buffer of acknowledgeable packets - */ -struct dccp_ackpkts { - unsigned int dccpap_buf_head; - unsigned int dccpap_buf_tail; - u64 dccpap_buf_ackno; - u64 dccpap_ack_seqno; - u64 dccpap_ack_ackno; - unsigned int dccpap_ack_ptr; - unsigned int dccpap_buf_vector_len; - unsigned int dccpap_ack_vector_len; - unsigned int dccpap_buf_len; - struct timeval dccpap_time; - u8 dccpap_buf_nonce; - u8 dccpap_ack_nonce; - u8 dccpap_buf[0]; -}; - -extern struct dccp_ackpkts * - dccp_ackpkts_alloc(unsigned int len, - const unsigned int __nocast priority); -extern void dccp_ackpkts_free(struct dccp_ackpkts *ap); -extern int dccp_ackpkts_add(struct dccp_ackpkts *ap, const struct sock *sk, - u64 ackno, u8 state); -extern void dccp_ackpkts_check_rcv_ackno(struct dccp_ackpkts *ap, - struct sock *sk, u64 ackno); - extern void dccp_timestamp(const struct sock *sk, struct timeval *tv); static inline suseconds_t timeval_usecs(const struct timeval *tv) @@ -471,15 +423,4 @@ static inline void timeval_sub_usecs(struct timeval *tv, } } -#ifdef CONFIG_IP_DCCP_DEBUG -extern void dccp_ackvector_print(const u64 ackno, - const unsigned char *vector, int len); -extern void dccp_ackpkts_print(const struct dccp_ackpkts *ap); -#else -static inline void dccp_ackvector_print(const u64 ackno, - const unsigned char *vector, - int len) { } -static inline void dccp_ackpkts_print(const struct dccp_ackpkts *ap) { } -#endif - #endif /* _DCCP_H */ diff --git a/net/dccp/input.c b/net/dccp/input.c index c60bc34..1b6b2cb 100644 --- a/net/dccp/input.c +++ b/net/dccp/input.c @@ -16,6 +16,7 @@ #include <net/sock.h> +#include "ackvec.h" #include "ccid.h" #include "dccp.h" @@ -50,7 +51,8 @@ static void dccp_rcv_closereq(struct sock *sk, struct sk_buff *skb) return; } - dccp_set_state(sk, DCCP_CLOSING); + if (sk->sk_state != DCCP_CLOSING) + dccp_set_state(sk, DCCP_CLOSING); dccp_send_close(sk, 0); } @@ -59,8 +61,8 @@ static inline void dccp_event_ack_recv(struct sock *sk, struct sk_buff *skb) struct dccp_sock *dp = dccp_sk(sk); if (dp->dccps_options.dccpo_send_ack_vector) - dccp_ackpkts_check_rcv_ackno(dp->dccps_hc_rx_ackpkts, sk, - DCCP_SKB_CB(skb)->dccpd_ack_seq); + dccp_ackvec_check_rcv_ackno(dp->dccps_hc_rx_ackvec, sk, + DCCP_SKB_CB(skb)->dccpd_ack_seq); } static int dccp_check_seqno(struct sock *sk, struct sk_buff *skb) @@ -163,37 +165,11 @@ int dccp_rcv_established(struct sock *sk, struct sk_buff *skb, if (DCCP_SKB_CB(skb)->dccpd_ack_seq != DCCP_PKT_WITHOUT_ACK_SEQ) dccp_event_ack_recv(sk, skb); - /* - * FIXME: check ECN to see if we should use - * DCCP_ACKPKTS_STATE_ECN_MARKED - */ - if (dp->dccps_options.dccpo_send_ack_vector) { - struct dccp_ackpkts *ap = dp->dccps_hc_rx_ackpkts; - - if (dccp_ackpkts_add(dp->dccps_hc_rx_ackpkts, sk, - DCCP_SKB_CB(skb)->dccpd_seq, - DCCP_ACKPKTS_STATE_RECEIVED)) { - LIMIT_NETDEBUG(KERN_WARNING "DCCP: acknowledgeable " - "packets buffer full!\n"); - ap->dccpap_ack_seqno = DCCP_MAX_SEQNO + 1; - inet_csk_schedule_ack(sk); - inet_csk_reset_xmit_timer(sk, ICSK_TIME_DACK, - TCP_DELACK_MIN, - DCCP_RTO_MAX); - goto discard; - } - - /* - * FIXME: this activation is probably wrong, have to study more - * TCP delack machinery and how it fits into DCCP draft, but - * for now it kinda "works" 8) - */ - if (!inet_csk_ack_scheduled(sk)) { - inet_csk_schedule_ack(sk); - inet_csk_reset_xmit_timer(sk, ICSK_TIME_DACK, 5 * HZ, - DCCP_RTO_MAX); - } - } + if (dp->dccps_options.dccpo_send_ack_vector && + dccp_ackvec_add(dp->dccps_hc_rx_ackvec, sk, + DCCP_SKB_CB(skb)->dccpd_seq, + DCCP_ACKVEC_STATE_RECEIVED)) + goto discard; ccid_hc_rx_packet_recv(dp->dccps_hc_rx_ccid, sk, skb); ccid_hc_tx_packet_recv(dp->dccps_hc_tx_ccid, sk, skb); @@ -383,9 +359,9 @@ static int dccp_rcv_request_sent_state_process(struct sock *sk, } out_invalid_packet: - return 1; /* dccp_v4_do_rcv will send a reset, but... - FIXME: the reset code should be - DCCP_RESET_CODE_PACKET_ERROR */ + /* dccp_v4_do_rcv will send a reset */ + DCCP_SKB_CB(skb)->dccpd_reset_code = DCCP_RESET_CODE_PACKET_ERROR; + return 1; } static int dccp_rcv_respond_partopen_state_process(struct sock *sk, @@ -432,6 +408,7 @@ int dccp_rcv_state_process(struct sock *sk, struct sk_buff *skb, struct dccp_hdr *dh, unsigned len) { struct dccp_sock *dp = dccp_sk(sk); + struct dccp_skb_cb *dcb = DCCP_SKB_CB(skb); const int old_state = sk->sk_state; int queued = 0; @@ -472,7 +449,8 @@ int dccp_rcv_state_process(struct sock *sk, struct sk_buff *skb, if (dh->dccph_type == DCCP_PKT_RESET) goto discard; - /* Caller (dccp_v4_do_rcv) will send Reset(No Connection)*/ + /* Caller (dccp_v4_do_rcv) will send Reset */ + dcb->dccpd_reset_code = DCCP_RESET_CODE_NO_CONNECTION; return 1; } @@ -486,36 +464,17 @@ int dccp_rcv_state_process(struct sock *sk, struct sk_buff *skb, if (dccp_parse_options(sk, skb)) goto discard; - if (DCCP_SKB_CB(skb)->dccpd_ack_seq != - DCCP_PKT_WITHOUT_ACK_SEQ) + if (dcb->dccpd_ack_seq != DCCP_PKT_WITHOUT_ACK_SEQ) dccp_event_ack_recv(sk, skb); ccid_hc_rx_packet_recv(dp->dccps_hc_rx_ccid, sk, skb); ccid_hc_tx_packet_recv(dp->dccps_hc_tx_ccid, sk, skb); - /* - * FIXME: check ECN to see if we should use - * DCCP_ACKPKTS_STATE_ECN_MARKED - */ - if (dp->dccps_options.dccpo_send_ack_vector) { - if (dccp_ackpkts_add(dp->dccps_hc_rx_ackpkts, sk, - DCCP_SKB_CB(skb)->dccpd_seq, - DCCP_ACKPKTS_STATE_RECEIVED)) - goto discard; - /* - * FIXME: this activation is probably wrong, have to - * study more TCP delack machinery and how it fits into - * DCCP draft, but for now it kinda "works" 8) - */ - if ((dp->dccps_hc_rx_ackpkts->dccpap_ack_seqno == - DCCP_MAX_SEQNO + 1) && - !inet_csk_ack_scheduled(sk)) { - inet_csk_schedule_ack(sk); - inet_csk_reset_xmit_timer(sk, ICSK_TIME_DACK, - TCP_DELACK_MIN, - DCCP_RTO_MAX); - } - } + if (dp->dccps_options.dccpo_send_ack_vector && + dccp_ackvec_add(dp->dccps_hc_rx_ackvec, sk, + DCCP_SKB_CB(skb)->dccpd_seq, + DCCP_ACKVEC_STATE_RECEIVED)) + goto discard; } /* @@ -550,8 +509,7 @@ int dccp_rcv_state_process(struct sock *sk, struct sk_buff *skb, dh->dccph_type == DCCP_PKT_REQUEST) || (sk->sk_state == DCCP_RESPOND && dh->dccph_type == DCCP_PKT_DATA)) { - dccp_send_sync(sk, DCCP_SKB_CB(skb)->dccpd_seq, - DCCP_PKT_SYNC); + dccp_send_sync(sk, dcb->dccpd_seq, DCCP_PKT_SYNC); goto discard; } else if (dh->dccph_type == DCCP_PKT_CLOSEREQ) { dccp_rcv_closereq(sk, skb); @@ -561,8 +519,14 @@ int dccp_rcv_state_process(struct sock *sk, struct sk_buff *skb, return 0; } + if (unlikely(dh->dccph_type == DCCP_PKT_SYNC)) { + dccp_send_sync(sk, dcb->dccpd_seq, DCCP_PKT_SYNCACK); + goto discard; + } + switch (sk->sk_state) { case DCCP_CLOSED: + dcb->dccpd_reset_code = DCCP_RESET_CODE_NO_CONNECTION; return 1; case DCCP_REQUESTING: diff --git a/net/dccp/ipv4.c b/net/dccp/ipv4.c index 2afaa46..40fe6af 100644 --- a/net/dccp/ipv4.c +++ b/net/dccp/ipv4.c @@ -23,6 +23,7 @@ #include <net/tcp_states.h> #include <net/xfrm.h> +#include "ackvec.h" #include "ccid.h" #include "dccp.h" @@ -246,6 +247,9 @@ static int dccp_v4_connect(struct sock *sk, struct sockaddr *uaddr, dp->dccps_role = DCCP_ROLE_CLIENT; + if (dccp_service_not_initialized(sk)) + return -EPROTO; + if (addr_len < sizeof(struct sockaddr_in)) return -EINVAL; @@ -661,6 +665,16 @@ static inline u64 dccp_v4_init_sequence(const struct sock *sk, dccp_hdr(skb)->dccph_sport); } +static inline int dccp_bad_service_code(const struct sock *sk, + const __u32 service) +{ + const struct dccp_sock *dp = dccp_sk(sk); + + if (dp->dccps_service == service) + return 0; + return !dccp_list_has_service(dp->dccps_service_list, service); +} + int dccp_v4_conn_request(struct sock *sk, struct sk_buff *skb) { struct inet_request_sock *ireq; @@ -669,13 +683,22 @@ int dccp_v4_conn_request(struct sock *sk, struct sk_buff *skb) struct dccp_request_sock *dreq; const __u32 saddr = skb->nh.iph->saddr; const __u32 daddr = skb->nh.iph->daddr; + const __u32 service = dccp_hdr_request(skb)->dccph_req_service; + struct dccp_skb_cb *dcb = DCCP_SKB_CB(skb); + __u8 reset_code = DCCP_RESET_CODE_TOO_BUSY; struct dst_entry *dst = NULL; /* Never answer to DCCP_PKT_REQUESTs send to broadcast or multicast */ if (((struct rtable *)skb->dst)->rt_flags & - (RTCF_BROADCAST | RTCF_MULTICAST)) + (RTCF_BROADCAST | RTCF_MULTICAST)) { + reset_code = DCCP_RESET_CODE_NO_CONNECTION; goto drop; + } + if (dccp_bad_service_code(sk, service)) { + reset_code = DCCP_RESET_CODE_BAD_SERVICE_CODE; + goto drop; + } /* * TW buckets are converted to open requests without * limitations, they conserve resources and peer is @@ -718,9 +741,9 @@ int dccp_v4_conn_request(struct sock *sk, struct sk_buff *skb) * dccp_create_openreq_child. */ dreq = dccp_rsk(req); - dreq->dreq_isr = DCCP_SKB_CB(skb)->dccpd_seq; - dreq->dreq_iss = dccp_v4_init_sequence(sk, skb); - dreq->dreq_service = dccp_hdr_request(skb)->dccph_req_service; + dreq->dreq_isr = dcb->dccpd_seq; + dreq->dreq_iss = dccp_v4_init_sequence(sk, skb); + dreq->dreq_service = service; if (dccp_v4_send_response(sk, req, dst)) goto drop_and_free; @@ -735,6 +758,7 @@ drop_and_free: __reqsk_free(req); drop: DCCP_INC_STATS_BH(DCCP_MIB_ATTEMPTFAILS); + dcb->dccpd_reset_code = reset_code; return -1; } @@ -1005,7 +1029,6 @@ int dccp_v4_do_rcv(struct sock *sk, struct sk_buff *skb) return 0; reset: - DCCP_SKB_CB(skb)->dccpd_reset_code = DCCP_RESET_CODE_NO_CONNECTION; dccp_v4_ctl_send_reset(skb); discard: kfree_skb(skb); @@ -1090,45 +1113,7 @@ int dccp_v4_rcv(struct sk_buff *skb) goto discard_it; dh = dccp_hdr(skb); -#if 0 - /* - * Use something like this to simulate some DATA/DATAACK loss to test - * dccp_ackpkts_add, you'll get something like this on a session that - * sends 10 DATA/DATAACK packets: - * - * ackpkts_print: 281473596467422 |0,0|3,0|0,0|3,0|0,0|3,0|0,0|3,0|0,1| - * - * 0, 0 means: DCCP_ACKPKTS_STATE_RECEIVED, RLE == just this packet - * 0, 1 means: DCCP_ACKPKTS_STATE_RECEIVED, RLE == two adjacent packets - * with the same state - * 3, 0 means: DCCP_ACKPKTS_STATE_NOT_RECEIVED, RLE == just this packet - * - * So... - * - * 281473596467422 was received - * 281473596467421 was not received - * 281473596467420 was received - * 281473596467419 was not received - * 281473596467418 was received - * 281473596467417 was not received - * 281473596467416 was received - * 281473596467415 was not received - * 281473596467414 was received - * 281473596467413 was received (this one was the 3way handshake - * RESPONSE) - * - */ - if (dh->dccph_type == DCCP_PKT_DATA || - dh->dccph_type == DCCP_PKT_DATAACK) { - static int discard = 0; - if (discard) { - discard = 0; - goto discard_it; - } - discard = 1; - } -#endif DCCP_SKB_CB(skb)->dccpd_seq = dccp_hdr_seq(skb); DCCP_SKB_CB(skb)->dccpd_type = dh->dccph_type; @@ -1242,11 +1227,9 @@ static int dccp_v4_init_sock(struct sock *sk) do_gettimeofday(&dp->dccps_epoch); if (dp->dccps_options.dccpo_send_ack_vector) { - dp->dccps_hc_rx_ackpkts = - dccp_ackpkts_alloc(DCCP_MAX_ACK_VECTOR_LEN, - GFP_KERNEL); - - if (dp->dccps_hc_rx_ackpkts == NULL) + dp->dccps_hc_rx_ackvec = dccp_ackvec_alloc(DCCP_MAX_ACKVEC_LEN, + GFP_KERNEL); + if (dp->dccps_hc_rx_ackvec == NULL) return -ENOMEM; } @@ -1258,16 +1241,18 @@ static int dccp_v4_init_sock(struct sock *sk) * setsockopt(CCIDs-I-want/accept). -acme */ if (likely(!dccp_ctl_socket_init)) { - dp->dccps_hc_rx_ccid = ccid_init(dp->dccps_options.dccpo_ccid, + dp->dccps_hc_rx_ccid = ccid_init(dp->dccps_options.dccpo_rx_ccid, sk); - dp->dccps_hc_tx_ccid = ccid_init(dp->dccps_options.dccpo_ccid, + dp->dccps_hc_tx_ccid = ccid_init(dp->dccps_options.dccpo_tx_ccid, sk); if (dp->dccps_hc_rx_ccid == NULL || dp->dccps_hc_tx_ccid == NULL) { ccid_exit(dp->dccps_hc_rx_ccid, sk); ccid_exit(dp->dccps_hc_tx_ccid, sk); - dccp_ackpkts_free(dp->dccps_hc_rx_ackpkts); - dp->dccps_hc_rx_ackpkts = NULL; + if (dp->dccps_options.dccpo_send_ack_vector) { + dccp_ackvec_free(dp->dccps_hc_rx_ackvec); + dp->dccps_hc_rx_ackvec = NULL; + } dp->dccps_hc_rx_ccid = dp->dccps_hc_tx_ccid = NULL; return -ENOMEM; } @@ -1280,6 +1265,7 @@ static int dccp_v4_init_sock(struct sock *sk) sk->sk_write_space = dccp_write_space; dp->dccps_mss_cache = 536; dp->dccps_role = DCCP_ROLE_UNDEFINED; + dp->dccps_service = DCCP_SERVICE_INVALID_VALUE; return 0; } @@ -1301,10 +1287,17 @@ static int dccp_v4_destroy_sock(struct sock *sk) if (inet_csk(sk)->icsk_bind_hash != NULL) inet_put_port(&dccp_hashinfo, sk); + if (dp->dccps_service_list != NULL) { + kfree(dp->dccps_service_list); + dp->dccps_service_list = NULL; + } + ccid_hc_rx_exit(dp->dccps_hc_rx_ccid, sk); ccid_hc_tx_exit(dp->dccps_hc_tx_ccid, sk); - dccp_ackpkts_free(dp->dccps_hc_rx_ackpkts); - dp->dccps_hc_rx_ackpkts = NULL; + if (dp->dccps_options.dccpo_send_ack_vector) { + dccp_ackvec_free(dp->dccps_hc_rx_ackvec); + dp->dccps_hc_rx_ackvec = NULL; + } ccid_exit(dp->dccps_hc_rx_ccid, sk); ccid_exit(dp->dccps_hc_tx_ccid, sk); dp->dccps_hc_rx_ccid = dp->dccps_hc_tx_ccid = NULL; diff --git a/net/dccp/minisocks.c b/net/dccp/minisocks.c index 18461bc..1393461 100644 --- a/net/dccp/minisocks.c +++ b/net/dccp/minisocks.c @@ -19,6 +19,7 @@ #include <net/xfrm.h> #include <net/inet_timewait_sock.h> +#include "ackvec.h" #include "ccid.h" #include "dccp.h" @@ -93,22 +94,24 @@ struct sock *dccp_create_openreq_child(struct sock *sk, struct inet_connection_sock *newicsk = inet_csk(sk); struct dccp_sock *newdp = dccp_sk(newsk); - newdp->dccps_hc_rx_ackpkts = NULL; - newdp->dccps_role = DCCP_ROLE_SERVER; - newicsk->icsk_rto = DCCP_TIMEOUT_INIT; + newdp->dccps_role = DCCP_ROLE_SERVER; + newdp->dccps_hc_rx_ackvec = NULL; + newdp->dccps_service_list = NULL; + newdp->dccps_service = dreq->dreq_service; + newicsk->icsk_rto = DCCP_TIMEOUT_INIT; do_gettimeofday(&newdp->dccps_epoch); if (newdp->dccps_options.dccpo_send_ack_vector) { - newdp->dccps_hc_rx_ackpkts = - dccp_ackpkts_alloc(DCCP_MAX_ACK_VECTOR_LEN, - GFP_ATOMIC); + newdp->dccps_hc_rx_ackvec = + dccp_ackvec_alloc(DCCP_MAX_ACKVEC_LEN, + GFP_ATOMIC); /* * XXX: We're using the same CCIDs set on the parent, * i.e. sk_clone copied the master sock and left the * CCID pointers for this child, that is why we do the * __ccid_get calls. */ - if (unlikely(newdp->dccps_hc_rx_ackpkts == NULL)) + if (unlikely(newdp->dccps_hc_rx_ackvec == NULL)) goto out_free; } @@ -116,7 +119,7 @@ struct sock *dccp_create_openreq_child(struct sock *sk, newsk) != 0 || ccid_hc_tx_init(newdp->dccps_hc_tx_ccid, newsk) != 0)) { - dccp_ackpkts_free(newdp->dccps_hc_rx_ackpkts); + dccp_ackvec_free(newdp->dccps_hc_rx_ackvec); ccid_hc_rx_exit(newdp->dccps_hc_rx_ccid, newsk); ccid_hc_tx_exit(newdp->dccps_hc_tx_ccid, newsk); out_free: diff --git a/net/dccp/options.c b/net/dccp/options.c index d4c4242..0a76426 100644 --- a/net/dccp/options.c +++ b/net/dccp/options.c @@ -18,19 +18,15 @@ #include <linux/kernel.h> #include <linux/skbuff.h> +#include "ackvec.h" #include "ccid.h" #include "dccp.h" -static void dccp_ackpkts_check_rcv_ackvector(struct dccp_ackpkts *ap, - struct sock *sk, - const u64 ackno, - const unsigned char len, - const unsigned char *vector); - /* stores the default values for new connection. may be changed with sysctl */ static const struct dccp_options dccpo_default_values = { .dccpo_sequence_window = DCCPF_INITIAL_SEQUENCE_WINDOW, - .dccpo_ccid = DCCPF_INITIAL_CCID, + .dccpo_rx_ccid = DCCPF_INITIAL_CCID, + .dccpo_tx_ccid = DCCPF_INITIAL_CCID, .dccpo_send_ack_vector = DCCPF_INITIAL_SEND_ACK_VECTOR, .dccpo_send_ndp_count = DCCPF_INITIAL_SEND_NDP_COUNT, }; @@ -113,25 +109,13 @@ int dccp_parse_options(struct sock *sk, struct sk_buff *skb) opt_recv->dccpor_ndp); break; case DCCPO_ACK_VECTOR_0: - if (len > DCCP_MAX_ACK_VECTOR_LEN) - goto out_invalid_option; - + case DCCPO_ACK_VECTOR_1: if (pkt_type == DCCP_PKT_DATA) continue; - opt_recv->dccpor_ack_vector_len = len; - opt_recv->dccpor_ack_vector_idx = value - options; - - dccp_pr_debug("%sACK vector 0, len=%d, ack_ackno=%llu\n", - debug_prefix, len, - (unsigned long long) - DCCP_SKB_CB(skb)->dccpd_ack_seq); - dccp_ackvector_print(DCCP_SKB_CB(skb)->dccpd_ack_seq, - value, len); - dccp_ackpkts_check_rcv_ackvector(dp->dccps_hc_rx_ackpkts, - sk, - DCCP_SKB_CB(skb)->dccpd_ack_seq, - len, value); + if (dp->dccps_options.dccpo_send_ack_vector && + dccp_ackvec_parse(sk, skb, opt, value, len)) + goto out_invalid_option; break; case DCCPO_TIMESTAMP: if (len != 4) @@ -352,86 +336,6 @@ void dccp_insert_option_elapsed_time(struct sock *sk, EXPORT_SYMBOL_GPL(dccp_insert_option_elapsed_time); -static void dccp_insert_option_ack_vector(struct sock *sk, struct sk_buff *skb) -{ - struct dccp_sock *dp = dccp_sk(sk); -#ifdef CONFIG_IP_DCCP_DEBUG - const char *debug_prefix = dp->dccps_role == DCCP_ROLE_CLIENT ? - "CLIENT TX opt: " : "server TX opt: "; -#endif - struct dccp_ackpkts *ap = dp->dccps_hc_rx_ackpkts; - int len = ap->dccpap_buf_vector_len + 2; - struct timeval now; - u32 elapsed_time; - unsigned char *to, *from; - - dccp_timestamp(sk, &now); - elapsed_time = timeval_delta(&now, &ap->dccpap_time) / 10; - - if (elapsed_time != 0) - dccp_insert_option_elapsed_time(sk, skb, elapsed_time); - - if (DCCP_SKB_CB(skb)->dccpd_opt_len + len > DCCP_MAX_OPT_LEN) { - LIMIT_NETDEBUG(KERN_INFO "DCCP: packet too small to " - "insert ACK Vector!\n"); - return; - } - - /* - * XXX: now we have just one ack vector sent record, so - * we have to wait for it to be cleared. - * - * Of course this is not acceptable, but this is just for - * basic testing now. - */ - if (ap->dccpap_ack_seqno != DCCP_MAX_SEQNO + 1) - return; - - DCCP_SKB_CB(skb)->dccpd_opt_len += len; - - to = skb_push(skb, len); - *to++ = DCCPO_ACK_VECTOR_0; - *to++ = len; - - len = ap->dccpap_buf_vector_len; - from = ap->dccpap_buf + ap->dccpap_buf_head; - - /* Check if buf_head wraps */ - if (ap->dccpap_buf_head + len > ap->dccpap_buf_len) { - const unsigned int tailsize = (ap->dccpap_buf_len - - ap->dccpap_buf_head); - - memcpy(to, from, tailsize); - to += tailsize; - len -= tailsize; - from = ap->dccpap_buf; - } - - memcpy(to, from, len); - /* - * From draft-ietf-dccp-spec-11.txt: - * - * For each acknowledgement it sends, the HC-Receiver will add an - * acknowledgement record. ack_seqno will equal the HC-Receiver - * sequence number it used for the ack packet; ack_ptr will equal - * buf_head; ack_ackno will equal buf_ackno; and ack_nonce will - * equal buf_nonce. - * - * This implemention uses just one ack record for now. - */ - ap->dccpap_ack_seqno = DCCP_SKB_CB(skb)->dccpd_seq; - ap->dccpap_ack_ptr = ap->dccpap_buf_head; - ap->dccpap_ack_ackno = ap->dccpap_buf_ackno; - ap->dccpap_ack_nonce = ap->dccpap_buf_nonce; - ap->dccpap_ack_vector_len = ap->dccpap_buf_vector_len; - - dccp_pr_debug("%sACK Vector 0, len=%d, ack_seqno=%llu, " - "ack_ackno=%llu\n", - debug_prefix, ap->dccpap_ack_vector_len, - (unsigned long long) ap->dccpap_ack_seqno, - (unsigned long long) ap->dccpap_ack_ackno); -} - void dccp_timestamp(const struct sock *sk, struct timeval *tv) { const struct dccp_sock *dp = dccp_sk(sk); @@ -528,9 +432,8 @@ void dccp_insert_options(struct sock *sk, struct sk_buff *skb) if (!dccp_packet_without_ack(skb)) { if (dp->dccps_options.dccpo_send_ack_vector && - (dp->dccps_hc_rx_ackpkts->dccpap_buf_ackno != - DCCP_MAX_SEQNO + 1)) - dccp_insert_option_ack_vector(sk, skb); + dccp_ackvec_pending(dp->dccps_hc_rx_ackvec)) + dccp_insert_option_ackvec(sk, skb); if (dp->dccps_timestamp_echo != 0) dccp_insert_option_timestamp_echo(sk, skb); } @@ -557,331 +460,3 @@ void dccp_insert_options(struct sock *sk, struct sk_buff *skb) } } } - -struct dccp_ackpkts *dccp_ackpkts_alloc(const unsigned int len, - const unsigned int __nocast priority) -{ - struct dccp_ackpkts *ap = kmalloc(sizeof(*ap) + len, priority); - - if (ap != NULL) { -#ifdef CONFIG_IP_DCCP_DEBUG - memset(ap->dccpap_buf, 0xFF, len); -#endif - ap->dccpap_buf_len = len; - ap->dccpap_buf_head = - ap->dccpap_buf_tail = - ap->dccpap_buf_len - 1; - ap->dccpap_buf_ackno = - ap->dccpap_ack_ackno = - ap->dccpap_ack_seqno = DCCP_MAX_SEQNO + 1; - ap->dccpap_buf_nonce = ap->dccpap_buf_nonce = 0; - ap->dccpap_ack_ptr = 0; - ap->dccpap_time.tv_sec = 0; - ap->dccpap_time.tv_usec = 0; - ap->dccpap_buf_vector_len = ap->dccpap_ack_vector_len = 0; - } - - return ap; -} - -void dccp_ackpkts_free(struct dccp_ackpkts *ap) -{ - if (ap != NULL) { -#ifdef CONFIG_IP_DCCP_DEBUG - memset(ap, 0xFF, sizeof(*ap) + ap->dccpap_buf_len); -#endif - kfree(ap); - } -} - -static inline u8 dccp_ackpkts_state(const struct dccp_ackpkts *ap, - const unsigned int index) -{ - return ap->dccpap_buf[index] & DCCP_ACKPKTS_STATE_MASK; -} - -static inline u8 dccp_ackpkts_len(const struct dccp_ackpkts *ap, - const unsigned int index) -{ - return ap->dccpap_buf[index] & DCCP_ACKPKTS_LEN_MASK; -} - -/* - * If several packets are missing, the HC-Receiver may prefer to enter multiple - * bytes with run length 0, rather than a single byte with a larger run length; - * this simplifies table updates if one of the missing packets arrives. - */ -static inline int dccp_ackpkts_set_buf_head_state(struct dccp_ackpkts *ap, - const unsigned int packets, - const unsigned char state) -{ - unsigned int gap; - signed long new_head; - - if (ap->dccpap_buf_vector_len + packets > ap->dccpap_buf_len) - return -ENOBUFS; - - gap = packets - 1; - new_head = ap->dccpap_buf_head - packets; - - if (new_head < 0) { - if (gap > 0) { - memset(ap->dccpap_buf, DCCP_ACKPKTS_STATE_NOT_RECEIVED, - gap + new_head + 1); - gap = -new_head; - } - new_head += ap->dccpap_buf_len; - } - - ap->dccpap_buf_head = new_head; - - if (gap > 0) - memset(ap->dccpap_buf + ap->dccpap_buf_head + 1, - DCCP_ACKPKTS_STATE_NOT_RECEIVED, gap); - - ap->dccpap_buf[ap->dccpap_buf_head] = state; - ap->dccpap_buf_vector_len += packets; - return 0; -} - -/* - * Implements the draft-ietf-dccp-spec-11.txt Appendix A - */ -int dccp_ackpkts_add(struct dccp_ackpkts *ap, const struct sock *sk, - u64 ackno, u8 state) -{ - /* - * Check at the right places if the buffer is full, if it is, tell the - * caller to start dropping packets till the HC-Sender acks our ACK - * vectors, when we will free up space in dccpap_buf. - * - * We may well decide to do buffer compression, etc, but for now lets - * just drop. - * - * From Appendix A: - * - * Of course, the circular buffer may overflow, either when the - * HC-Sender is sending data at a very high rate, when the - * HC-Receiver's acknowledgements are not reaching the HC-Sender, - * or when the HC-Sender is forgetting to acknowledge those acks - * (so the HC-Receiver is unable to clean up old state). In this - * case, the HC-Receiver should either compress the buffer (by - * increasing run lengths when possible), transfer its state to - * a larger buffer, or, as a last resort, drop all received - * packets, without processing them whatsoever, until its buffer - * shrinks again. - */ - - /* See if this is the first ackno being inserted */ - if (ap->dccpap_buf_vector_len == 0) { - ap->dccpap_buf[ap->dccpap_buf_head] = state; - ap->dccpap_buf_vector_len = 1; - } else if (after48(ackno, ap->dccpap_buf_ackno)) { - const u64 delta = dccp_delta_seqno(ap->dccpap_buf_ackno, - ackno); - - /* - * Look if the state of this packet is the same as the - * previous ackno and if so if we can bump the head len. - */ - if (delta == 1 && - dccp_ackpkts_state(ap, ap->dccpap_buf_head) == state && - (dccp_ackpkts_len(ap, ap->dccpap_buf_head) < - DCCP_ACKPKTS_LEN_MASK)) - ap->dccpap_buf[ap->dccpap_buf_head]++; - else if (dccp_ackpkts_set_buf_head_state(ap, delta, state)) - return -ENOBUFS; - } else { - /* - * A.1.2. Old Packets - * - * When a packet with Sequence Number S arrives, and - * S <= buf_ackno, the HC-Receiver will scan the table - * for the byte corresponding to S. (Indexing structures - * could reduce the complexity of this scan.) - */ - u64 delta = dccp_delta_seqno(ackno, ap->dccpap_buf_ackno); - unsigned int index = ap->dccpap_buf_head; - - while (1) { - const u8 len = dccp_ackpkts_len(ap, index); - const u8 state = dccp_ackpkts_state(ap, index); - /* - * valid packets not yet in dccpap_buf have a reserved - * entry, with a len equal to 0. - */ - if (state == DCCP_ACKPKTS_STATE_NOT_RECEIVED && - len == 0 && delta == 0) { /* Found our - reserved seat! */ - dccp_pr_debug("Found %llu reserved seat!\n", - (unsigned long long) ackno); - ap->dccpap_buf[index] = state; - goto out; - } - /* len == 0 means one packet */ - if (delta < len + 1) - goto out_duplicate; - - delta -= len + 1; - if (++index == ap->dccpap_buf_len) - index = 0; - } - } - - ap->dccpap_buf_ackno = ackno; - dccp_timestamp(sk, &ap->dccpap_time); -out: - dccp_pr_debug(""); - dccp_ackpkts_print(ap); - return 0; - -out_duplicate: - /* Duplicate packet */ - dccp_pr_debug("Received a dup or already considered lost " - "packet: %llu\n", (unsigned long long) ackno); - return -EILSEQ; -} - -#ifdef CONFIG_IP_DCCP_DEBUG -void dccp_ackvector_print(const u64 ackno, const unsigned char *vector, - int len) -{ - if (!dccp_debug) - return; - - printk("ACK vector len=%d, ackno=%llu |", len, - (unsigned long long) ackno); - - while (len--) { - const u8 state = (*vector & DCCP_ACKPKTS_STATE_MASK) >> 6; - const u8 rl = (*vector & DCCP_ACKPKTS_LEN_MASK); - - printk("%d,%d|", state, rl); - ++vector; - } - - printk("\n"); -} - -void dccp_ackpkts_print(const struct dccp_ackpkts *ap) -{ - dccp_ackvector_print(ap->dccpap_buf_ackno, - ap->dccpap_buf + ap->dccpap_buf_head, - ap->dccpap_buf_vector_len); -} -#endif - -static void dccp_ackpkts_trow_away_ack_record(struct dccp_ackpkts *ap) -{ - /* - * As we're keeping track of the ack vector size - * (dccpap_buf_vector_len) and the sent ack vector size - * (dccpap_ack_vector_len) we don't need dccpap_buf_tail at all, but - * keep this code here as in the future we'll implement a vector of - * ack records, as suggested in draft-ietf-dccp-spec-11.txt - * Appendix A. -acme - */ -#if 0 - ap->dccpap_buf_tail = ap->dccpap_ack_ptr + 1; - if (ap->dccpap_buf_tail >= ap->dccpap_buf_len) - ap->dccpap_buf_tail -= ap->dccpap_buf_len; -#endif - ap->dccpap_buf_vector_len -= ap->dccpap_ack_vector_len; -} - -void dccp_ackpkts_check_rcv_ackno(struct dccp_ackpkts *ap, struct sock *sk, - u64 ackno) -{ - /* Check if we actually sent an ACK vector */ - if (ap->dccpap_ack_seqno == DCCP_MAX_SEQNO + 1) - return; - - if (ackno == ap->dccpap_ack_seqno) { -#ifdef CONFIG_IP_DCCP_DEBUG - struct dccp_sock *dp = dccp_sk(sk); - const char *debug_prefix = dp->dccps_role == DCCP_ROLE_CLIENT ? - "CLIENT rx ack: " : "server rx ack: "; -#endif - dccp_pr_debug("%sACK packet 0, len=%d, ack_seqno=%llu, " - "ack_ackno=%llu, ACKED!\n", - debug_prefix, 1, - (unsigned long long) ap->dccpap_ack_seqno, - (unsigned long long) ap->dccpap_ack_ackno); - dccp_ackpkts_trow_away_ack_record(ap); - ap->dccpap_ack_seqno = DCCP_MAX_SEQNO + 1; - } -} - -static void dccp_ackpkts_check_rcv_ackvector(struct dccp_ackpkts *ap, - struct sock *sk, u64 ackno, - const unsigned char len, - const unsigned char *vector) -{ - unsigned char i; - - /* Check if we actually sent an ACK vector */ - if (ap->dccpap_ack_seqno == DCCP_MAX_SEQNO + 1) - return; - /* - * We're in the receiver half connection, so if the received an ACK - * vector ackno (e.g. 50) before dccpap_ack_seqno (e.g. 52), we're - * not interested. - * - * Extra explanation with example: - * - * if we received an ACK vector with ackno 50, it can only be acking - * 50, 49, 48, etc, not 52 (the seqno for the ACK vector we sent). - */ - /* dccp_pr_debug("is %llu < %llu? ", ackno, ap->dccpap_ack_seqno); */ - if (before48(ackno, ap->dccpap_ack_seqno)) { - /* dccp_pr_debug_cat("yes\n"); */ - return; - } - /* dccp_pr_debug_cat("no\n"); */ - - i = len; - while (i--) { - const u8 rl = (*vector & DCCP_ACKPKTS_LEN_MASK); - u64 ackno_end_rl; - - dccp_set_seqno(&ackno_end_rl, ackno - rl); - - /* - * dccp_pr_debug("is %llu <= %llu <= %llu? ", ackno_end_rl, - * ap->dccpap_ack_seqno, ackno); - */ - if (between48(ap->dccpap_ack_seqno, ackno_end_rl, ackno)) { - const u8 state = (*vector & - DCCP_ACKPKTS_STATE_MASK) >> 6; - /* dccp_pr_debug_cat("yes\n"); */ - - if (state != DCCP_ACKPKTS_STATE_NOT_RECEIVED) { -#ifdef CONFIG_IP_DCCP_DEBUG - struct dccp_sock *dp = dccp_sk(sk); - const char *debug_prefix = - dp->dccps_role == DCCP_ROLE_CLIENT ? - "CLIENT rx ack: " : "server rx ack: "; -#endif - dccp_pr_debug("%sACK vector 0, len=%d, " - "ack_seqno=%llu, ack_ackno=%llu, " - "ACKED!\n", - debug_prefix, len, - (unsigned long long) - ap->dccpap_ack_seqno, - (unsigned long long) - ap->dccpap_ack_ackno); - dccp_ackpkts_trow_away_ack_record(ap); - } - /* - * If dccpap_ack_seqno was not received, no problem - * we'll send another ACK vector. - */ - ap->dccpap_ack_seqno = DCCP_MAX_SEQNO + 1; - break; - } - /* dccp_pr_debug_cat("no\n"); */ - - dccp_set_seqno(&ackno, ackno_end_rl - 1); - ++vector; - } -} diff --git a/net/dccp/output.c b/net/dccp/output.c index ea6d0e9..4786bdc 100644 --- a/net/dccp/output.c +++ b/net/dccp/output.c @@ -16,6 +16,7 @@ #include <net/sock.h> +#include "ackvec.h" #include "ccid.h" #include "dccp.h" @@ -85,7 +86,7 @@ int dccp_transmit_skb(struct sock *sk, struct sk_buff *skb) switch (dcb->dccpd_type) { case DCCP_PKT_REQUEST: dccp_hdr_request(skb)->dccph_req_service = - dcb->dccpd_service; + dp->dccps_service; break; case DCCP_PKT_RESET: dccp_hdr_reset(skb)->dccph_reset_code = @@ -225,7 +226,6 @@ int dccp_write_xmit(struct sock *sk, struct sk_buff *skb, long *timeo) err = dccp_wait_for_ccid(sk, skb, timeo); if (err == 0) { - const struct dccp_ackpkts *ap = dp->dccps_hc_rx_ackpkts; struct dccp_skb_cb *dcb = DCCP_SKB_CB(skb); const int len = skb->len; @@ -236,15 +236,7 @@ int dccp_write_xmit(struct sock *sk, struct sk_buff *skb, long *timeo) inet_csk(sk)->icsk_rto, DCCP_RTO_MAX); dcb->dccpd_type = DCCP_PKT_DATAACK; - /* - * FIXME: we really should have a - * dccps_ack_pending or use icsk. - */ - } else if (inet_csk_ack_scheduled(sk) || - dp->dccps_timestamp_echo != 0 || - (dp->dccps_options.dccpo_send_ack_vector && - ap->dccpap_buf_ackno != DCCP_MAX_SEQNO + 1 && - ap->dccpap_ack_seqno == DCCP_MAX_SEQNO + 1)) + } else if (dccp_ack_pending(sk)) dcb->dccpd_type = DCCP_PKT_DATAACK; else dcb->dccpd_type = DCCP_PKT_DATA; @@ -270,6 +262,7 @@ struct sk_buff *dccp_make_response(struct sock *sk, struct dst_entry *dst, struct request_sock *req) { struct dccp_hdr *dh; + struct dccp_request_sock *dreq; const int dccp_header_size = sizeof(struct dccp_hdr) + sizeof(struct dccp_hdr_ext) + sizeof(struct dccp_hdr_response); @@ -285,8 +278,9 @@ struct sk_buff *dccp_make_response(struct sock *sk, struct dst_entry *dst, skb->dst = dst_clone(dst); skb->csum = 0; + dreq = dccp_rsk(req); DCCP_SKB_CB(skb)->dccpd_type = DCCP_PKT_RESPONSE; - DCCP_SKB_CB(skb)->dccpd_seq = dccp_rsk(req)->dreq_iss; + DCCP_SKB_CB(skb)->dccpd_seq = dreq->dreq_iss; dccp_insert_options(sk, skb); skb->h.raw = skb_push(skb, dccp_header_size); @@ -300,8 +294,9 @@ struct sk_buff *dccp_make_response(struct sock *sk, struct dst_entry *dst, DCCP_SKB_CB(skb)->dccpd_opt_len) / 4; dh->dccph_type = DCCP_PKT_RESPONSE; dh->dccph_x = 1; - dccp_hdr_set_seq(dh, dccp_rsk(req)->dreq_iss); - dccp_hdr_set_ack(dccp_hdr_ack_bits(skb), dccp_rsk(req)->dreq_isr); + dccp_hdr_set_seq(dh, dreq->dreq_iss); + dccp_hdr_set_ack(dccp_hdr_ack_bits(skb), dreq->dreq_isr); + dccp_hdr_response(skb)->dccph_resp_service = dreq->dreq_service; dh->dccph_checksum = dccp_v4_checksum(skb, inet_rsk(req)->loc_addr, inet_rsk(req)->rmt_addr); @@ -397,9 +392,6 @@ int dccp_connect(struct sock *sk) skb_reserve(skb, MAX_DCCP_HEADER); DCCP_SKB_CB(skb)->dccpd_type = DCCP_PKT_REQUEST; - /* FIXME: set service to something meaningful, coming - * from userspace*/ - DCCP_SKB_CB(skb)->dccpd_service = 0; skb->csum = 0; skb_set_owner_w(skb, sk); diff --git a/net/dccp/proto.c b/net/dccp/proto.c index 18a0e69..a1cfd0e 100644 --- a/net/dccp/proto.c +++ b/net/dccp/proto.c @@ -94,7 +94,15 @@ EXPORT_SYMBOL_GPL(dccp_state_name); static inline int dccp_listen_start(struct sock *sk) { - dccp_sk(sk)->dccps_role = DCCP_ROLE_LISTEN; + struct dccp_sock *dp = dccp_sk(sk); + + dp->dccps_role = DCCP_ROLE_LISTEN; + /* + * Apps need to use setsockopt(DCCP_SOCKOPT_SERVICE) + * before calling listen() + */ + if (dccp_service_not_initialized(sk)) + return -EPROTO; return inet_csk_listen_start(sk, TCP_SYNQ_HSIZE); } @@ -202,6 +210,42 @@ int dccp_ioctl(struct sock *sk, int cmd, unsigned long arg) return -ENOIOCTLCMD; } +static int dccp_setsockopt_service(struct sock *sk, const u32 service, + char __user *optval, int optlen) +{ + struct dccp_sock *dp = dccp_sk(sk); + struct dccp_service_list *sl = NULL; + + if (service == DCCP_SERVICE_INVALID_VALUE || + optlen > DCCP_SERVICE_LIST_MAX_LEN * sizeof(u32)) + return -EINVAL; + + if (optlen > sizeof(service)) { + sl = kmalloc(optlen, GFP_KERNEL); + if (sl == NULL) + return -ENOMEM; + + sl->dccpsl_nr = optlen / sizeof(u32) - 1; + if (copy_from_user(sl->dccpsl_list, + optval + sizeof(service), + optlen - sizeof(service)) || + dccp_list_has_service(sl, DCCP_SERVICE_INVALID_VALUE)) { + kfree(sl); + return -EFAULT; + } + } + + lock_sock(sk); + dp->dccps_service = service; + + if (dp->dccps_service_list != NULL) + kfree(dp->dccps_service_list); + + dp->dccps_service_list = sl; + release_sock(sk); + return 0; +} + int dccp_setsockopt(struct sock *sk, int level, int optname, char __user *optval, int optlen) { @@ -218,8 +262,10 @@ int dccp_setsockopt(struct sock *sk, int level, int optname, if (get_user(val, (int __user *)optval)) return -EFAULT; - lock_sock(sk); + if (optname == DCCP_SOCKOPT_SERVICE) + return dccp_setsockopt_service(sk, val, optval, optlen); + lock_sock(sk); dp = dccp_sk(sk); err = 0; @@ -236,6 +282,37 @@ int dccp_setsockopt(struct sock *sk, int level, int optname, return err; } +static int dccp_getsockopt_service(struct sock *sk, int len, + u32 __user *optval, + int __user *optlen) +{ + const struct dccp_sock *dp = dccp_sk(sk); + const struct dccp_service_list *sl; + int err = -ENOENT, slen = 0, total_len = sizeof(u32); + + lock_sock(sk); + if (dccp_service_not_initialized(sk)) + goto out; + + if ((sl = dp->dccps_service_list) != NULL) { + slen = sl->dccpsl_nr * sizeof(u32); + total_len += slen; + } + + err = -EINVAL; + if (total_len > len) + goto out; + + err = 0; + if (put_user(total_len, optlen) || + put_user(dp->dccps_service, optval) || + (sl != NULL && copy_to_user(optval + 1, sl->dccpsl_list, slen))) + err = -EFAULT; +out: + release_sock(sk); + return err; +} + int dccp_getsockopt(struct sock *sk, int level, int optname, char __user *optval, int __user *optlen) { @@ -248,8 +325,7 @@ int dccp_getsockopt(struct sock *sk, int level, int optname, if (get_user(len, optlen)) return -EFAULT; - len = min_t(unsigned int, len, sizeof(int)); - if (len < 0) + if (len < sizeof(int)) return -EINVAL; dp = dccp_sk(sk); @@ -257,7 +333,17 @@ int dccp_getsockopt(struct sock *sk, int level, int optname, switch (optname) { case DCCP_SOCKOPT_PACKET_SIZE: val = dp->dccps_packet_size; + len = sizeof(dp->dccps_packet_size); break; + case DCCP_SOCKOPT_SERVICE: + return dccp_getsockopt_service(sk, len, + (u32 __user *)optval, optlen); + case 128 ... 191: + return ccid_hc_rx_getsockopt(dp->dccps_hc_rx_ccid, sk, optname, + len, (u32 __user *)optval, optlen); + case 192 ... 255: + return ccid_hc_tx_getsockopt(dp->dccps_hc_tx_ccid, sk, optname, + len, (u32 __user *)optval, optlen); default: return -ENOPROTOOPT; } diff --git a/net/ipv4/fib_trie.c b/net/ipv4/fib_trie.c index 1b63b48..50c0519 100644 --- a/net/ipv4/fib_trie.c +++ b/net/ipv4/fib_trie.c @@ -43,7 +43,7 @@ * 2 of the License, or (at your option) any later version. */ -#define VERSION "0.403" +#define VERSION "0.404" #include <linux/config.h> #include <asm/uaccess.h> @@ -224,7 +224,7 @@ static inline int tkey_mismatch(t_key a, int offset, t_key b) Consider a node 'n' and its parent 'tp'. If n is a leaf, every bit in its key is significant. Its presence is - necessitaded by path compression, since during a tree traversal (when + necessitated by path compression, since during a tree traversal (when searching for a leaf - unless we are doing an insertion) we will completely ignore all skipped bits we encounter. Thus we need to verify, at the end of a potentially successful search, that we have indeed been walking the @@ -836,11 +836,12 @@ static void trie_init(struct trie *t) #endif } -/* readside most use rcu_read_lock currently dump routines +/* readside must use rcu_read_lock currently dump routines via get_fa_head and dump */ -static struct leaf_info *find_leaf_info(struct hlist_head *head, int plen) +static struct leaf_info *find_leaf_info(struct leaf *l, int plen) { + struct hlist_head *head = &l->list; struct hlist_node *node; struct leaf_info *li; @@ -853,7 +854,7 @@ static struct leaf_info *find_leaf_info(struct hlist_head *head, int plen) static inline struct list_head * get_fa_head(struct leaf *l, int plen) { - struct leaf_info *li = find_leaf_info(&l->list, plen); + struct leaf_info *li = find_leaf_info(l, plen); if (!li) return NULL; @@ -1085,7 +1086,7 @@ fib_insert_node(struct trie *t, int *err, u32 key, int plen) } if (tp && tp->pos + tp->bits > 32) - printk("ERROR tp=%p pos=%d, bits=%d, key=%0x plen=%d\n", + printk(KERN_WARNING "fib_trie tp=%p pos=%d, bits=%d, key=%0x plen=%d\n", tp, tp->pos, tp->bits, key, plen); /* Rebalance the trie */ @@ -1248,7 +1249,7 @@ err: } -/* should be clalled with rcu_read_lock */ +/* should be called with rcu_read_lock */ static inline int check_leaf(struct trie *t, struct leaf *l, t_key key, int *plen, const struct flowi *flp, struct fib_result *res) @@ -1590,7 +1591,7 @@ fn_trie_delete(struct fib_table *tb, struct rtmsg *r, struct kern_rta *rta, rtmsg_fib(RTM_DELROUTE, htonl(key), fa, plen, tb->tb_id, nlhdr, req); l = fib_find_node(t, key); - li = find_leaf_info(&l->list, plen); + li = find_leaf_info(l, plen); list_del_rcu(&fa->fa_list); @@ -1714,7 +1715,6 @@ static int fn_trie_flush(struct fib_table *tb) t->revision++; - rcu_read_lock(); for (h = 0; (l = nextleaf(t, l)) != NULL; h++) { found += trie_flush_leaf(t, l); @@ -1722,7 +1722,6 @@ static int fn_trie_flush(struct fib_table *tb) trie_leaf_remove(t, ll->key); ll = l; } - rcu_read_unlock(); if (ll && hlist_empty(&ll->list)) trie_leaf_remove(t, ll->key); @@ -1833,16 +1832,7 @@ static int fn_trie_dump_fa(t_key key, int plen, struct list_head *fah, struct fi i++; continue; } - if (fa->fa_info->fib_nh == NULL) { - printk("Trie error _fib_nh=NULL in fa[%d] k=%08x plen=%d\n", i, key, plen); - i++; - continue; - } - if (fa->fa_info == NULL) { - printk("Trie error fa_info=NULL in fa[%d] k=%08x plen=%d\n", i, key, plen); - i++; - continue; - } + BUG_ON(!fa->fa_info); if (fib_dump_info(skb, NETLINK_CB(cb->skb).pid, cb->nlh->nlmsg_seq, @@ -1965,7 +1955,7 @@ struct fib_table * __init fib_hash_init(int id) trie_main = t; if (id == RT_TABLE_LOCAL) - printk("IPv4 FIB: Using LC-trie version %s\n", VERSION); + printk(KERN_INFO "IPv4 FIB: Using LC-trie version %s\n", VERSION); return tb; } @@ -2029,7 +2019,7 @@ static struct node *fib_trie_get_first(struct fib_trie_iter *iter, iter->tnode = (struct tnode *) n; iter->trie = t; iter->index = 0; - iter->depth = 0; + iter->depth = 1; return n; } return NULL; @@ -2274,11 +2264,12 @@ static int fib_trie_seq_show(struct seq_file *seq, void *v) seq_puts(seq, "<local>:\n"); else seq_puts(seq, "<main>:\n"); - } else { - seq_indent(seq, iter->depth-1); - seq_printf(seq, " +-- %d.%d.%d.%d/%d\n", - NIPQUAD(prf), tn->pos); - } + } + seq_indent(seq, iter->depth-1); + seq_printf(seq, " +-- %d.%d.%d.%d/%d %d %d %d\n", + NIPQUAD(prf), tn->pos, tn->bits, tn->full_children, + tn->empty_children); + } else { struct leaf *l = (struct leaf *) n; int i; @@ -2287,7 +2278,7 @@ static int fib_trie_seq_show(struct seq_file *seq, void *v) seq_indent(seq, iter->depth); seq_printf(seq, " |-- %d.%d.%d.%d\n", NIPQUAD(val)); for (i = 32; i >= 0; i--) { - struct leaf_info *li = find_leaf_info(&l->list, i); + struct leaf_info *li = find_leaf_info(l, i); if (li) { struct fib_alias *fa; list_for_each_entry_rcu(fa, &li->falh, fa_list) { @@ -2383,7 +2374,7 @@ static int fib_route_seq_show(struct seq_file *seq, void *v) return 0; for (i=32; i>=0; i--) { - struct leaf_info *li = find_leaf_info(&l->list, i); + struct leaf_info *li = find_leaf_info(l, i); struct fib_alias *fa; u32 mask, prefix; diff --git a/net/ipv4/igmp.c b/net/ipv4/igmp.c index 44607f4..70c44e4 100644 --- a/net/ipv4/igmp.c +++ b/net/ipv4/igmp.c @@ -1603,7 +1603,7 @@ static void ip_mc_clear_src(struct ip_mc_list *pmc) } pmc->sources = NULL; pmc->sfmode = MCAST_EXCLUDE; - pmc->sfcount[MCAST_EXCLUDE] = 0; + pmc->sfcount[MCAST_INCLUDE] = 0; pmc->sfcount[MCAST_EXCLUDE] = 1; } diff --git a/net/ipv4/ipvs/ip_vs_conn.c b/net/ipv4/ipvs/ip_vs_conn.c index e11952e..f828fa2 100644 --- a/net/ipv4/ipvs/ip_vs_conn.c +++ b/net/ipv4/ipvs/ip_vs_conn.c @@ -196,6 +196,7 @@ static inline struct ip_vs_conn *__ip_vs_conn_in_get list_for_each_entry(cp, &ip_vs_conn_tab[hash], c_list) { if (s_addr==cp->caddr && s_port==cp->cport && d_port==cp->vport && d_addr==cp->vaddr && + ((!s_port) ^ (!(cp->flags & IP_VS_CONN_F_NO_CPORT))) && protocol==cp->protocol) { /* HIT */ atomic_inc(&cp->refcnt); @@ -227,6 +228,40 @@ struct ip_vs_conn *ip_vs_conn_in_get return cp; } +/* Get reference to connection template */ +struct ip_vs_conn *ip_vs_ct_in_get +(int protocol, __u32 s_addr, __u16 s_port, __u32 d_addr, __u16 d_port) +{ + unsigned hash; + struct ip_vs_conn *cp; + + hash = ip_vs_conn_hashkey(protocol, s_addr, s_port); + + ct_read_lock(hash); + + list_for_each_entry(cp, &ip_vs_conn_tab[hash], c_list) { + if (s_addr==cp->caddr && s_port==cp->cport && + d_port==cp->vport && d_addr==cp->vaddr && + cp->flags & IP_VS_CONN_F_TEMPLATE && + protocol==cp->protocol) { + /* HIT */ + atomic_inc(&cp->refcnt); + goto out; + } + } + cp = NULL; + + out: + ct_read_unlock(hash); + + IP_VS_DBG(7, "template lookup/in %s %u.%u.%u.%u:%d->%u.%u.%u.%u:%d %s\n", + ip_vs_proto_name(protocol), + NIPQUAD(s_addr), ntohs(s_port), + NIPQUAD(d_addr), ntohs(d_port), + cp?"hit":"not hit"); + + return cp; +} /* * Gets ip_vs_conn associated with supplied parameters in the ip_vs_conn_tab. @@ -367,7 +402,7 @@ ip_vs_bind_dest(struct ip_vs_conn *cp, struct ip_vs_dest *dest) atomic_read(&dest->refcnt)); /* Update the connection counters */ - if (cp->cport || (cp->flags & IP_VS_CONN_F_NO_CPORT)) { + if (!(cp->flags & IP_VS_CONN_F_TEMPLATE)) { /* It is a normal connection, so increase the inactive connection counter because it is in TCP SYNRECV state (inactive) or other protocol inacive state */ @@ -406,7 +441,7 @@ static inline void ip_vs_unbind_dest(struct ip_vs_conn *cp) atomic_read(&dest->refcnt)); /* Update the connection counters */ - if (cp->cport || (cp->flags & IP_VS_CONN_F_NO_CPORT)) { + if (!(cp->flags & IP_VS_CONN_F_TEMPLATE)) { /* It is a normal connection, so decrease the inactconns or activeconns counter */ if (cp->flags & IP_VS_CONN_F_INACTIVE) { @@ -467,7 +502,7 @@ int ip_vs_check_template(struct ip_vs_conn *ct) /* * Invalidate the connection template */ - if (ct->cport) { + if (ct->vport != 65535) { if (ip_vs_conn_unhash(ct)) { ct->dport = 65535; ct->vport = 65535; @@ -776,7 +811,7 @@ void ip_vs_random_dropentry(void) ct_write_lock_bh(hash); list_for_each_entry(cp, &ip_vs_conn_tab[hash], c_list) { - if (!cp->cport && !(cp->flags & IP_VS_CONN_F_NO_CPORT)) + if (cp->flags & IP_VS_CONN_F_TEMPLATE) /* connection template */ continue; diff --git a/net/ipv4/ipvs/ip_vs_core.c b/net/ipv4/ipvs/ip_vs_core.c index 3ac7eec..981cc32 100644 --- a/net/ipv4/ipvs/ip_vs_core.c +++ b/net/ipv4/ipvs/ip_vs_core.c @@ -243,10 +243,10 @@ ip_vs_sched_persist(struct ip_vs_service *svc, if (ports[1] == svc->port) { /* Check if a template already exists */ if (svc->port != FTPPORT) - ct = ip_vs_conn_in_get(iph->protocol, snet, 0, + ct = ip_vs_ct_in_get(iph->protocol, snet, 0, iph->daddr, ports[1]); else - ct = ip_vs_conn_in_get(iph->protocol, snet, 0, + ct = ip_vs_ct_in_get(iph->protocol, snet, 0, iph->daddr, 0); if (!ct || !ip_vs_check_template(ct)) { @@ -272,14 +272,14 @@ ip_vs_sched_persist(struct ip_vs_service *svc, iph->daddr, ports[1], dest->addr, dest->port, - 0, + IP_VS_CONN_F_TEMPLATE, dest); else ct = ip_vs_conn_new(iph->protocol, snet, 0, iph->daddr, 0, dest->addr, 0, - 0, + IP_VS_CONN_F_TEMPLATE, dest); if (ct == NULL) return NULL; @@ -298,10 +298,10 @@ ip_vs_sched_persist(struct ip_vs_service *svc, * port zero template: <protocol,caddr,0,vaddr,0,daddr,0> */ if (svc->fwmark) - ct = ip_vs_conn_in_get(IPPROTO_IP, snet, 0, + ct = ip_vs_ct_in_get(IPPROTO_IP, snet, 0, htonl(svc->fwmark), 0); else - ct = ip_vs_conn_in_get(iph->protocol, snet, 0, + ct = ip_vs_ct_in_get(iph->protocol, snet, 0, iph->daddr, 0); if (!ct || !ip_vs_check_template(ct)) { @@ -326,14 +326,14 @@ ip_vs_sched_persist(struct ip_vs_service *svc, snet, 0, htonl(svc->fwmark), 0, dest->addr, 0, - 0, + IP_VS_CONN_F_TEMPLATE, dest); else ct = ip_vs_conn_new(iph->protocol, snet, 0, iph->daddr, 0, dest->addr, 0, - 0, + IP_VS_CONN_F_TEMPLATE, dest); if (ct == NULL) return NULL; diff --git a/net/ipv4/ipvs/ip_vs_sync.c b/net/ipv4/ipvs/ip_vs_sync.c index 574d1f5..2e5ced3 100644 --- a/net/ipv4/ipvs/ip_vs_sync.c +++ b/net/ipv4/ipvs/ip_vs_sync.c @@ -297,16 +297,24 @@ static void ip_vs_process_message(const char *buffer, const size_t buflen) p = (char *)buffer + sizeof(struct ip_vs_sync_mesg); for (i=0; i<m->nr_conns; i++) { + unsigned flags; + s = (struct ip_vs_sync_conn *)p; - cp = ip_vs_conn_in_get(s->protocol, - s->caddr, s->cport, - s->vaddr, s->vport); + flags = ntohs(s->flags); + if (!(flags & IP_VS_CONN_F_TEMPLATE)) + cp = ip_vs_conn_in_get(s->protocol, + s->caddr, s->cport, + s->vaddr, s->vport); + else + cp = ip_vs_ct_in_get(s->protocol, + s->caddr, s->cport, + s->vaddr, s->vport); if (!cp) { cp = ip_vs_conn_new(s->protocol, s->caddr, s->cport, s->vaddr, s->vport, s->daddr, s->dport, - ntohs(s->flags), NULL); + flags, NULL); if (!cp) { IP_VS_ERR("ip_vs_conn_new failed\n"); return; @@ -315,11 +323,11 @@ static void ip_vs_process_message(const char *buffer, const size_t buflen) } else if (!cp->dest) { /* it is an entry created by the synchronization */ cp->state = ntohs(s->state); - cp->flags = ntohs(s->flags) | IP_VS_CONN_F_HASHED; + cp->flags = flags | IP_VS_CONN_F_HASHED; } /* Note that we don't touch its state and flags if it is a normal entry. */ - if (ntohs(s->flags) & IP_VS_CONN_F_SEQ_MASK) { + if (flags & IP_VS_CONN_F_SEQ_MASK) { opt = (struct ip_vs_sync_conn_options *)&s[1]; memcpy(&cp->in_seq, opt, sizeof(*opt)); p += FULL_CONN_SIZE; diff --git a/net/ipv4/netfilter/Kconfig b/net/ipv4/netfilter/Kconfig index 30aa8e2..3cf9b45 100644 --- a/net/ipv4/netfilter/Kconfig +++ b/net/ipv4/netfilter/Kconfig @@ -51,6 +51,14 @@ config IP_NF_CONNTRACK_EVENTS IF unsure, say `N'. +config IP_NF_CONNTRACK_NETLINK + tristate 'Connection tracking netlink interface' + depends on IP_NF_CONNTRACK && NETFILTER_NETLINK + depends on IP_NF_CONNTRACK!=y || NETFILTER_NETLINK!=m + help + This option enables support for a netlink-based userspace interface + + config IP_NF_CT_PROTO_SCTP tristate 'SCTP protocol connection tracking support (EXPERIMENTAL)' depends on IP_NF_CONNTRACK && EXPERIMENTAL @@ -129,6 +137,22 @@ config IP_NF_AMANDA To compile it as a module, choose M here. If unsure, say Y. +config IP_NF_PPTP + tristate 'PPTP protocol support' + help + This module adds support for PPTP (Point to Point Tunnelling + Protocol, RFC2637) conncection tracking and NAT. + + If you are running PPTP sessions over a stateful firewall or NAT + box, you may want to enable this feature. + + Please note that not all PPTP modes of operation are supported yet. + For more info, read top of the file + net/ipv4/netfilter/ip_conntrack_pptp.c + + If you want to compile it as a module, say M here and read + Documentation/modules.txt. If unsure, say `N'. + config IP_NF_QUEUE tristate "IP Userspace queueing via NETLINK (OBSOLETE)" help @@ -613,6 +637,12 @@ config IP_NF_NAT_AMANDA default IP_NF_NAT if IP_NF_AMANDA=y default m if IP_NF_AMANDA=m +config IP_NF_NAT_PPTP + tristate + depends on IP_NF_NAT!=n && IP_NF_PPTP!=n + default IP_NF_NAT if IP_NF_PPTP=y + default m if IP_NF_PPTP=m + # mangle + specific targets config IP_NF_MANGLE tristate "Packet mangling" @@ -774,11 +804,5 @@ config IP_NF_ARP_MANGLE Allows altering the ARP packet payload: source and destination hardware and network addresses. -config IP_NF_CONNTRACK_NETLINK - tristate 'Connection tracking netlink interface' - depends on IP_NF_CONNTRACK && NETFILTER_NETLINK - help - This option enables support for a netlink-based userspace interface - endmenu diff --git a/net/ipv4/netfilter/Makefile b/net/ipv4/netfilter/Makefile index 1ba0db7..3d45d3c 100644 --- a/net/ipv4/netfilter/Makefile +++ b/net/ipv4/netfilter/Makefile @@ -6,6 +6,9 @@ ip_conntrack-objs := ip_conntrack_standalone.o ip_conntrack_core.o ip_conntrack_proto_generic.o ip_conntrack_proto_tcp.o ip_conntrack_proto_udp.o ip_conntrack_proto_icmp.o iptable_nat-objs := ip_nat_standalone.o ip_nat_rule.o ip_nat_core.o ip_nat_helper.o ip_nat_proto_unknown.o ip_nat_proto_tcp.o ip_nat_proto_udp.o ip_nat_proto_icmp.o +ip_conntrack_pptp-objs := ip_conntrack_helper_pptp.o ip_conntrack_proto_gre.o +ip_nat_pptp-objs := ip_nat_helper_pptp.o ip_nat_proto_gre.o + # connection tracking obj-$(CONFIG_IP_NF_CONNTRACK) += ip_conntrack.o @@ -17,6 +20,7 @@ obj-$(CONFIG_IP_NF_CONNTRACK_NETLINK) += ip_conntrack_netlink.o obj-$(CONFIG_IP_NF_CT_PROTO_SCTP) += ip_conntrack_proto_sctp.o # connection tracking helpers +obj-$(CONFIG_IP_NF_PPTP) += ip_conntrack_pptp.o obj-$(CONFIG_IP_NF_AMANDA) += ip_conntrack_amanda.o obj-$(CONFIG_IP_NF_TFTP) += ip_conntrack_tftp.o obj-$(CONFIG_IP_NF_FTP) += ip_conntrack_ftp.o @@ -24,6 +28,7 @@ obj-$(CONFIG_IP_NF_IRC) += ip_conntrack_irc.o obj-$(CONFIG_IP_NF_NETBIOS_NS) += ip_conntrack_netbios_ns.o # NAT helpers +obj-$(CONFIG_IP_NF_NAT_PPTP) += ip_nat_pptp.o obj-$(CONFIG_IP_NF_NAT_AMANDA) += ip_nat_amanda.o obj-$(CONFIG_IP_NF_NAT_TFTP) += ip_nat_tftp.o obj-$(CONFIG_IP_NF_NAT_FTP) += ip_nat_ftp.o diff --git a/net/ipv4/netfilter/ip_conntrack_amanda.c b/net/ipv4/netfilter/ip_conntrack_amanda.c index dc20881..fa3f914 100644 --- a/net/ipv4/netfilter/ip_conntrack_amanda.c +++ b/net/ipv4/netfilter/ip_conntrack_amanda.c @@ -65,7 +65,7 @@ static int help(struct sk_buff **pskb, /* increase the UDP timeout of the master connection as replies from * Amanda clients to the server can be quite delayed */ - ip_ct_refresh_acct(ct, ctinfo, NULL, master_timeout * HZ); + ip_ct_refresh(ct, *pskb, master_timeout * HZ); /* No data? */ dataoff = (*pskb)->nh.iph->ihl*4 + sizeof(struct udphdr); diff --git a/net/ipv4/netfilter/ip_conntrack_core.c b/net/ipv4/netfilter/ip_conntrack_core.c index 19cba16..ea65dd3 100644 --- a/net/ipv4/netfilter/ip_conntrack_core.c +++ b/net/ipv4/netfilter/ip_conntrack_core.c @@ -233,7 +233,7 @@ __ip_conntrack_expect_find(const struct ip_conntrack_tuple *tuple) /* Just find a expectation corresponding to a tuple. */ struct ip_conntrack_expect * -ip_conntrack_expect_find_get(const struct ip_conntrack_tuple *tuple) +ip_conntrack_expect_find(const struct ip_conntrack_tuple *tuple) { struct ip_conntrack_expect *i; @@ -1112,42 +1112,46 @@ void ip_conntrack_helper_unregister(struct ip_conntrack_helper *me) synchronize_net(); } -static inline void ct_add_counters(struct ip_conntrack *ct, - enum ip_conntrack_info ctinfo, - const struct sk_buff *skb) -{ -#ifdef CONFIG_IP_NF_CT_ACCT - if (skb) { - ct->counters[CTINFO2DIR(ctinfo)].packets++; - ct->counters[CTINFO2DIR(ctinfo)].bytes += - ntohs(skb->nh.iph->tot_len); - } -#endif -} - -/* Refresh conntrack for this many jiffies and do accounting (if skb != NULL) */ -void ip_ct_refresh_acct(struct ip_conntrack *ct, +/* Refresh conntrack for this many jiffies and do accounting if do_acct is 1 */ +void __ip_ct_refresh_acct(struct ip_conntrack *ct, enum ip_conntrack_info ctinfo, const struct sk_buff *skb, - unsigned long extra_jiffies) + unsigned long extra_jiffies, + int do_acct) { + int do_event = 0; + IP_NF_ASSERT(ct->timeout.data == (unsigned long)ct); + IP_NF_ASSERT(skb); + + write_lock_bh(&ip_conntrack_lock); /* If not in hash table, timer will not be active yet */ if (!is_confirmed(ct)) { ct->timeout.expires = extra_jiffies; - ct_add_counters(ct, ctinfo, skb); + do_event = 1; } else { - write_lock_bh(&ip_conntrack_lock); /* Need del_timer for race avoidance (may already be dying). */ if (del_timer(&ct->timeout)) { ct->timeout.expires = jiffies + extra_jiffies; add_timer(&ct->timeout); - ip_conntrack_event_cache(IPCT_REFRESH, skb); + do_event = 1; } - ct_add_counters(ct, ctinfo, skb); - write_unlock_bh(&ip_conntrack_lock); } + +#ifdef CONFIG_IP_NF_CT_ACCT + if (do_acct) { + ct->counters[CTINFO2DIR(ctinfo)].packets++; + ct->counters[CTINFO2DIR(ctinfo)].bytes += + ntohs(skb->nh.iph->tot_len); + } +#endif + + write_unlock_bh(&ip_conntrack_lock); + + /* must be unlocked when calling event cache */ + if (do_event) + ip_conntrack_event_cache(IPCT_REFRESH, skb); } #if defined(CONFIG_IP_NF_CONNTRACK_NETLINK) || \ diff --git a/net/ipv4/netfilter/ip_conntrack_ftp.c b/net/ipv4/netfilter/ip_conntrack_ftp.c index 1b79ec3..d77d6b3f 100644 --- a/net/ipv4/netfilter/ip_conntrack_ftp.c +++ b/net/ipv4/netfilter/ip_conntrack_ftp.c @@ -29,9 +29,9 @@ static char *ftp_buffer; static DEFINE_SPINLOCK(ip_ftp_lock); #define MAX_PORTS 8 -static int ports[MAX_PORTS]; +static short ports[MAX_PORTS]; static int ports_c; -module_param_array(ports, int, &ports_c, 0400); +module_param_array(ports, short, &ports_c, 0400); static int loose; module_param(loose, int, 0600); @@ -450,7 +450,7 @@ out_update_nl: } static struct ip_conntrack_helper ftp[MAX_PORTS]; -static char ftp_names[MAX_PORTS][10]; +static char ftp_names[MAX_PORTS][sizeof("ftp-65535")]; /* Not __exit: called from init() */ static void fini(void) diff --git a/net/ipv4/netfilter/ip_conntrack_helper_pptp.c b/net/ipv4/netfilter/ip_conntrack_helper_pptp.c new file mode 100644 index 0000000..926a668 --- /dev/null +++ b/net/ipv4/netfilter/ip_conntrack_helper_pptp.c @@ -0,0 +1,806 @@ +/* + * ip_conntrack_pptp.c - Version 3.0 + * + * Connection tracking support for PPTP (Point to Point Tunneling Protocol). + * PPTP is a a protocol for creating virtual private networks. + * It is a specification defined by Microsoft and some vendors + * working with Microsoft. PPTP is built on top of a modified + * version of the Internet Generic Routing Encapsulation Protocol. + * GRE is defined in RFC 1701 and RFC 1702. Documentation of + * PPTP can be found in RFC 2637 + * + * (C) 2000-2005 by Harald Welte <laforge@gnumonks.org> + * + * Development of this code funded by Astaro AG (http://www.astaro.com/) + * + * Limitations: + * - We blindly assume that control connections are always + * established in PNS->PAC direction. This is a violation + * of RFFC2673 + * - We can only support one single call within each session + * + * TODO: + * - testing of incoming PPTP calls + * + * Changes: + * 2002-02-05 - Version 1.3 + * - Call ip_conntrack_unexpect_related() from + * pptp_destroy_siblings() to destroy expectations in case + * CALL_DISCONNECT_NOTIFY or tcp fin packet was seen + * (Philip Craig <philipc@snapgear.com>) + * - Add Version information at module loadtime + * 2002-02-10 - Version 1.6 + * - move to C99 style initializers + * - remove second expectation if first arrives + * 2004-10-22 - Version 2.0 + * - merge Mandrake's 2.6.x port with recent 2.6.x API changes + * - fix lots of linear skb assumptions from Mandrake's port + * 2005-06-10 - Version 2.1 + * - use ip_conntrack_expect_free() instead of kfree() on the + * expect's (which are from the slab for quite some time) + * 2005-06-10 - Version 3.0 + * - port helper to post-2.6.11 API changes, + * funded by Oxcoda NetBox Blue (http://www.netboxblue.com/) + * 2005-07-30 - Version 3.1 + * - port helper to 2.6.13 API changes + * + */ + +#include <linux/config.h> +#include <linux/module.h> +#include <linux/netfilter.h> +#include <linux/ip.h> +#include <net/checksum.h> +#include <net/tcp.h> + +#include <linux/netfilter_ipv4/ip_conntrack.h> +#include <linux/netfilter_ipv4/ip_conntrack_core.h> +#include <linux/netfilter_ipv4/ip_conntrack_helper.h> +#include <linux/netfilter_ipv4/ip_conntrack_proto_gre.h> +#include <linux/netfilter_ipv4/ip_conntrack_pptp.h> + +#define IP_CT_PPTP_VERSION "3.1" + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Harald Welte <laforge@gnumonks.org>"); +MODULE_DESCRIPTION("Netfilter connection tracking helper module for PPTP"); + +static DEFINE_SPINLOCK(ip_pptp_lock); + +int +(*ip_nat_pptp_hook_outbound)(struct sk_buff **pskb, + struct ip_conntrack *ct, + enum ip_conntrack_info ctinfo, + struct PptpControlHeader *ctlh, + union pptp_ctrl_union *pptpReq); + +int +(*ip_nat_pptp_hook_inbound)(struct sk_buff **pskb, + struct ip_conntrack *ct, + enum ip_conntrack_info ctinfo, + struct PptpControlHeader *ctlh, + union pptp_ctrl_union *pptpReq); + +int +(*ip_nat_pptp_hook_exp_gre)(struct ip_conntrack_expect *expect_orig, + struct ip_conntrack_expect *expect_reply); + +void +(*ip_nat_pptp_hook_expectfn)(struct ip_conntrack *ct, + struct ip_conntrack_expect *exp); + +#if 0 +/* PptpControlMessageType names */ +const char *pptp_msg_name[] = { + "UNKNOWN_MESSAGE", + "START_SESSION_REQUEST", + "START_SESSION_REPLY", + "STOP_SESSION_REQUEST", + "STOP_SESSION_REPLY", + "ECHO_REQUEST", + "ECHO_REPLY", + "OUT_CALL_REQUEST", + "OUT_CALL_REPLY", + "IN_CALL_REQUEST", + "IN_CALL_REPLY", + "IN_CALL_CONNECT", + "CALL_CLEAR_REQUEST", + "CALL_DISCONNECT_NOTIFY", + "WAN_ERROR_NOTIFY", + "SET_LINK_INFO" +}; +EXPORT_SYMBOL(pptp_msg_name); +#define DEBUGP(format, args...) printk(KERN_DEBUG "%s:%s: " format, __FILE__, __FUNCTION__, ## args) +#else +#define DEBUGP(format, args...) +#endif + +#define SECS *HZ +#define MINS * 60 SECS +#define HOURS * 60 MINS + +#define PPTP_GRE_TIMEOUT (10 MINS) +#define PPTP_GRE_STREAM_TIMEOUT (5 HOURS) + +static void pptp_expectfn(struct ip_conntrack *ct, + struct ip_conntrack_expect *exp) +{ + DEBUGP("increasing timeouts\n"); + + /* increase timeout of GRE data channel conntrack entry */ + ct->proto.gre.timeout = PPTP_GRE_TIMEOUT; + ct->proto.gre.stream_timeout = PPTP_GRE_STREAM_TIMEOUT; + + /* Can you see how rusty this code is, compared with the pre-2.6.11 + * one? That's what happened to my shiny newnat of 2002 ;( -HW */ + + if (!ip_nat_pptp_hook_expectfn) { + struct ip_conntrack_tuple inv_t; + struct ip_conntrack_expect *exp_other; + + /* obviously this tuple inversion only works until you do NAT */ + invert_tuplepr(&inv_t, &exp->tuple); + DEBUGP("trying to unexpect other dir: "); + DUMP_TUPLE(&inv_t); + + exp_other = ip_conntrack_expect_find(&inv_t); + if (exp_other) { + /* delete other expectation. */ + DEBUGP("found\n"); + ip_conntrack_unexpect_related(exp_other); + ip_conntrack_expect_put(exp_other); + } else { + DEBUGP("not found\n"); + } + } else { + /* we need more than simple inversion */ + ip_nat_pptp_hook_expectfn(ct, exp); + } +} + +static int destroy_sibling_or_exp(const struct ip_conntrack_tuple *t) +{ + struct ip_conntrack_tuple_hash *h; + struct ip_conntrack_expect *exp; + + DEBUGP("trying to timeout ct or exp for tuple "); + DUMP_TUPLE(t); + + h = ip_conntrack_find_get(t, NULL); + if (h) { + struct ip_conntrack *sibling = tuplehash_to_ctrack(h); + DEBUGP("setting timeout of conntrack %p to 0\n", sibling); + sibling->proto.gre.timeout = 0; + sibling->proto.gre.stream_timeout = 0; + if (del_timer(&sibling->timeout)) + sibling->timeout.function((unsigned long)sibling); + ip_conntrack_put(sibling); + return 1; + } else { + exp = ip_conntrack_expect_find(t); + if (exp) { + DEBUGP("unexpect_related of expect %p\n", exp); + ip_conntrack_unexpect_related(exp); + ip_conntrack_expect_put(exp); + return 1; + } + } + + return 0; +} + + +/* timeout GRE data connections */ +static void pptp_destroy_siblings(struct ip_conntrack *ct) +{ + struct ip_conntrack_tuple t; + + /* Since ct->sibling_list has literally rusted away in 2.6.11, + * we now need another way to find out about our sibling + * contrack and expects... -HW */ + + /* try original (pns->pac) tuple */ + memcpy(&t, &ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple, sizeof(t)); + t.dst.protonum = IPPROTO_GRE; + t.src.u.gre.key = htons(ct->help.ct_pptp_info.pns_call_id); + t.dst.u.gre.key = htons(ct->help.ct_pptp_info.pac_call_id); + + if (!destroy_sibling_or_exp(&t)) + DEBUGP("failed to timeout original pns->pac ct/exp\n"); + + /* try reply (pac->pns) tuple */ + memcpy(&t, &ct->tuplehash[IP_CT_DIR_REPLY].tuple, sizeof(t)); + t.dst.protonum = IPPROTO_GRE; + t.src.u.gre.key = htons(ct->help.ct_pptp_info.pac_call_id); + t.dst.u.gre.key = htons(ct->help.ct_pptp_info.pns_call_id); + + if (!destroy_sibling_or_exp(&t)) + DEBUGP("failed to timeout reply pac->pns ct/exp\n"); +} + +/* expect GRE connections (PNS->PAC and PAC->PNS direction) */ +static inline int +exp_gre(struct ip_conntrack *master, + u_int32_t seq, + __be16 callid, + __be16 peer_callid) +{ + struct ip_conntrack_tuple inv_tuple; + struct ip_conntrack_tuple exp_tuples[] = { + /* tuple in original direction, PNS->PAC */ + { .src = { .ip = master->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip, + .u = { .gre = { .key = peer_callid } } + }, + .dst = { .ip = master->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.ip, + .u = { .gre = { .key = callid } }, + .protonum = IPPROTO_GRE + }, + }, + /* tuple in reply direction, PAC->PNS */ + { .src = { .ip = master->tuplehash[IP_CT_DIR_REPLY].tuple.src.ip, + .u = { .gre = { .key = callid } } + }, + .dst = { .ip = master->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip, + .u = { .gre = { .key = peer_callid } }, + .protonum = IPPROTO_GRE + }, + } + }; + struct ip_conntrack_expect *exp_orig, *exp_reply; + int ret = 1; + + exp_orig = ip_conntrack_expect_alloc(master); + if (exp_orig == NULL) + goto out; + + exp_reply = ip_conntrack_expect_alloc(master); + if (exp_reply == NULL) + goto out_put_orig; + + memcpy(&exp_orig->tuple, &exp_tuples[0], sizeof(exp_orig->tuple)); + + exp_orig->mask.src.ip = 0xffffffff; + exp_orig->mask.src.u.all = 0; + exp_orig->mask.dst.u.all = 0; + exp_orig->mask.dst.u.gre.key = htons(0xffff); + exp_orig->mask.dst.ip = 0xffffffff; + exp_orig->mask.dst.protonum = 0xff; + + exp_orig->master = master; + exp_orig->expectfn = pptp_expectfn; + exp_orig->flags = 0; + + exp_orig->dir = IP_CT_DIR_ORIGINAL; + + /* both expectations are identical apart from tuple */ + memcpy(exp_reply, exp_orig, sizeof(*exp_reply)); + memcpy(&exp_reply->tuple, &exp_tuples[1], sizeof(exp_reply->tuple)); + + exp_reply->dir = !exp_orig->dir; + + if (ip_nat_pptp_hook_exp_gre) + ret = ip_nat_pptp_hook_exp_gre(exp_orig, exp_reply); + else { + + DEBUGP("calling expect_related PNS->PAC"); + DUMP_TUPLE(&exp_orig->tuple); + + if (ip_conntrack_expect_related(exp_orig) != 0) { + DEBUGP("cannot expect_related()\n"); + goto out_put_both; + } + + DEBUGP("calling expect_related PAC->PNS"); + DUMP_TUPLE(&exp_reply->tuple); + + if (ip_conntrack_expect_related(exp_reply) != 0) { + DEBUGP("cannot expect_related()\n"); + goto out_unexpect_orig; + } + + /* Add GRE keymap entries */ + if (ip_ct_gre_keymap_add(master, &exp_reply->tuple, 0) != 0) { + DEBUGP("cannot keymap_add() exp\n"); + goto out_unexpect_both; + } + + invert_tuplepr(&inv_tuple, &exp_reply->tuple); + if (ip_ct_gre_keymap_add(master, &inv_tuple, 1) != 0) { + ip_ct_gre_keymap_destroy(master); + DEBUGP("cannot keymap_add() exp_inv\n"); + goto out_unexpect_both; + } + ret = 0; + } + +out_put_both: + ip_conntrack_expect_put(exp_reply); +out_put_orig: + ip_conntrack_expect_put(exp_orig); +out: + return ret; + +out_unexpect_both: + ip_conntrack_unexpect_related(exp_reply); +out_unexpect_orig: + ip_conntrack_unexpect_related(exp_orig); + goto out_put_both; +} + +static inline int +pptp_inbound_pkt(struct sk_buff **pskb, + struct tcphdr *tcph, + unsigned int nexthdr_off, + unsigned int datalen, + struct ip_conntrack *ct, + enum ip_conntrack_info ctinfo) +{ + struct PptpControlHeader _ctlh, *ctlh; + unsigned int reqlen; + union pptp_ctrl_union _pptpReq, *pptpReq; + struct ip_ct_pptp_master *info = &ct->help.ct_pptp_info; + u_int16_t msg; + __be16 *cid, *pcid; + u_int32_t seq; + + ctlh = skb_header_pointer(*pskb, nexthdr_off, sizeof(_ctlh), &_ctlh); + if (!ctlh) { + DEBUGP("error during skb_header_pointer\n"); + return NF_ACCEPT; + } + nexthdr_off += sizeof(_ctlh); + datalen -= sizeof(_ctlh); + + reqlen = datalen; + if (reqlen > sizeof(*pptpReq)) + reqlen = sizeof(*pptpReq); + pptpReq = skb_header_pointer(*pskb, nexthdr_off, reqlen, &_pptpReq); + if (!pptpReq) { + DEBUGP("error during skb_header_pointer\n"); + return NF_ACCEPT; + } + + msg = ntohs(ctlh->messageType); + DEBUGP("inbound control message %s\n", pptp_msg_name[msg]); + + switch (msg) { + case PPTP_START_SESSION_REPLY: + if (reqlen < sizeof(_pptpReq.srep)) { + DEBUGP("%s: short packet\n", pptp_msg_name[msg]); + break; + } + + /* server confirms new control session */ + if (info->sstate < PPTP_SESSION_REQUESTED) { + DEBUGP("%s without START_SESS_REQUEST\n", + pptp_msg_name[msg]); + break; + } + if (pptpReq->srep.resultCode == PPTP_START_OK) + info->sstate = PPTP_SESSION_CONFIRMED; + else + info->sstate = PPTP_SESSION_ERROR; + break; + + case PPTP_STOP_SESSION_REPLY: + if (reqlen < sizeof(_pptpReq.strep)) { + DEBUGP("%s: short packet\n", pptp_msg_name[msg]); + break; + } + + /* server confirms end of control session */ + if (info->sstate > PPTP_SESSION_STOPREQ) { + DEBUGP("%s without STOP_SESS_REQUEST\n", + pptp_msg_name[msg]); + break; + } + if (pptpReq->strep.resultCode == PPTP_STOP_OK) + info->sstate = PPTP_SESSION_NONE; + else + info->sstate = PPTP_SESSION_ERROR; + break; + + case PPTP_OUT_CALL_REPLY: + if (reqlen < sizeof(_pptpReq.ocack)) { + DEBUGP("%s: short packet\n", pptp_msg_name[msg]); + break; + } + + /* server accepted call, we now expect GRE frames */ + if (info->sstate != PPTP_SESSION_CONFIRMED) { + DEBUGP("%s but no session\n", pptp_msg_name[msg]); + break; + } + if (info->cstate != PPTP_CALL_OUT_REQ && + info->cstate != PPTP_CALL_OUT_CONF) { + DEBUGP("%s without OUTCALL_REQ\n", pptp_msg_name[msg]); + break; + } + if (pptpReq->ocack.resultCode != PPTP_OUTCALL_CONNECT) { + info->cstate = PPTP_CALL_NONE; + break; + } + + cid = &pptpReq->ocack.callID; + pcid = &pptpReq->ocack.peersCallID; + + info->pac_call_id = ntohs(*cid); + + if (htons(info->pns_call_id) != *pcid) { + DEBUGP("%s for unknown callid %u\n", + pptp_msg_name[msg], ntohs(*pcid)); + break; + } + + DEBUGP("%s, CID=%X, PCID=%X\n", pptp_msg_name[msg], + ntohs(*cid), ntohs(*pcid)); + + info->cstate = PPTP_CALL_OUT_CONF; + + seq = ntohl(tcph->seq) + sizeof(struct pptp_pkt_hdr) + + sizeof(struct PptpControlHeader) + + ((void *)pcid - (void *)pptpReq); + + if (exp_gre(ct, seq, *cid, *pcid) != 0) + printk("ip_conntrack_pptp: error during exp_gre\n"); + break; + + case PPTP_IN_CALL_REQUEST: + if (reqlen < sizeof(_pptpReq.icack)) { + DEBUGP("%s: short packet\n", pptp_msg_name[msg]); + break; + } + + /* server tells us about incoming call request */ + if (info->sstate != PPTP_SESSION_CONFIRMED) { + DEBUGP("%s but no session\n", pptp_msg_name[msg]); + break; + } + pcid = &pptpReq->icack.peersCallID; + DEBUGP("%s, PCID=%X\n", pptp_msg_name[msg], ntohs(*pcid)); + info->cstate = PPTP_CALL_IN_REQ; + info->pac_call_id = ntohs(*pcid); + break; + + case PPTP_IN_CALL_CONNECT: + if (reqlen < sizeof(_pptpReq.iccon)) { + DEBUGP("%s: short packet\n", pptp_msg_name[msg]); + break; + } + + /* server tells us about incoming call established */ + if (info->sstate != PPTP_SESSION_CONFIRMED) { + DEBUGP("%s but no session\n", pptp_msg_name[msg]); + break; + } + if (info->sstate != PPTP_CALL_IN_REP + && info->sstate != PPTP_CALL_IN_CONF) { + DEBUGP("%s but never sent IN_CALL_REPLY\n", + pptp_msg_name[msg]); + break; + } + + pcid = &pptpReq->iccon.peersCallID; + cid = &info->pac_call_id; + + if (info->pns_call_id != ntohs(*pcid)) { + DEBUGP("%s for unknown CallID %u\n", + pptp_msg_name[msg], ntohs(*pcid)); + break; + } + + DEBUGP("%s, PCID=%X\n", pptp_msg_name[msg], ntohs(*pcid)); + info->cstate = PPTP_CALL_IN_CONF; + + /* we expect a GRE connection from PAC to PNS */ + seq = ntohl(tcph->seq) + sizeof(struct pptp_pkt_hdr) + + sizeof(struct PptpControlHeader) + + ((void *)pcid - (void *)pptpReq); + + if (exp_gre(ct, seq, *cid, *pcid) != 0) + printk("ip_conntrack_pptp: error during exp_gre\n"); + + break; + + case PPTP_CALL_DISCONNECT_NOTIFY: + if (reqlen < sizeof(_pptpReq.disc)) { + DEBUGP("%s: short packet\n", pptp_msg_name[msg]); + break; + } + + /* server confirms disconnect */ + cid = &pptpReq->disc.callID; + DEBUGP("%s, CID=%X\n", pptp_msg_name[msg], ntohs(*cid)); + info->cstate = PPTP_CALL_NONE; + + /* untrack this call id, unexpect GRE packets */ + pptp_destroy_siblings(ct); + break; + + case PPTP_WAN_ERROR_NOTIFY: + break; + + case PPTP_ECHO_REQUEST: + case PPTP_ECHO_REPLY: + /* I don't have to explain these ;) */ + break; + default: + DEBUGP("invalid %s (TY=%d)\n", (msg <= PPTP_MSG_MAX) + ? pptp_msg_name[msg]:pptp_msg_name[0], msg); + break; + } + + + if (ip_nat_pptp_hook_inbound) + return ip_nat_pptp_hook_inbound(pskb, ct, ctinfo, ctlh, + pptpReq); + + return NF_ACCEPT; + +} + +static inline int +pptp_outbound_pkt(struct sk_buff **pskb, + struct tcphdr *tcph, + unsigned int nexthdr_off, + unsigned int datalen, + struct ip_conntrack *ct, + enum ip_conntrack_info ctinfo) +{ + struct PptpControlHeader _ctlh, *ctlh; + unsigned int reqlen; + union pptp_ctrl_union _pptpReq, *pptpReq; + struct ip_ct_pptp_master *info = &ct->help.ct_pptp_info; + u_int16_t msg; + __be16 *cid, *pcid; + + ctlh = skb_header_pointer(*pskb, nexthdr_off, sizeof(_ctlh), &_ctlh); + if (!ctlh) + return NF_ACCEPT; + nexthdr_off += sizeof(_ctlh); + datalen -= sizeof(_ctlh); + + reqlen = datalen; + if (reqlen > sizeof(*pptpReq)) + reqlen = sizeof(*pptpReq); + pptpReq = skb_header_pointer(*pskb, nexthdr_off, reqlen, &_pptpReq); + if (!pptpReq) + return NF_ACCEPT; + + msg = ntohs(ctlh->messageType); + DEBUGP("outbound control message %s\n", pptp_msg_name[msg]); + + switch (msg) { + case PPTP_START_SESSION_REQUEST: + /* client requests for new control session */ + if (info->sstate != PPTP_SESSION_NONE) { + DEBUGP("%s but we already have one", + pptp_msg_name[msg]); + } + info->sstate = PPTP_SESSION_REQUESTED; + break; + case PPTP_STOP_SESSION_REQUEST: + /* client requests end of control session */ + info->sstate = PPTP_SESSION_STOPREQ; + break; + + case PPTP_OUT_CALL_REQUEST: + if (reqlen < sizeof(_pptpReq.ocreq)) { + DEBUGP("%s: short packet\n", pptp_msg_name[msg]); + /* FIXME: break; */ + } + + /* client initiating connection to server */ + if (info->sstate != PPTP_SESSION_CONFIRMED) { + DEBUGP("%s but no session\n", + pptp_msg_name[msg]); + break; + } + info->cstate = PPTP_CALL_OUT_REQ; + /* track PNS call id */ + cid = &pptpReq->ocreq.callID; + DEBUGP("%s, CID=%X\n", pptp_msg_name[msg], ntohs(*cid)); + info->pns_call_id = ntohs(*cid); + break; + case PPTP_IN_CALL_REPLY: + if (reqlen < sizeof(_pptpReq.icack)) { + DEBUGP("%s: short packet\n", pptp_msg_name[msg]); + break; + } + + /* client answers incoming call */ + if (info->cstate != PPTP_CALL_IN_REQ + && info->cstate != PPTP_CALL_IN_REP) { + DEBUGP("%s without incall_req\n", + pptp_msg_name[msg]); + break; + } + if (pptpReq->icack.resultCode != PPTP_INCALL_ACCEPT) { + info->cstate = PPTP_CALL_NONE; + break; + } + pcid = &pptpReq->icack.peersCallID; + if (info->pac_call_id != ntohs(*pcid)) { + DEBUGP("%s for unknown call %u\n", + pptp_msg_name[msg], ntohs(*pcid)); + break; + } + DEBUGP("%s, CID=%X\n", pptp_msg_name[msg], ntohs(*pcid)); + /* part two of the three-way handshake */ + info->cstate = PPTP_CALL_IN_REP; + info->pns_call_id = ntohs(pptpReq->icack.callID); + break; + + case PPTP_CALL_CLEAR_REQUEST: + /* client requests hangup of call */ + if (info->sstate != PPTP_SESSION_CONFIRMED) { + DEBUGP("CLEAR_CALL but no session\n"); + break; + } + /* FUTURE: iterate over all calls and check if + * call ID is valid. We don't do this without newnat, + * because we only know about last call */ + info->cstate = PPTP_CALL_CLEAR_REQ; + break; + case PPTP_SET_LINK_INFO: + break; + case PPTP_ECHO_REQUEST: + case PPTP_ECHO_REPLY: + /* I don't have to explain these ;) */ + break; + default: + DEBUGP("invalid %s (TY=%d)\n", (msg <= PPTP_MSG_MAX)? + pptp_msg_name[msg]:pptp_msg_name[0], msg); + /* unknown: no need to create GRE masq table entry */ + break; + } + + if (ip_nat_pptp_hook_outbound) + return ip_nat_pptp_hook_outbound(pskb, ct, ctinfo, ctlh, + pptpReq); + + return NF_ACCEPT; +} + + +/* track caller id inside control connection, call expect_related */ +static int +conntrack_pptp_help(struct sk_buff **pskb, + struct ip_conntrack *ct, enum ip_conntrack_info ctinfo) + +{ + struct pptp_pkt_hdr _pptph, *pptph; + struct tcphdr _tcph, *tcph; + u_int32_t tcplen = (*pskb)->len - (*pskb)->nh.iph->ihl * 4; + u_int32_t datalen; + int dir = CTINFO2DIR(ctinfo); + struct ip_ct_pptp_master *info = &ct->help.ct_pptp_info; + unsigned int nexthdr_off; + + int oldsstate, oldcstate; + int ret; + + /* don't do any tracking before tcp handshake complete */ + if (ctinfo != IP_CT_ESTABLISHED + && ctinfo != IP_CT_ESTABLISHED+IP_CT_IS_REPLY) { + DEBUGP("ctinfo = %u, skipping\n", ctinfo); + return NF_ACCEPT; + } + + nexthdr_off = (*pskb)->nh.iph->ihl*4; + tcph = skb_header_pointer(*pskb, nexthdr_off, sizeof(_tcph), &_tcph); + BUG_ON(!tcph); + nexthdr_off += tcph->doff * 4; + datalen = tcplen - tcph->doff * 4; + + if (tcph->fin || tcph->rst) { + DEBUGP("RST/FIN received, timeouting GRE\n"); + /* can't do this after real newnat */ + info->cstate = PPTP_CALL_NONE; + + /* untrack this call id, unexpect GRE packets */ + pptp_destroy_siblings(ct); + } + + pptph = skb_header_pointer(*pskb, nexthdr_off, sizeof(_pptph), &_pptph); + if (!pptph) { + DEBUGP("no full PPTP header, can't track\n"); + return NF_ACCEPT; + } + nexthdr_off += sizeof(_pptph); + datalen -= sizeof(_pptph); + + /* if it's not a control message we can't do anything with it */ + if (ntohs(pptph->packetType) != PPTP_PACKET_CONTROL || + ntohl(pptph->magicCookie) != PPTP_MAGIC_COOKIE) { + DEBUGP("not a control packet\n"); + return NF_ACCEPT; + } + + oldsstate = info->sstate; + oldcstate = info->cstate; + + spin_lock_bh(&ip_pptp_lock); + + /* FIXME: We just blindly assume that the control connection is always + * established from PNS->PAC. However, RFC makes no guarantee */ + if (dir == IP_CT_DIR_ORIGINAL) + /* client -> server (PNS -> PAC) */ + ret = pptp_outbound_pkt(pskb, tcph, nexthdr_off, datalen, ct, + ctinfo); + else + /* server -> client (PAC -> PNS) */ + ret = pptp_inbound_pkt(pskb, tcph, nexthdr_off, datalen, ct, + ctinfo); + DEBUGP("sstate: %d->%d, cstate: %d->%d\n", + oldsstate, info->sstate, oldcstate, info->cstate); + spin_unlock_bh(&ip_pptp_lock); + + return ret; +} + +/* control protocol helper */ +static struct ip_conntrack_helper pptp = { + .list = { NULL, NULL }, + .name = "pptp", + .me = THIS_MODULE, + .max_expected = 2, + .timeout = 5 * 60, + .tuple = { .src = { .ip = 0, + .u = { .tcp = { .port = + __constant_htons(PPTP_CONTROL_PORT) } } + }, + .dst = { .ip = 0, + .u = { .all = 0 }, + .protonum = IPPROTO_TCP + } + }, + .mask = { .src = { .ip = 0, + .u = { .tcp = { .port = __constant_htons(0xffff) } } + }, + .dst = { .ip = 0, + .u = { .all = 0 }, + .protonum = 0xff + } + }, + .help = conntrack_pptp_help +}; + +extern void __exit ip_ct_proto_gre_fini(void); +extern int __init ip_ct_proto_gre_init(void); + +/* ip_conntrack_pptp initialization */ +static int __init init(void) +{ + int retcode; + + retcode = ip_ct_proto_gre_init(); + if (retcode < 0) + return retcode; + + DEBUGP(" registering helper\n"); + if ((retcode = ip_conntrack_helper_register(&pptp))) { + printk(KERN_ERR "Unable to register conntrack application " + "helper for pptp: %d\n", retcode); + ip_ct_proto_gre_fini(); + return retcode; + } + + printk("ip_conntrack_pptp version %s loaded\n", IP_CT_PPTP_VERSION); + return 0; +} + +static void __exit fini(void) +{ + ip_conntrack_helper_unregister(&pptp); + ip_ct_proto_gre_fini(); + printk("ip_conntrack_pptp version %s unloaded\n", IP_CT_PPTP_VERSION); +} + +module_init(init); +module_exit(fini); + +EXPORT_SYMBOL(ip_nat_pptp_hook_outbound); +EXPORT_SYMBOL(ip_nat_pptp_hook_inbound); +EXPORT_SYMBOL(ip_nat_pptp_hook_exp_gre); +EXPORT_SYMBOL(ip_nat_pptp_hook_expectfn); diff --git a/net/ipv4/netfilter/ip_conntrack_irc.c b/net/ipv4/netfilter/ip_conntrack_irc.c index d7a8a98..1545741 100644 --- a/net/ipv4/netfilter/ip_conntrack_irc.c +++ b/net/ipv4/netfilter/ip_conntrack_irc.c @@ -34,7 +34,7 @@ #include <linux/moduleparam.h> #define MAX_PORTS 8 -static int ports[MAX_PORTS]; +static short ports[MAX_PORTS]; static int ports_c; static int max_dcc_channels = 8; static unsigned int dcc_timeout = 300; @@ -52,7 +52,7 @@ EXPORT_SYMBOL_GPL(ip_nat_irc_hook); MODULE_AUTHOR("Harald Welte <laforge@netfilter.org>"); MODULE_DESCRIPTION("IRC (DCC) connection tracking helper"); MODULE_LICENSE("GPL"); -module_param_array(ports, int, &ports_c, 0400); +module_param_array(ports, short, &ports_c, 0400); MODULE_PARM_DESC(ports, "port numbers of IRC servers"); module_param(max_dcc_channels, int, 0400); MODULE_PARM_DESC(max_dcc_channels, "max number of expected DCC channels per IRC session"); @@ -240,7 +240,7 @@ static int help(struct sk_buff **pskb, } static struct ip_conntrack_helper irc_helpers[MAX_PORTS]; -static char irc_names[MAX_PORTS][10]; +static char irc_names[MAX_PORTS][sizeof("irc-65535")]; static void fini(void); diff --git a/net/ipv4/netfilter/ip_conntrack_netbios_ns.c b/net/ipv4/netfilter/ip_conntrack_netbios_ns.c index bb72466..577bac2 100644 --- a/net/ipv4/netfilter/ip_conntrack_netbios_ns.c +++ b/net/ipv4/netfilter/ip_conntrack_netbios_ns.c @@ -23,7 +23,6 @@ #include <linux/inetdevice.h> #include <linux/in.h> #include <linux/ip.h> -#include <linux/udp.h> #include <net/route.h> #include <linux/netfilter.h> @@ -31,6 +30,8 @@ #include <linux/netfilter_ipv4/ip_conntrack.h> #include <linux/netfilter_ipv4/ip_conntrack_helper.h> +#define NMBD_PORT 137 + MODULE_AUTHOR("Patrick McHardy <kaber@trash.net>"); MODULE_DESCRIPTION("NetBIOS name service broadcast connection tracking helper"); MODULE_LICENSE("GPL"); @@ -44,7 +45,6 @@ static int help(struct sk_buff **pskb, { struct ip_conntrack_expect *exp; struct iphdr *iph = (*pskb)->nh.iph; - struct udphdr _uh, *uh; struct rtable *rt = (struct rtable *)(*pskb)->dst; struct in_device *in_dev; u_int32_t mask = 0; @@ -72,20 +72,15 @@ static int help(struct sk_buff **pskb, if (mask == 0) goto out; - uh = skb_header_pointer(*pskb, iph->ihl * 4, sizeof(_uh), &_uh); - BUG_ON(uh == NULL); - exp = ip_conntrack_expect_alloc(ct); if (exp == NULL) goto out; - memset(&exp->tuple, 0, sizeof(exp->tuple)); - exp->tuple.src.ip = iph->daddr & mask; - exp->tuple.dst.ip = iph->saddr; - exp->tuple.dst.u.udp.port = uh->source; - exp->tuple.dst.protonum = IPPROTO_UDP; - memset(&exp->mask, 0, sizeof(exp->mask)); + exp->tuple = ct->tuplehash[IP_CT_DIR_REPLY].tuple; + exp->tuple.src.u.udp.port = ntohs(NMBD_PORT); + exp->mask.src.ip = mask; + exp->mask.src.u.udp.port = 0xFFFF; exp->mask.dst.ip = 0xFFFFFFFF; exp->mask.dst.u.udp.port = 0xFFFF; exp->mask.dst.protonum = 0xFF; @@ -96,7 +91,7 @@ static int help(struct sk_buff **pskb, ip_conntrack_expect_related(exp); ip_conntrack_expect_put(exp); - ip_ct_refresh_acct(ct, ctinfo, NULL, timeout * HZ); + ip_ct_refresh(ct, *pskb, timeout * HZ); out: return NF_ACCEPT; } @@ -107,7 +102,7 @@ static struct ip_conntrack_helper helper = { .src = { .u = { .udp = { - .port = __constant_htons(137), + .port = __constant_htons(NMBD_PORT), } } }, diff --git a/net/ipv4/netfilter/ip_conntrack_netlink.c b/net/ipv4/netfilter/ip_conntrack_netlink.c index 15aef35..b08a432 100644 --- a/net/ipv4/netfilter/ip_conntrack_netlink.c +++ b/net/ipv4/netfilter/ip_conntrack_netlink.c @@ -1270,7 +1270,7 @@ ctnetlink_get_expect(struct sock *ctnl, struct sk_buff *skb, if (err < 0) return err; - exp = ip_conntrack_expect_find_get(&tuple); + exp = ip_conntrack_expect_find(&tuple); if (!exp) return -ENOENT; @@ -1318,7 +1318,7 @@ ctnetlink_del_expect(struct sock *ctnl, struct sk_buff *skb, return err; /* bump usage count to 2 */ - exp = ip_conntrack_expect_find_get(&tuple); + exp = ip_conntrack_expect_find(&tuple); if (!exp) return -ENOENT; diff --git a/net/ipv4/netfilter/ip_conntrack_proto_gre.c b/net/ipv4/netfilter/ip_conntrack_proto_gre.c new file mode 100644 index 0000000..de3cb9d --- /dev/null +++ b/net/ipv4/netfilter/ip_conntrack_proto_gre.c @@ -0,0 +1,327 @@ +/* + * ip_conntrack_proto_gre.c - Version 3.0 + * + * Connection tracking protocol helper module for GRE. + * + * GRE is a generic encapsulation protocol, which is generally not very + * suited for NAT, as it has no protocol-specific part as port numbers. + * + * It has an optional key field, which may help us distinguishing two + * connections between the same two hosts. + * + * GRE is defined in RFC 1701 and RFC 1702, as well as RFC 2784 + * + * PPTP is built on top of a modified version of GRE, and has a mandatory + * field called "CallID", which serves us for the same purpose as the key + * field in plain GRE. + * + * Documentation about PPTP can be found in RFC 2637 + * + * (C) 2000-2005 by Harald Welte <laforge@gnumonks.org> + * + * Development of this code funded by Astaro AG (http://www.astaro.com/) + * + */ + +#include <linux/config.h> +#include <linux/module.h> +#include <linux/types.h> +#include <linux/timer.h> +#include <linux/netfilter.h> +#include <linux/ip.h> +#include <linux/in.h> +#include <linux/list.h> + +static DEFINE_RWLOCK(ip_ct_gre_lock); +#define ASSERT_READ_LOCK(x) +#define ASSERT_WRITE_LOCK(x) + +#include <linux/netfilter_ipv4/listhelp.h> +#include <linux/netfilter_ipv4/ip_conntrack_protocol.h> +#include <linux/netfilter_ipv4/ip_conntrack_helper.h> +#include <linux/netfilter_ipv4/ip_conntrack_core.h> + +#include <linux/netfilter_ipv4/ip_conntrack_proto_gre.h> +#include <linux/netfilter_ipv4/ip_conntrack_pptp.h> + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Harald Welte <laforge@gnumonks.org>"); +MODULE_DESCRIPTION("netfilter connection tracking protocol helper for GRE"); + +/* shamelessly stolen from ip_conntrack_proto_udp.c */ +#define GRE_TIMEOUT (30*HZ) +#define GRE_STREAM_TIMEOUT (180*HZ) + +#if 0 +#define DEBUGP(format, args...) printk(KERN_DEBUG "%s:%s: " format, __FILE__, __FUNCTION__, ## args) +#define DUMP_TUPLE_GRE(x) printk("%u.%u.%u.%u:0x%x -> %u.%u.%u.%u:0x%x\n", \ + NIPQUAD((x)->src.ip), ntohs((x)->src.u.gre.key), \ + NIPQUAD((x)->dst.ip), ntohs((x)->dst.u.gre.key)) +#else +#define DEBUGP(x, args...) +#define DUMP_TUPLE_GRE(x) +#endif + +/* GRE KEYMAP HANDLING FUNCTIONS */ +static LIST_HEAD(gre_keymap_list); + +static inline int gre_key_cmpfn(const struct ip_ct_gre_keymap *km, + const struct ip_conntrack_tuple *t) +{ + return ((km->tuple.src.ip == t->src.ip) && + (km->tuple.dst.ip == t->dst.ip) && + (km->tuple.dst.protonum == t->dst.protonum) && + (km->tuple.dst.u.all == t->dst.u.all)); +} + +/* look up the source key for a given tuple */ +static u_int32_t gre_keymap_lookup(struct ip_conntrack_tuple *t) +{ + struct ip_ct_gre_keymap *km; + u_int32_t key = 0; + + read_lock_bh(&ip_ct_gre_lock); + km = LIST_FIND(&gre_keymap_list, gre_key_cmpfn, + struct ip_ct_gre_keymap *, t); + if (km) + key = km->tuple.src.u.gre.key; + read_unlock_bh(&ip_ct_gre_lock); + + DEBUGP("lookup src key 0x%x up key for ", key); + DUMP_TUPLE_GRE(t); + + return key; +} + +/* add a single keymap entry, associate with specified master ct */ +int +ip_ct_gre_keymap_add(struct ip_conntrack *ct, + struct ip_conntrack_tuple *t, int reply) +{ + struct ip_ct_gre_keymap **exist_km, *km, *old; + + if (!ct->helper || strcmp(ct->helper->name, "pptp")) { + DEBUGP("refusing to add GRE keymap to non-pptp session\n"); + return -1; + } + + if (!reply) + exist_km = &ct->help.ct_pptp_info.keymap_orig; + else + exist_km = &ct->help.ct_pptp_info.keymap_reply; + + if (*exist_km) { + /* check whether it's a retransmission */ + old = LIST_FIND(&gre_keymap_list, gre_key_cmpfn, + struct ip_ct_gre_keymap *, t); + if (old == *exist_km) { + DEBUGP("retransmission\n"); + return 0; + } + + DEBUGP("trying to override keymap_%s for ct %p\n", + reply? "reply":"orig", ct); + return -EEXIST; + } + + km = kmalloc(sizeof(*km), GFP_ATOMIC); + if (!km) + return -ENOMEM; + + memcpy(&km->tuple, t, sizeof(*t)); + *exist_km = km; + + DEBUGP("adding new entry %p: ", km); + DUMP_TUPLE_GRE(&km->tuple); + + write_lock_bh(&ip_ct_gre_lock); + list_append(&gre_keymap_list, km); + write_unlock_bh(&ip_ct_gre_lock); + + return 0; +} + +/* destroy the keymap entries associated with specified master ct */ +void ip_ct_gre_keymap_destroy(struct ip_conntrack *ct) +{ + DEBUGP("entering for ct %p\n", ct); + + if (!ct->helper || strcmp(ct->helper->name, "pptp")) { + DEBUGP("refusing to destroy GRE keymap to non-pptp session\n"); + return; + } + + write_lock_bh(&ip_ct_gre_lock); + if (ct->help.ct_pptp_info.keymap_orig) { + DEBUGP("removing %p from list\n", + ct->help.ct_pptp_info.keymap_orig); + list_del(&ct->help.ct_pptp_info.keymap_orig->list); + kfree(ct->help.ct_pptp_info.keymap_orig); + ct->help.ct_pptp_info.keymap_orig = NULL; + } + if (ct->help.ct_pptp_info.keymap_reply) { + DEBUGP("removing %p from list\n", + ct->help.ct_pptp_info.keymap_reply); + list_del(&ct->help.ct_pptp_info.keymap_reply->list); + kfree(ct->help.ct_pptp_info.keymap_reply); + ct->help.ct_pptp_info.keymap_reply = NULL; + } + write_unlock_bh(&ip_ct_gre_lock); +} + + +/* PUBLIC CONNTRACK PROTO HELPER FUNCTIONS */ + +/* invert gre part of tuple */ +static int gre_invert_tuple(struct ip_conntrack_tuple *tuple, + const struct ip_conntrack_tuple *orig) +{ + tuple->dst.u.gre.key = orig->src.u.gre.key; + tuple->src.u.gre.key = orig->dst.u.gre.key; + + return 1; +} + +/* gre hdr info to tuple */ +static int gre_pkt_to_tuple(const struct sk_buff *skb, + unsigned int dataoff, + struct ip_conntrack_tuple *tuple) +{ + struct gre_hdr_pptp _pgrehdr, *pgrehdr; + u_int32_t srckey; + struct gre_hdr _grehdr, *grehdr; + + /* first only delinearize old RFC1701 GRE header */ + grehdr = skb_header_pointer(skb, dataoff, sizeof(_grehdr), &_grehdr); + if (!grehdr || grehdr->version != GRE_VERSION_PPTP) { + /* try to behave like "ip_conntrack_proto_generic" */ + tuple->src.u.all = 0; + tuple->dst.u.all = 0; + return 1; + } + + /* PPTP header is variable length, only need up to the call_id field */ + pgrehdr = skb_header_pointer(skb, dataoff, 8, &_pgrehdr); + if (!pgrehdr) + return 1; + + if (ntohs(grehdr->protocol) != GRE_PROTOCOL_PPTP) { + DEBUGP("GRE_VERSION_PPTP but unknown proto\n"); + return 0; + } + + tuple->dst.u.gre.key = pgrehdr->call_id; + srckey = gre_keymap_lookup(tuple); + tuple->src.u.gre.key = srckey; + + return 1; +} + +/* print gre part of tuple */ +static int gre_print_tuple(struct seq_file *s, + const struct ip_conntrack_tuple *tuple) +{ + return seq_printf(s, "srckey=0x%x dstkey=0x%x ", + ntohs(tuple->src.u.gre.key), + ntohs(tuple->dst.u.gre.key)); +} + +/* print private data for conntrack */ +static int gre_print_conntrack(struct seq_file *s, + const struct ip_conntrack *ct) +{ + return seq_printf(s, "timeout=%u, stream_timeout=%u ", + (ct->proto.gre.timeout / HZ), + (ct->proto.gre.stream_timeout / HZ)); +} + +/* Returns verdict for packet, and may modify conntrack */ +static int gre_packet(struct ip_conntrack *ct, + const struct sk_buff *skb, + enum ip_conntrack_info conntrackinfo) +{ + /* If we've seen traffic both ways, this is a GRE connection. + * Extend timeout. */ + if (ct->status & IPS_SEEN_REPLY) { + ip_ct_refresh_acct(ct, conntrackinfo, skb, + ct->proto.gre.stream_timeout); + /* Also, more likely to be important, and not a probe. */ + set_bit(IPS_ASSURED_BIT, &ct->status); + } else + ip_ct_refresh_acct(ct, conntrackinfo, skb, + ct->proto.gre.timeout); + + return NF_ACCEPT; +} + +/* Called when a new connection for this protocol found. */ +static int gre_new(struct ip_conntrack *ct, + const struct sk_buff *skb) +{ + DEBUGP(": "); + DUMP_TUPLE_GRE(&ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple); + + /* initialize to sane value. Ideally a conntrack helper + * (e.g. in case of pptp) is increasing them */ + ct->proto.gre.stream_timeout = GRE_STREAM_TIMEOUT; + ct->proto.gre.timeout = GRE_TIMEOUT; + + return 1; +} + +/* Called when a conntrack entry has already been removed from the hashes + * and is about to be deleted from memory */ +static void gre_destroy(struct ip_conntrack *ct) +{ + struct ip_conntrack *master = ct->master; + DEBUGP(" entering\n"); + + if (!master) + DEBUGP("no master !?!\n"); + else + ip_ct_gre_keymap_destroy(master); +} + +/* protocol helper struct */ +static struct ip_conntrack_protocol gre = { + .proto = IPPROTO_GRE, + .name = "gre", + .pkt_to_tuple = gre_pkt_to_tuple, + .invert_tuple = gre_invert_tuple, + .print_tuple = gre_print_tuple, + .print_conntrack = gre_print_conntrack, + .packet = gre_packet, + .new = gre_new, + .destroy = gre_destroy, + .me = THIS_MODULE, +#if defined(CONFIG_IP_NF_CONNTRACK_NETLINK) || \ + defined(CONFIG_IP_NF_CONNTRACK_NETLINK_MODULE) + .tuple_to_nfattr = ip_ct_port_tuple_to_nfattr, + .nfattr_to_tuple = ip_ct_port_nfattr_to_tuple, +#endif +}; + +/* ip_conntrack_proto_gre initialization */ +int __init ip_ct_proto_gre_init(void) +{ + return ip_conntrack_protocol_register(&gre); +} + +void __exit ip_ct_proto_gre_fini(void) +{ + struct list_head *pos, *n; + + /* delete all keymap entries */ + write_lock_bh(&ip_ct_gre_lock); + list_for_each_safe(pos, n, &gre_keymap_list) { + DEBUGP("deleting keymap %p at module unload time\n", pos); + list_del(pos); + kfree(pos); + } + write_unlock_bh(&ip_ct_gre_lock); + + ip_conntrack_protocol_unregister(&gre); +} + +EXPORT_SYMBOL(ip_ct_gre_keymap_add); +EXPORT_SYMBOL(ip_ct_gre_keymap_destroy); diff --git a/net/ipv4/netfilter/ip_conntrack_standalone.c b/net/ipv4/netfilter/ip_conntrack_standalone.c index ae3e3e6..dd476b1 100644 --- a/net/ipv4/netfilter/ip_conntrack_standalone.c +++ b/net/ipv4/netfilter/ip_conntrack_standalone.c @@ -989,15 +989,15 @@ EXPORT_SYMBOL(need_ip_conntrack); EXPORT_SYMBOL(ip_conntrack_helper_register); EXPORT_SYMBOL(ip_conntrack_helper_unregister); EXPORT_SYMBOL(ip_ct_iterate_cleanup); -EXPORT_SYMBOL(ip_ct_refresh_acct); +EXPORT_SYMBOL(__ip_ct_refresh_acct); EXPORT_SYMBOL(ip_conntrack_expect_alloc); EXPORT_SYMBOL(ip_conntrack_expect_put); -EXPORT_SYMBOL_GPL(ip_conntrack_expect_find_get); +EXPORT_SYMBOL_GPL(__ip_conntrack_expect_find); +EXPORT_SYMBOL_GPL(ip_conntrack_expect_find); EXPORT_SYMBOL(ip_conntrack_expect_related); EXPORT_SYMBOL(ip_conntrack_unexpect_related); EXPORT_SYMBOL_GPL(ip_conntrack_expect_list); -EXPORT_SYMBOL_GPL(__ip_conntrack_expect_find); EXPORT_SYMBOL_GPL(ip_ct_unlink_expect); EXPORT_SYMBOL(ip_conntrack_tuple_taken); diff --git a/net/ipv4/netfilter/ip_conntrack_tftp.c b/net/ipv4/netfilter/ip_conntrack_tftp.c index d2b5905..a78736b 100644 --- a/net/ipv4/netfilter/ip_conntrack_tftp.c +++ b/net/ipv4/netfilter/ip_conntrack_tftp.c @@ -26,9 +26,9 @@ MODULE_DESCRIPTION("tftp connection tracking helper"); MODULE_LICENSE("GPL"); #define MAX_PORTS 8 -static int ports[MAX_PORTS]; +static short ports[MAX_PORTS]; static int ports_c; -module_param_array(ports, int, &ports_c, 0400); +module_param_array(ports, short, &ports_c, 0400); MODULE_PARM_DESC(ports, "port numbers of tftp servers"); #if 0 @@ -100,7 +100,7 @@ static int tftp_help(struct sk_buff **pskb, } static struct ip_conntrack_helper tftp[MAX_PORTS]; -static char tftp_names[MAX_PORTS][10]; +static char tftp_names[MAX_PORTS][sizeof("tftp-65535")]; static void fini(void) { diff --git a/net/ipv4/netfilter/ip_nat_core.c b/net/ipv4/netfilter/ip_nat_core.c index 1adedb7..c3ea891 100644 --- a/net/ipv4/netfilter/ip_nat_core.c +++ b/net/ipv4/netfilter/ip_nat_core.c @@ -578,6 +578,8 @@ ip_nat_port_nfattr_to_range(struct nfattr *tb[], struct ip_nat_range *range) return ret; } +EXPORT_SYMBOL_GPL(ip_nat_port_nfattr_to_range); +EXPORT_SYMBOL_GPL(ip_nat_port_range_to_nfattr); #endif int __init ip_nat_init(void) diff --git a/net/ipv4/netfilter/ip_nat_helper_pptp.c b/net/ipv4/netfilter/ip_nat_helper_pptp.c new file mode 100644 index 0000000..3cdd068 --- /dev/null +++ b/net/ipv4/netfilter/ip_nat_helper_pptp.c @@ -0,0 +1,401 @@ +/* + * ip_nat_pptp.c - Version 3.0 + * + * NAT support for PPTP (Point to Point Tunneling Protocol). + * PPTP is a a protocol for creating virtual private networks. + * It is a specification defined by Microsoft and some vendors + * working with Microsoft. PPTP is built on top of a modified + * version of the Internet Generic Routing Encapsulation Protocol. + * GRE is defined in RFC 1701 and RFC 1702. Documentation of + * PPTP can be found in RFC 2637 + * + * (C) 2000-2005 by Harald Welte <laforge@gnumonks.org> + * + * Development of this code funded by Astaro AG (http://www.astaro.com/) + * + * TODO: - NAT to a unique tuple, not to TCP source port + * (needs netfilter tuple reservation) + * + * Changes: + * 2002-02-10 - Version 1.3 + * - Use ip_nat_mangle_tcp_packet() because of cloned skb's + * in local connections (Philip Craig <philipc@snapgear.com>) + * - add checks for magicCookie and pptp version + * - make argument list of pptp_{out,in}bound_packet() shorter + * - move to C99 style initializers + * - print version number at module loadtime + * 2003-09-22 - Version 1.5 + * - use SNATed tcp sourceport as callid, since we get called before + * TCP header is mangled (Philip Craig <philipc@snapgear.com>) + * 2004-10-22 - Version 2.0 + * - kernel 2.6.x version + * 2005-06-10 - Version 3.0 + * - kernel >= 2.6.11 version, + * funded by Oxcoda NetBox Blue (http://www.netboxblue.com/) + * + */ + +#include <linux/config.h> +#include <linux/module.h> +#include <linux/ip.h> +#include <linux/tcp.h> +#include <net/tcp.h> + +#include <linux/netfilter_ipv4/ip_nat.h> +#include <linux/netfilter_ipv4/ip_nat_rule.h> +#include <linux/netfilter_ipv4/ip_nat_helper.h> +#include <linux/netfilter_ipv4/ip_nat_pptp.h> +#include <linux/netfilter_ipv4/ip_conntrack_core.h> +#include <linux/netfilter_ipv4/ip_conntrack_helper.h> +#include <linux/netfilter_ipv4/ip_conntrack_proto_gre.h> +#include <linux/netfilter_ipv4/ip_conntrack_pptp.h> + +#define IP_NAT_PPTP_VERSION "3.0" + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Harald Welte <laforge@gnumonks.org>"); +MODULE_DESCRIPTION("Netfilter NAT helper module for PPTP"); + + +#if 0 +extern const char *pptp_msg_name[]; +#define DEBUGP(format, args...) printk(KERN_DEBUG "%s:%s: " format, __FILE__, \ + __FUNCTION__, ## args) +#else +#define DEBUGP(format, args...) +#endif + +static void pptp_nat_expected(struct ip_conntrack *ct, + struct ip_conntrack_expect *exp) +{ + struct ip_conntrack *master = ct->master; + struct ip_conntrack_expect *other_exp; + struct ip_conntrack_tuple t; + struct ip_ct_pptp_master *ct_pptp_info; + struct ip_nat_pptp *nat_pptp_info; + + ct_pptp_info = &master->help.ct_pptp_info; + nat_pptp_info = &master->nat.help.nat_pptp_info; + + /* And here goes the grand finale of corrosion... */ + + if (exp->dir == IP_CT_DIR_ORIGINAL) { + DEBUGP("we are PNS->PAC\n"); + /* therefore, build tuple for PAC->PNS */ + t.src.ip = master->tuplehash[IP_CT_DIR_REPLY].tuple.src.ip; + t.src.u.gre.key = htons(master->help.ct_pptp_info.pac_call_id); + t.dst.ip = master->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip; + t.dst.u.gre.key = htons(master->help.ct_pptp_info.pns_call_id); + t.dst.protonum = IPPROTO_GRE; + } else { + DEBUGP("we are PAC->PNS\n"); + /* build tuple for PNS->PAC */ + t.src.ip = master->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip; + t.src.u.gre.key = + htons(master->nat.help.nat_pptp_info.pns_call_id); + t.dst.ip = master->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.ip; + t.dst.u.gre.key = + htons(master->nat.help.nat_pptp_info.pac_call_id); + t.dst.protonum = IPPROTO_GRE; + } + + DEBUGP("trying to unexpect other dir: "); + DUMP_TUPLE(&t); + other_exp = ip_conntrack_expect_find(&t); + if (other_exp) { + ip_conntrack_unexpect_related(other_exp); + ip_conntrack_expect_put(other_exp); + DEBUGP("success\n"); + } else { + DEBUGP("not found!\n"); + } + + ip_nat_follow_master(ct, exp); +} + +/* outbound packets == from PNS to PAC */ +static int +pptp_outbound_pkt(struct sk_buff **pskb, + struct ip_conntrack *ct, + enum ip_conntrack_info ctinfo, + struct PptpControlHeader *ctlh, + union pptp_ctrl_union *pptpReq) + +{ + struct ip_ct_pptp_master *ct_pptp_info = &ct->help.ct_pptp_info; + struct ip_nat_pptp *nat_pptp_info = &ct->nat.help.nat_pptp_info; + + u_int16_t msg, *cid = NULL, new_callid; + + new_callid = htons(ct_pptp_info->pns_call_id); + + switch (msg = ntohs(ctlh->messageType)) { + case PPTP_OUT_CALL_REQUEST: + cid = &pptpReq->ocreq.callID; + /* FIXME: ideally we would want to reserve a call ID + * here. current netfilter NAT core is not able to do + * this :( For now we use TCP source port. This breaks + * multiple calls within one control session */ + + /* save original call ID in nat_info */ + nat_pptp_info->pns_call_id = ct_pptp_info->pns_call_id; + + /* don't use tcph->source since we are at a DSTmanip + * hook (e.g. PREROUTING) and pkt is not mangled yet */ + new_callid = ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.u.tcp.port; + + /* save new call ID in ct info */ + ct_pptp_info->pns_call_id = ntohs(new_callid); + break; + case PPTP_IN_CALL_REPLY: + cid = &pptpReq->icreq.callID; + break; + case PPTP_CALL_CLEAR_REQUEST: + cid = &pptpReq->clrreq.callID; + break; + default: + DEBUGP("unknown outbound packet 0x%04x:%s\n", msg, + (msg <= PPTP_MSG_MAX)? + pptp_msg_name[msg]:pptp_msg_name[0]); + /* fall through */ + + case PPTP_SET_LINK_INFO: + /* only need to NAT in case PAC is behind NAT box */ + case PPTP_START_SESSION_REQUEST: + case PPTP_START_SESSION_REPLY: + case PPTP_STOP_SESSION_REQUEST: + case PPTP_STOP_SESSION_REPLY: + case PPTP_ECHO_REQUEST: + case PPTP_ECHO_REPLY: + /* no need to alter packet */ + return NF_ACCEPT; + } + + /* only OUT_CALL_REQUEST, IN_CALL_REPLY, CALL_CLEAR_REQUEST pass + * down to here */ + + IP_NF_ASSERT(cid); + + DEBUGP("altering call id from 0x%04x to 0x%04x\n", + ntohs(*cid), ntohs(new_callid)); + + /* mangle packet */ + if (ip_nat_mangle_tcp_packet(pskb, ct, ctinfo, + (void *)cid - ((void *)ctlh - sizeof(struct pptp_pkt_hdr)), + sizeof(new_callid), + (char *)&new_callid, + sizeof(new_callid)) == 0) + return NF_DROP; + + return NF_ACCEPT; +} + +static int +pptp_exp_gre(struct ip_conntrack_expect *expect_orig, + struct ip_conntrack_expect *expect_reply) +{ + struct ip_ct_pptp_master *ct_pptp_info = + &expect_orig->master->help.ct_pptp_info; + struct ip_nat_pptp *nat_pptp_info = + &expect_orig->master->nat.help.nat_pptp_info; + + struct ip_conntrack *ct = expect_orig->master; + + struct ip_conntrack_tuple inv_t; + struct ip_conntrack_tuple *orig_t, *reply_t; + + /* save original PAC call ID in nat_info */ + nat_pptp_info->pac_call_id = ct_pptp_info->pac_call_id; + + /* alter expectation */ + orig_t = &ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple; + reply_t = &ct->tuplehash[IP_CT_DIR_REPLY].tuple; + + /* alter expectation for PNS->PAC direction */ + invert_tuplepr(&inv_t, &expect_orig->tuple); + expect_orig->saved_proto.gre.key = htons(nat_pptp_info->pac_call_id); + expect_orig->tuple.src.u.gre.key = htons(nat_pptp_info->pns_call_id); + expect_orig->tuple.dst.u.gre.key = htons(ct_pptp_info->pac_call_id); + inv_t.src.ip = reply_t->src.ip; + inv_t.dst.ip = reply_t->dst.ip; + inv_t.src.u.gre.key = htons(nat_pptp_info->pac_call_id); + inv_t.dst.u.gre.key = htons(ct_pptp_info->pns_call_id); + + if (!ip_conntrack_expect_related(expect_orig)) { + DEBUGP("successfully registered expect\n"); + } else { + DEBUGP("can't expect_related(expect_orig)\n"); + return 1; + } + + /* alter expectation for PAC->PNS direction */ + invert_tuplepr(&inv_t, &expect_reply->tuple); + expect_reply->saved_proto.gre.key = htons(nat_pptp_info->pns_call_id); + expect_reply->tuple.src.u.gre.key = htons(nat_pptp_info->pac_call_id); + expect_reply->tuple.dst.u.gre.key = htons(ct_pptp_info->pns_call_id); + inv_t.src.ip = orig_t->src.ip; + inv_t.dst.ip = orig_t->dst.ip; + inv_t.src.u.gre.key = htons(nat_pptp_info->pns_call_id); + inv_t.dst.u.gre.key = htons(ct_pptp_info->pac_call_id); + + if (!ip_conntrack_expect_related(expect_reply)) { + DEBUGP("successfully registered expect\n"); + } else { + DEBUGP("can't expect_related(expect_reply)\n"); + ip_conntrack_unexpect_related(expect_orig); + return 1; + } + + if (ip_ct_gre_keymap_add(ct, &expect_reply->tuple, 0) < 0) { + DEBUGP("can't register original keymap\n"); + ip_conntrack_unexpect_related(expect_orig); + ip_conntrack_unexpect_related(expect_reply); + return 1; + } + + if (ip_ct_gre_keymap_add(ct, &inv_t, 1) < 0) { + DEBUGP("can't register reply keymap\n"); + ip_conntrack_unexpect_related(expect_orig); + ip_conntrack_unexpect_related(expect_reply); + ip_ct_gre_keymap_destroy(ct); + return 1; + } + + return 0; +} + +/* inbound packets == from PAC to PNS */ +static int +pptp_inbound_pkt(struct sk_buff **pskb, + struct ip_conntrack *ct, + enum ip_conntrack_info ctinfo, + struct PptpControlHeader *ctlh, + union pptp_ctrl_union *pptpReq) +{ + struct ip_nat_pptp *nat_pptp_info = &ct->nat.help.nat_pptp_info; + u_int16_t msg, new_cid = 0, new_pcid, *pcid = NULL, *cid = NULL; + + int ret = NF_ACCEPT, rv; + + new_pcid = htons(nat_pptp_info->pns_call_id); + + switch (msg = ntohs(ctlh->messageType)) { + case PPTP_OUT_CALL_REPLY: + pcid = &pptpReq->ocack.peersCallID; + cid = &pptpReq->ocack.callID; + break; + case PPTP_IN_CALL_CONNECT: + pcid = &pptpReq->iccon.peersCallID; + break; + case PPTP_IN_CALL_REQUEST: + /* only need to nat in case PAC is behind NAT box */ + break; + case PPTP_WAN_ERROR_NOTIFY: + pcid = &pptpReq->wanerr.peersCallID; + break; + case PPTP_CALL_DISCONNECT_NOTIFY: + pcid = &pptpReq->disc.callID; + break; + case PPTP_SET_LINK_INFO: + pcid = &pptpReq->setlink.peersCallID; + break; + + default: + DEBUGP("unknown inbound packet %s\n", (msg <= PPTP_MSG_MAX)? + pptp_msg_name[msg]:pptp_msg_name[0]); + /* fall through */ + + case PPTP_START_SESSION_REQUEST: + case PPTP_START_SESSION_REPLY: + case PPTP_STOP_SESSION_REQUEST: + case PPTP_STOP_SESSION_REPLY: + case PPTP_ECHO_REQUEST: + case PPTP_ECHO_REPLY: + /* no need to alter packet */ + return NF_ACCEPT; + } + + /* only OUT_CALL_REPLY, IN_CALL_CONNECT, IN_CALL_REQUEST, + * WAN_ERROR_NOTIFY, CALL_DISCONNECT_NOTIFY pass down here */ + + /* mangle packet */ + IP_NF_ASSERT(pcid); + DEBUGP("altering peer call id from 0x%04x to 0x%04x\n", + ntohs(*pcid), ntohs(new_pcid)); + + rv = ip_nat_mangle_tcp_packet(pskb, ct, ctinfo, + (void *)pcid - ((void *)ctlh - sizeof(struct pptp_pkt_hdr)), + sizeof(new_pcid), (char *)&new_pcid, + sizeof(new_pcid)); + if (rv != NF_ACCEPT) + return rv; + + if (new_cid) { + IP_NF_ASSERT(cid); + DEBUGP("altering call id from 0x%04x to 0x%04x\n", + ntohs(*cid), ntohs(new_cid)); + rv = ip_nat_mangle_tcp_packet(pskb, ct, ctinfo, + (void *)cid - ((void *)ctlh - sizeof(struct pptp_pkt_hdr)), + sizeof(new_cid), + (char *)&new_cid, + sizeof(new_cid)); + if (rv != NF_ACCEPT) + return rv; + } + + /* check for earlier return value of 'switch' above */ + if (ret != NF_ACCEPT) + return ret; + + /* great, at least we don't need to resize packets */ + return NF_ACCEPT; +} + + +extern int __init ip_nat_proto_gre_init(void); +extern void __exit ip_nat_proto_gre_fini(void); + +static int __init init(void) +{ + int ret; + + DEBUGP("%s: registering NAT helper\n", __FILE__); + + ret = ip_nat_proto_gre_init(); + if (ret < 0) + return ret; + + BUG_ON(ip_nat_pptp_hook_outbound); + ip_nat_pptp_hook_outbound = &pptp_outbound_pkt; + + BUG_ON(ip_nat_pptp_hook_inbound); + ip_nat_pptp_hook_inbound = &pptp_inbound_pkt; + + BUG_ON(ip_nat_pptp_hook_exp_gre); + ip_nat_pptp_hook_exp_gre = &pptp_exp_gre; + + BUG_ON(ip_nat_pptp_hook_expectfn); + ip_nat_pptp_hook_expectfn = &pptp_nat_expected; + + printk("ip_nat_pptp version %s loaded\n", IP_NAT_PPTP_VERSION); + return 0; +} + +static void __exit fini(void) +{ + DEBUGP("cleanup_module\n" ); + + ip_nat_pptp_hook_expectfn = NULL; + ip_nat_pptp_hook_exp_gre = NULL; + ip_nat_pptp_hook_inbound = NULL; + ip_nat_pptp_hook_outbound = NULL; + + ip_nat_proto_gre_fini(); + /* Make sure noone calls it, meanwhile */ + synchronize_net(); + + printk("ip_nat_pptp version %s unloaded\n", IP_NAT_PPTP_VERSION); +} + +module_init(init); +module_exit(fini); diff --git a/net/ipv4/netfilter/ip_nat_proto_gre.c b/net/ipv4/netfilter/ip_nat_proto_gre.c new file mode 100644 index 0000000..7c12854 --- /dev/null +++ b/net/ipv4/netfilter/ip_nat_proto_gre.c @@ -0,0 +1,214 @@ +/* + * ip_nat_proto_gre.c - Version 2.0 + * + * NAT protocol helper module for GRE. + * + * GRE is a generic encapsulation protocol, which is generally not very + * suited for NAT, as it has no protocol-specific part as port numbers. + * + * It has an optional key field, which may help us distinguishing two + * connections between the same two hosts. + * + * GRE is defined in RFC 1701 and RFC 1702, as well as RFC 2784 + * + * PPTP is built on top of a modified version of GRE, and has a mandatory + * field called "CallID", which serves us for the same purpose as the key + * field in plain GRE. + * + * Documentation about PPTP can be found in RFC 2637 + * + * (C) 2000-2005 by Harald Welte <laforge@gnumonks.org> + * + * Development of this code funded by Astaro AG (http://www.astaro.com/) + * + */ + +#include <linux/config.h> +#include <linux/module.h> +#include <linux/ip.h> +#include <linux/netfilter_ipv4/ip_nat.h> +#include <linux/netfilter_ipv4/ip_nat_rule.h> +#include <linux/netfilter_ipv4/ip_nat_protocol.h> +#include <linux/netfilter_ipv4/ip_conntrack_proto_gre.h> + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Harald Welte <laforge@gnumonks.org>"); +MODULE_DESCRIPTION("Netfilter NAT protocol helper module for GRE"); + +#if 0 +#define DEBUGP(format, args...) printk(KERN_DEBUG "%s:%s: " format, __FILE__, \ + __FUNCTION__, ## args) +#else +#define DEBUGP(x, args...) +#endif + +/* is key in given range between min and max */ +static int +gre_in_range(const struct ip_conntrack_tuple *tuple, + enum ip_nat_manip_type maniptype, + const union ip_conntrack_manip_proto *min, + const union ip_conntrack_manip_proto *max) +{ + u_int32_t key; + + if (maniptype == IP_NAT_MANIP_SRC) + key = tuple->src.u.gre.key; + else + key = tuple->dst.u.gre.key; + + return ntohl(key) >= ntohl(min->gre.key) + && ntohl(key) <= ntohl(max->gre.key); +} + +/* generate unique tuple ... */ +static int +gre_unique_tuple(struct ip_conntrack_tuple *tuple, + const struct ip_nat_range *range, + enum ip_nat_manip_type maniptype, + const struct ip_conntrack *conntrack) +{ + static u_int16_t key; + u_int16_t *keyptr; + unsigned int min, i, range_size; + + if (maniptype == IP_NAT_MANIP_SRC) + keyptr = &tuple->src.u.gre.key; + else + keyptr = &tuple->dst.u.gre.key; + + if (!(range->flags & IP_NAT_RANGE_PROTO_SPECIFIED)) { + DEBUGP("%p: NATing GRE PPTP\n", conntrack); + min = 1; + range_size = 0xffff; + } else { + min = ntohl(range->min.gre.key); + range_size = ntohl(range->max.gre.key) - min + 1; + } + + DEBUGP("min = %u, range_size = %u\n", min, range_size); + + for (i = 0; i < range_size; i++, key++) { + *keyptr = htonl(min + key % range_size); + if (!ip_nat_used_tuple(tuple, conntrack)) + return 1; + } + + DEBUGP("%p: no NAT mapping\n", conntrack); + + return 0; +} + +/* manipulate a GRE packet according to maniptype */ +static int +gre_manip_pkt(struct sk_buff **pskb, + unsigned int iphdroff, + const struct ip_conntrack_tuple *tuple, + enum ip_nat_manip_type maniptype) +{ + struct gre_hdr *greh; + struct gre_hdr_pptp *pgreh; + struct iphdr *iph = (struct iphdr *)((*pskb)->data + iphdroff); + unsigned int hdroff = iphdroff + iph->ihl*4; + + /* pgreh includes two optional 32bit fields which are not required + * to be there. That's where the magic '8' comes from */ + if (!skb_make_writable(pskb, hdroff + sizeof(*pgreh)-8)) + return 0; + + greh = (void *)(*pskb)->data + hdroff; + pgreh = (struct gre_hdr_pptp *) greh; + + /* we only have destination manip of a packet, since 'source key' + * is not present in the packet itself */ + if (maniptype == IP_NAT_MANIP_DST) { + /* key manipulation is always dest */ + switch (greh->version) { + case 0: + if (!greh->key) { + DEBUGP("can't nat GRE w/o key\n"); + break; + } + if (greh->csum) { + /* FIXME: Never tested this code... */ + *(gre_csum(greh)) = + ip_nat_cheat_check(~*(gre_key(greh)), + tuple->dst.u.gre.key, + *(gre_csum(greh))); + } + *(gre_key(greh)) = tuple->dst.u.gre.key; + break; + case GRE_VERSION_PPTP: + DEBUGP("call_id -> 0x%04x\n", + ntohl(tuple->dst.u.gre.key)); + pgreh->call_id = htons(ntohl(tuple->dst.u.gre.key)); + break; + default: + DEBUGP("can't nat unknown GRE version\n"); + return 0; + break; + } + } + return 1; +} + +/* print out a nat tuple */ +static unsigned int +gre_print(char *buffer, + const struct ip_conntrack_tuple *match, + const struct ip_conntrack_tuple *mask) +{ + unsigned int len = 0; + + if (mask->src.u.gre.key) + len += sprintf(buffer + len, "srckey=0x%x ", + ntohl(match->src.u.gre.key)); + + if (mask->dst.u.gre.key) + len += sprintf(buffer + len, "dstkey=0x%x ", + ntohl(match->src.u.gre.key)); + + return len; +} + +/* print a range of keys */ +static unsigned int +gre_print_range(char *buffer, const struct ip_nat_range *range) +{ + if (range->min.gre.key != 0 + || range->max.gre.key != 0xFFFF) { + if (range->min.gre.key == range->max.gre.key) + return sprintf(buffer, "key 0x%x ", + ntohl(range->min.gre.key)); + else + return sprintf(buffer, "keys 0x%u-0x%u ", + ntohl(range->min.gre.key), + ntohl(range->max.gre.key)); + } else + return 0; +} + +/* nat helper struct */ +static struct ip_nat_protocol gre = { + .name = "GRE", + .protonum = IPPROTO_GRE, + .manip_pkt = gre_manip_pkt, + .in_range = gre_in_range, + .unique_tuple = gre_unique_tuple, + .print = gre_print, + .print_range = gre_print_range, +#if defined(CONFIG_IP_NF_CONNTRACK_NETLINK) || \ + defined(CONFIG_IP_NF_CONNTRACK_NETLINK_MODULE) + .range_to_nfattr = ip_nat_port_range_to_nfattr, + .nfattr_to_range = ip_nat_port_nfattr_to_range, +#endif +}; + +int __init ip_nat_proto_gre_init(void) +{ + return ip_nat_protocol_register(&gre); +} + +void __exit ip_nat_proto_gre_fini(void) +{ + ip_nat_protocol_unregister(&gre); +} diff --git a/net/ipv4/netfilter/ipt_CLUSTERIP.c b/net/ipv4/netfilter/ipt_CLUSTERIP.c index 7d38913..9bcb398 100644 --- a/net/ipv4/netfilter/ipt_CLUSTERIP.c +++ b/net/ipv4/netfilter/ipt_CLUSTERIP.c @@ -13,6 +13,7 @@ #include <linux/config.h> #include <linux/proc_fs.h> #include <linux/jhash.h> +#include <linux/bitops.h> #include <linux/skbuff.h> #include <linux/ip.h> #include <linux/tcp.h> @@ -30,7 +31,7 @@ #include <linux/netfilter_ipv4/ipt_CLUSTERIP.h> #include <linux/netfilter_ipv4/ip_conntrack.h> -#define CLUSTERIP_VERSION "0.7" +#define CLUSTERIP_VERSION "0.8" #define DEBUG_CLUSTERIP @@ -49,13 +50,14 @@ MODULE_DESCRIPTION("iptables target for CLUSTERIP"); struct clusterip_config { struct list_head list; /* list of all configs */ atomic_t refcount; /* reference count */ + atomic_t entries; /* number of entries/rules + * referencing us */ u_int32_t clusterip; /* the IP address */ u_int8_t clustermac[ETH_ALEN]; /* the MAC address */ struct net_device *dev; /* device */ u_int16_t num_total_nodes; /* total number of nodes */ - u_int16_t num_local_nodes; /* number of local nodes */ - u_int16_t local_nodes[CLUSTERIP_MAX_NODES]; /* node number array */ + unsigned long local_nodes; /* node number array */ #ifdef CONFIG_PROC_FS struct proc_dir_entry *pde; /* proc dir entry */ @@ -66,8 +68,7 @@ struct clusterip_config { static LIST_HEAD(clusterip_configs); -/* clusterip_lock protects the clusterip_configs list _AND_ the configurable - * data within all structurses (num_local_nodes, local_nodes[]) */ +/* clusterip_lock protects the clusterip_configs list */ static DEFINE_RWLOCK(clusterip_lock); #ifdef CONFIG_PROC_FS @@ -76,23 +77,48 @@ static struct proc_dir_entry *clusterip_procdir; #endif static inline void -clusterip_config_get(struct clusterip_config *c) { +clusterip_config_get(struct clusterip_config *c) +{ atomic_inc(&c->refcount); } static inline void -clusterip_config_put(struct clusterip_config *c) { - if (atomic_dec_and_test(&c->refcount)) { +clusterip_config_put(struct clusterip_config *c) +{ + if (atomic_dec_and_test(&c->refcount)) + kfree(c); +} + +/* increase the count of entries(rules) using/referencing this config */ +static inline void +clusterip_config_entry_get(struct clusterip_config *c) +{ + atomic_inc(&c->entries); +} + +/* decrease the count of entries using/referencing this config. If last + * entry(rule) is removed, remove the config from lists, but don't free it + * yet, since proc-files could still be holding references */ +static inline void +clusterip_config_entry_put(struct clusterip_config *c) +{ + if (atomic_dec_and_test(&c->entries)) { write_lock_bh(&clusterip_lock); list_del(&c->list); write_unlock_bh(&clusterip_lock); + dev_mc_delete(c->dev, c->clustermac, ETH_ALEN, 0); dev_put(c->dev); - kfree(c); + + /* In case anyone still accesses the file, the open/close + * functions are also incrementing the refcount on their own, + * so it's safe to remove the entry even if it's in use. */ +#ifdef CONFIG_PROC_FS + remove_proc_entry(c->pde->name, c->pde->parent); +#endif } } - static struct clusterip_config * __clusterip_config_find(u_int32_t clusterip) { @@ -111,7 +137,7 @@ __clusterip_config_find(u_int32_t clusterip) } static inline struct clusterip_config * -clusterip_config_find_get(u_int32_t clusterip) +clusterip_config_find_get(u_int32_t clusterip, int entry) { struct clusterip_config *c; @@ -122,11 +148,24 @@ clusterip_config_find_get(u_int32_t clusterip) return NULL; } atomic_inc(&c->refcount); + if (entry) + atomic_inc(&c->entries); read_unlock_bh(&clusterip_lock); return c; } +static void +clusterip_config_init_nodelist(struct clusterip_config *c, + const struct ipt_clusterip_tgt_info *i) +{ + int n; + + for (n = 0; n < i->num_local_nodes; n++) { + set_bit(i->local_nodes[n] - 1, &c->local_nodes); + } +} + static struct clusterip_config * clusterip_config_init(struct ipt_clusterip_tgt_info *i, u_int32_t ip, struct net_device *dev) @@ -143,11 +182,11 @@ clusterip_config_init(struct ipt_clusterip_tgt_info *i, u_int32_t ip, c->clusterip = ip; memcpy(&c->clustermac, &i->clustermac, ETH_ALEN); c->num_total_nodes = i->num_total_nodes; - c->num_local_nodes = i->num_local_nodes; - memcpy(&c->local_nodes, &i->local_nodes, sizeof(c->local_nodes)); + clusterip_config_init_nodelist(c, i); c->hash_mode = i->hash_mode; c->hash_initval = i->hash_initval; atomic_set(&c->refcount, 1); + atomic_set(&c->entries, 1); #ifdef CONFIG_PROC_FS /* create proc dir entry */ @@ -171,53 +210,28 @@ clusterip_config_init(struct ipt_clusterip_tgt_info *i, u_int32_t ip, static int clusterip_add_node(struct clusterip_config *c, u_int16_t nodenum) { - int i; - - write_lock_bh(&clusterip_lock); - if (c->num_local_nodes >= CLUSTERIP_MAX_NODES - || nodenum > CLUSTERIP_MAX_NODES) { - write_unlock_bh(&clusterip_lock); + if (nodenum == 0 || + nodenum > c->num_total_nodes) return 1; - } - - /* check if we alrady have this number in our array */ - for (i = 0; i < c->num_local_nodes; i++) { - if (c->local_nodes[i] == nodenum) { - write_unlock_bh(&clusterip_lock); - return 1; - } - } - c->local_nodes[c->num_local_nodes++] = nodenum; + /* check if we already have this number in our bitfield */ + if (test_and_set_bit(nodenum - 1, &c->local_nodes)) + return 1; - write_unlock_bh(&clusterip_lock); return 0; } static int clusterip_del_node(struct clusterip_config *c, u_int16_t nodenum) { - int i; - - write_lock_bh(&clusterip_lock); - - if (c->num_local_nodes <= 1 || nodenum > CLUSTERIP_MAX_NODES) { - write_unlock_bh(&clusterip_lock); + if (nodenum == 0 || + nodenum > c->num_total_nodes) return 1; - } - for (i = 0; i < c->num_local_nodes; i++) { - if (c->local_nodes[i] == nodenum) { - int size = sizeof(u_int16_t)*(c->num_local_nodes-(i+1)); - memmove(&c->local_nodes[i], &c->local_nodes[i+1], size); - c->num_local_nodes--; - write_unlock_bh(&clusterip_lock); - return 0; - } - } + if (test_and_clear_bit(nodenum - 1, &c->local_nodes)) + return 0; - write_unlock_bh(&clusterip_lock); return 1; } @@ -285,25 +299,7 @@ clusterip_hashfn(struct sk_buff *skb, struct clusterip_config *config) static inline int clusterip_responsible(struct clusterip_config *config, u_int32_t hash) { - int i; - - read_lock_bh(&clusterip_lock); - - if (config->num_local_nodes == 0) { - read_unlock_bh(&clusterip_lock); - return 0; - } - - for (i = 0; i < config->num_local_nodes; i++) { - if (config->local_nodes[i] == hash) { - read_unlock_bh(&clusterip_lock); - return 1; - } - } - - read_unlock_bh(&clusterip_lock); - - return 0; + return test_bit(hash - 1, &config->local_nodes); } /*********************************************************************** @@ -415,8 +411,26 @@ checkentry(const char *tablename, /* FIXME: further sanity checks */ - config = clusterip_config_find_get(e->ip.dst.s_addr); - if (!config) { + config = clusterip_config_find_get(e->ip.dst.s_addr, 1); + if (config) { + if (cipinfo->config != NULL) { + /* Case A: This is an entry that gets reloaded, since + * it still has a cipinfo->config pointer. Simply + * increase the entry refcount and return */ + if (cipinfo->config != config) { + printk(KERN_ERR "CLUSTERIP: Reloaded entry " + "has invalid config pointer!\n"); + return 0; + } + clusterip_config_entry_get(cipinfo->config); + } else { + /* Case B: This is a new rule referring to an existing + * clusterip config. */ + cipinfo->config = config; + clusterip_config_entry_get(cipinfo->config); + } + } else { + /* Case C: This is a completely new clusterip config */ if (!(cipinfo->flags & CLUSTERIP_FLAG_NEW)) { printk(KERN_WARNING "CLUSTERIP: no config found for %u.%u.%u.%u, need 'new'\n", NIPQUAD(e->ip.dst.s_addr)); return 0; @@ -443,10 +457,9 @@ checkentry(const char *tablename, } dev_mc_add(config->dev,config->clustermac, ETH_ALEN, 0); } + cipinfo->config = config; } - cipinfo->config = config; - return 1; } @@ -455,13 +468,10 @@ static void destroy(void *matchinfo, unsigned int matchinfosize) { struct ipt_clusterip_tgt_info *cipinfo = matchinfo; - /* we first remove the proc entry and then drop the reference - * count. In case anyone still accesses the file, the open/close - * functions are also incrementing the refcount on their own */ -#ifdef CONFIG_PROC_FS - remove_proc_entry(cipinfo->config->pde->name, - cipinfo->config->pde->parent); -#endif + /* if no more entries are referencing the config, remove it + * from the list and destroy the proc entry */ + clusterip_config_entry_put(cipinfo->config); + clusterip_config_put(cipinfo->config); } @@ -533,7 +543,7 @@ arp_mangle(unsigned int hook, /* if there is no clusterip configuration for the arp reply's * source ip, we don't want to mangle it */ - c = clusterip_config_find_get(payload->src_ip); + c = clusterip_config_find_get(payload->src_ip, 0); if (!c) return NF_ACCEPT; @@ -574,56 +584,69 @@ static struct nf_hook_ops cip_arp_ops = { #ifdef CONFIG_PROC_FS +struct clusterip_seq_position { + unsigned int pos; /* position */ + unsigned int weight; /* number of bits set == size */ + unsigned int bit; /* current bit */ + unsigned long val; /* current value */ +}; + static void *clusterip_seq_start(struct seq_file *s, loff_t *pos) { struct proc_dir_entry *pde = s->private; struct clusterip_config *c = pde->data; - unsigned int *nodeidx; - - read_lock_bh(&clusterip_lock); - if (*pos >= c->num_local_nodes) + unsigned int weight; + u_int32_t local_nodes; + struct clusterip_seq_position *idx; + + /* FIXME: possible race */ + local_nodes = c->local_nodes; + weight = hweight32(local_nodes); + if (*pos >= weight) return NULL; - nodeidx = kmalloc(sizeof(unsigned int), GFP_KERNEL); - if (!nodeidx) + idx = kmalloc(sizeof(struct clusterip_seq_position), GFP_KERNEL); + if (!idx) return ERR_PTR(-ENOMEM); - *nodeidx = *pos; - return nodeidx; + idx->pos = *pos; + idx->weight = weight; + idx->bit = ffs(local_nodes); + idx->val = local_nodes; + clear_bit(idx->bit - 1, &idx->val); + + return idx; } static void *clusterip_seq_next(struct seq_file *s, void *v, loff_t *pos) { - struct proc_dir_entry *pde = s->private; - struct clusterip_config *c = pde->data; - unsigned int *nodeidx = (unsigned int *)v; + struct clusterip_seq_position *idx = (struct clusterip_seq_position *)v; - *pos = ++(*nodeidx); - if (*pos >= c->num_local_nodes) { + *pos = ++idx->pos; + if (*pos >= idx->weight) { kfree(v); return NULL; } - return nodeidx; + idx->bit = ffs(idx->val); + clear_bit(idx->bit - 1, &idx->val); + return idx; } static void clusterip_seq_stop(struct seq_file *s, void *v) { kfree(v); - - read_unlock_bh(&clusterip_lock); } static int clusterip_seq_show(struct seq_file *s, void *v) { - struct proc_dir_entry *pde = s->private; - struct clusterip_config *c = pde->data; - unsigned int *nodeidx = (unsigned int *)v; + struct clusterip_seq_position *idx = (struct clusterip_seq_position *)v; - if (*nodeidx != 0) + if (idx->pos != 0) seq_putc(s, ','); - seq_printf(s, "%u", c->local_nodes[*nodeidx]); - if (*nodeidx == c->num_local_nodes-1) + seq_printf(s, "%u", idx->bit); + + if (idx->pos == idx->weight - 1) seq_putc(s, '\n'); return 0; diff --git a/net/ipv4/netfilter/ipt_MASQUERADE.c b/net/ipv4/netfilter/ipt_MASQUERADE.c index 2f3e181..275a174 100644 --- a/net/ipv4/netfilter/ipt_MASQUERADE.c +++ b/net/ipv4/netfilter/ipt_MASQUERADE.c @@ -90,6 +90,12 @@ masquerade_target(struct sk_buff **pskb, IP_NF_ASSERT(ct && (ctinfo == IP_CT_NEW || ctinfo == IP_CT_RELATED || ctinfo == IP_CT_RELATED + IP_CT_IS_REPLY)); + /* Source address is 0.0.0.0 - locally generated packet that is + * probably not supposed to be masqueraded. + */ + if (ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip == 0) + return NF_ACCEPT; + mr = targinfo; rt = (struct rtable *)(*pskb)->dst; newsrc = inet_select_addr(out, rt->rt_gateway, RT_SCOPE_UNIVERSE); diff --git a/net/ipv4/netfilter/ipt_REDIRECT.c b/net/ipv4/netfilter/ipt_REDIRECT.c index d2e1344..715cb61 100644 --- a/net/ipv4/netfilter/ipt_REDIRECT.c +++ b/net/ipv4/netfilter/ipt_REDIRECT.c @@ -88,14 +88,18 @@ redirect_target(struct sk_buff **pskb, newdst = htonl(0x7F000001); else { struct in_device *indev; + struct in_ifaddr *ifa; - /* Device might not have an associated in_device. */ - indev = (struct in_device *)(*pskb)->dev->ip_ptr; - if (indev == NULL || indev->ifa_list == NULL) - return NF_DROP; + newdst = 0; + + rcu_read_lock(); + indev = __in_dev_get((*pskb)->dev); + if (indev && (ifa = indev->ifa_list)) + newdst = ifa->ifa_local; + rcu_read_unlock(); - /* Grab first address on interface. */ - newdst = indev->ifa_list->ifa_local; + if (!newdst) + return NF_DROP; } /* Transfer from original range. */ diff --git a/net/ipv4/raw.c b/net/ipv4/raw.c index 304bb0a..4b0d7e4 100644 --- a/net/ipv4/raw.c +++ b/net/ipv4/raw.c @@ -361,7 +361,7 @@ static void raw_probe_proto_opt(struct flowi *fl, struct msghdr *msg) if (type && code) { get_user(fl->fl_icmp_type, type); - __get_user(fl->fl_icmp_code, code); + get_user(fl->fl_icmp_code, code); probed = 1; } break; diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index 29222b96..a7537c7 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c @@ -979,14 +979,19 @@ tcp_sacktag_write_queue(struct sock *sk, struct sk_buff *ack_skb, u32 prior_snd_ if (!before(TCP_SKB_CB(skb)->seq, end_seq)) break; + in_sack = !after(start_seq, TCP_SKB_CB(skb)->seq) && + !before(end_seq, TCP_SKB_CB(skb)->end_seq); + pcount = tcp_skb_pcount(skb); - if (pcount > 1 && - (after(start_seq, TCP_SKB_CB(skb)->seq) || - before(end_seq, TCP_SKB_CB(skb)->end_seq))) { + if (pcount > 1 && !in_sack && + after(TCP_SKB_CB(skb)->end_seq, start_seq)) { unsigned int pkt_len; - if (after(start_seq, TCP_SKB_CB(skb)->seq)) + in_sack = !after(start_seq, + TCP_SKB_CB(skb)->seq); + + if (!in_sack) pkt_len = (start_seq - TCP_SKB_CB(skb)->seq); else @@ -999,9 +1004,6 @@ tcp_sacktag_write_queue(struct sock *sk, struct sk_buff *ack_skb, u32 prior_snd_ fack_count += pcount; - in_sack = !after(start_seq, TCP_SKB_CB(skb)->seq) && - !before(end_seq, TCP_SKB_CB(skb)->end_seq); - sacked = TCP_SKB_CB(skb)->sacked; /* Account D-SACK for retransmitted packet. */ diff --git a/net/ipv4/tcp_minisocks.c b/net/ipv4/tcp_minisocks.c index a88db28..b1a63b2 100644 --- a/net/ipv4/tcp_minisocks.c +++ b/net/ipv4/tcp_minisocks.c @@ -384,7 +384,7 @@ struct sock *tcp_create_openreq_child(struct sock *sk, struct request_sock *req, newtp->frto_counter = 0; newtp->frto_highmark = 0; - newicsk->icsk_ca_ops = &tcp_reno; + newicsk->icsk_ca_ops = &tcp_init_congestion_ops; tcp_set_ca_state(newsk, TCP_CA_Open); tcp_init_xmit_timers(newsk); diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c index c10e443..d6e3d26 100644 --- a/net/ipv4/tcp_output.c +++ b/net/ipv4/tcp_output.c @@ -435,6 +435,8 @@ int tcp_fragment(struct sock *sk, struct sk_buff *skb, u32 len, unsigned int mss int nsize, old_factor; u16 flags; + BUG_ON(len >= skb->len); + nsize = skb_headlen(skb) - len; if (nsize < 0) nsize = 0; @@ -459,9 +461,7 @@ int tcp_fragment(struct sock *sk, struct sk_buff *skb, u32 len, unsigned int mss flags = TCP_SKB_CB(skb)->flags; TCP_SKB_CB(skb)->flags = flags & ~(TCPCB_FLAG_FIN|TCPCB_FLAG_PSH); TCP_SKB_CB(buff)->flags = flags; - TCP_SKB_CB(buff)->sacked = - (TCP_SKB_CB(skb)->sacked & - (TCPCB_LOST | TCPCB_EVER_RETRANS | TCPCB_AT_TAIL)); + TCP_SKB_CB(buff)->sacked = TCP_SKB_CB(skb)->sacked; TCP_SKB_CB(skb)->sacked &= ~TCPCB_AT_TAIL; if (!skb_shinfo(skb)->nr_frags && skb->ip_summed != CHECKSUM_HW) { @@ -499,11 +499,26 @@ int tcp_fragment(struct sock *sk, struct sk_buff *skb, u32 len, unsigned int mss tcp_skb_pcount(buff); tp->packets_out -= diff; + + if (TCP_SKB_CB(skb)->sacked & TCPCB_SACKED_ACKED) + tp->sacked_out -= diff; + if (TCP_SKB_CB(skb)->sacked & TCPCB_SACKED_RETRANS) + tp->retrans_out -= diff; + if (TCP_SKB_CB(skb)->sacked & TCPCB_LOST) { tp->lost_out -= diff; tp->left_out -= diff; } + if (diff > 0) { + /* Adjust Reno SACK estimate. */ + if (!tp->rx_opt.sack_ok) { + tp->sacked_out -= diff; + if ((int)tp->sacked_out < 0) + tp->sacked_out = 0; + tcp_sync_left_out(tp); + } + tp->fackets_out -= diff; if ((int)tp->fackets_out < 0) tp->fackets_out = 0; diff --git a/net/ipv6/mcast.c b/net/ipv6/mcast.c index 29fed6e..519899f 100644 --- a/net/ipv6/mcast.c +++ b/net/ipv6/mcast.c @@ -1968,7 +1968,7 @@ static void ip6_mc_clear_src(struct ifmcaddr6 *pmc) } pmc->mca_sources = NULL; pmc->mca_sfmode = MCAST_EXCLUDE; - pmc->mca_sfcount[MCAST_EXCLUDE] = 0; + pmc->mca_sfcount[MCAST_INCLUDE] = 0; pmc->mca_sfcount[MCAST_EXCLUDE] = 1; } diff --git a/net/ipv6/netfilter/ip6_tables.c b/net/ipv6/netfilter/ip6_tables.c index 1cb8adb..2da514b 100644 --- a/net/ipv6/netfilter/ip6_tables.c +++ b/net/ipv6/netfilter/ip6_tables.c @@ -1955,6 +1955,57 @@ static void __exit fini(void) #endif } +/* + * find specified header up to transport protocol header. + * If found target header, the offset to the header is set to *offset + * and return 0. otherwise, return -1. + * + * Notes: - non-1st Fragment Header isn't skipped. + * - ESP header isn't skipped. + * - The target header may be trancated. + */ +int ipv6_find_hdr(const struct sk_buff *skb, unsigned int *offset, u8 target) +{ + unsigned int start = (u8*)(skb->nh.ipv6h + 1) - skb->data; + u8 nexthdr = skb->nh.ipv6h->nexthdr; + unsigned int len = skb->len - start; + + while (nexthdr != target) { + struct ipv6_opt_hdr _hdr, *hp; + unsigned int hdrlen; + + if ((!ipv6_ext_hdr(nexthdr)) || nexthdr == NEXTHDR_NONE) + return -1; + hp = skb_header_pointer(skb, start, sizeof(_hdr), &_hdr); + if (hp == NULL) + return -1; + if (nexthdr == NEXTHDR_FRAGMENT) { + unsigned short _frag_off, *fp; + fp = skb_header_pointer(skb, + start+offsetof(struct frag_hdr, + frag_off), + sizeof(_frag_off), + &_frag_off); + if (fp == NULL) + return -1; + + if (ntohs(*fp) & ~0x7) + return -1; + hdrlen = 8; + } else if (nexthdr == NEXTHDR_AUTH) + hdrlen = (hp->hdrlen + 2) << 2; + else + hdrlen = ipv6_optlen(hp); + + nexthdr = hp->nexthdr; + len -= hdrlen; + start += hdrlen; + } + + *offset = start; + return 0; +} + EXPORT_SYMBOL(ip6t_register_table); EXPORT_SYMBOL(ip6t_unregister_table); EXPORT_SYMBOL(ip6t_do_table); @@ -1963,6 +2014,7 @@ EXPORT_SYMBOL(ip6t_unregister_match); EXPORT_SYMBOL(ip6t_register_target); EXPORT_SYMBOL(ip6t_unregister_target); EXPORT_SYMBOL(ip6t_ext_hdr); +EXPORT_SYMBOL(ipv6_find_hdr); module_init(init); module_exit(fini); diff --git a/net/ipv6/netfilter/ip6t_ah.c b/net/ipv6/netfilter/ip6t_ah.c index d5b94f1..dde3779 100644 --- a/net/ipv6/netfilter/ip6t_ah.c +++ b/net/ipv6/netfilter/ip6t_ah.c @@ -48,92 +48,21 @@ match(const struct sk_buff *skb, unsigned int protoff, int *hotdrop) { - struct ip_auth_hdr *ah = NULL, _ah; + struct ip_auth_hdr *ah, _ah; const struct ip6t_ah *ahinfo = matchinfo; - unsigned int temp; - int len; - u8 nexthdr; unsigned int ptr; unsigned int hdrlen = 0; - /*DEBUGP("IPv6 AH entered\n");*/ - /* if (opt->auth == 0) return 0; - * It does not filled on output */ - - /* type of the 1st exthdr */ - nexthdr = skb->nh.ipv6h->nexthdr; - /* pointer to the 1st exthdr */ - ptr = sizeof(struct ipv6hdr); - /* available length */ - len = skb->len - ptr; - temp = 0; - - while (ip6t_ext_hdr(nexthdr)) { - struct ipv6_opt_hdr _hdr, *hp; - - DEBUGP("ipv6_ah header iteration \n"); - - /* Is there enough space for the next ext header? */ - if (len < sizeof(struct ipv6_opt_hdr)) - return 0; - /* No more exthdr -> evaluate */ - if (nexthdr == NEXTHDR_NONE) - break; - /* ESP -> evaluate */ - if (nexthdr == NEXTHDR_ESP) - break; - - hp = skb_header_pointer(skb, ptr, sizeof(_hdr), &_hdr); - BUG_ON(hp == NULL); - - /* Calculate the header length */ - if (nexthdr == NEXTHDR_FRAGMENT) - hdrlen = 8; - else if (nexthdr == NEXTHDR_AUTH) - hdrlen = (hp->hdrlen+2)<<2; - else - hdrlen = ipv6_optlen(hp); - - /* AH -> evaluate */ - if (nexthdr == NEXTHDR_AUTH) { - temp |= MASK_AH; - break; - } - - - /* set the flag */ - switch (nexthdr) { - case NEXTHDR_HOP: - case NEXTHDR_ROUTING: - case NEXTHDR_FRAGMENT: - case NEXTHDR_AUTH: - case NEXTHDR_DEST: - break; - default: - DEBUGP("ipv6_ah match: unknown nextheader %u\n",nexthdr); - return 0; - } - - nexthdr = hp->nexthdr; - len -= hdrlen; - ptr += hdrlen; - if (ptr > skb->len) { - DEBUGP("ipv6_ah: new pointer too large! \n"); - break; - } - } - - /* AH header not found */ - if (temp != MASK_AH) + if (ipv6_find_hdr(skb, &ptr, NEXTHDR_AUTH) < 0) return 0; - if (len < sizeof(struct ip_auth_hdr)){ + ah = skb_header_pointer(skb, ptr, sizeof(_ah), &_ah); + if (ah == NULL) { *hotdrop = 1; return 0; } - ah = skb_header_pointer(skb, ptr, sizeof(_ah), &_ah); - BUG_ON(ah == NULL); + hdrlen = (ah->hdrlen + 2) << 2; DEBUGP("IPv6 AH LEN %u %u ", hdrlen, ah->hdrlen); DEBUGP("RES %04X ", ah->reserved); diff --git a/net/ipv6/netfilter/ip6t_dst.c b/net/ipv6/netfilter/ip6t_dst.c index 540925e..c450a63 100644 --- a/net/ipv6/netfilter/ip6t_dst.c +++ b/net/ipv6/netfilter/ip6t_dst.c @@ -63,8 +63,6 @@ match(const struct sk_buff *skb, struct ipv6_opt_hdr _optsh, *oh; const struct ip6t_opts *optinfo = matchinfo; unsigned int temp; - unsigned int len; - u8 nexthdr; unsigned int ptr; unsigned int hdrlen = 0; unsigned int ret = 0; @@ -72,97 +70,25 @@ match(const struct sk_buff *skb, u8 _optlen, *lp = NULL; unsigned int optlen; - /* type of the 1st exthdr */ - nexthdr = skb->nh.ipv6h->nexthdr; - /* pointer to the 1st exthdr */ - ptr = sizeof(struct ipv6hdr); - /* available length */ - len = skb->len - ptr; - temp = 0; - - while (ip6t_ext_hdr(nexthdr)) { - struct ipv6_opt_hdr _hdr, *hp; - - DEBUGP("ipv6_opts header iteration \n"); - - /* Is there enough space for the next ext header? */ - if (len < (int)sizeof(struct ipv6_opt_hdr)) - return 0; - /* No more exthdr -> evaluate */ - if (nexthdr == NEXTHDR_NONE) { - break; - } - /* ESP -> evaluate */ - if (nexthdr == NEXTHDR_ESP) { - break; - } - - hp = skb_header_pointer(skb, ptr, sizeof(_hdr), &_hdr); - BUG_ON(hp == NULL); - - /* Calculate the header length */ - if (nexthdr == NEXTHDR_FRAGMENT) { - hdrlen = 8; - } else if (nexthdr == NEXTHDR_AUTH) - hdrlen = (hp->hdrlen+2)<<2; - else - hdrlen = ipv6_optlen(hp); - - /* OPTS -> evaluate */ #if HOPBYHOP - if (nexthdr == NEXTHDR_HOP) { - temp |= MASK_HOPOPTS; + if (ipv6_find_hdr(skb, &ptr, NEXTHDR_HOP) < 0) #else - if (nexthdr == NEXTHDR_DEST) { - temp |= MASK_DSTOPTS; + if (ipv6_find_hdr(skb, &ptr, NEXTHDR_DEST) < 0) #endif - break; - } - + return 0; - /* set the flag */ - switch (nexthdr){ - case NEXTHDR_HOP: - case NEXTHDR_ROUTING: - case NEXTHDR_FRAGMENT: - case NEXTHDR_AUTH: - case NEXTHDR_DEST: - break; - default: - DEBUGP("ipv6_opts match: unknown nextheader %u\n",nexthdr); - return 0; - break; - } - - nexthdr = hp->nexthdr; - len -= hdrlen; - ptr += hdrlen; - if ( ptr > skb->len ) { - DEBUGP("ipv6_opts: new pointer is too large! \n"); - break; - } - } - - /* OPTIONS header not found */ -#if HOPBYHOP - if ( temp != MASK_HOPOPTS ) return 0; -#else - if ( temp != MASK_DSTOPTS ) return 0; -#endif - - if (len < (int)sizeof(struct ipv6_opt_hdr)){ + oh = skb_header_pointer(skb, ptr, sizeof(_optsh), &_optsh); + if (oh == NULL){ *hotdrop = 1; return 0; } - if (len < hdrlen){ + hdrlen = ipv6_optlen(oh); + if (skb->len - ptr < hdrlen){ /* Packet smaller than it's length field */ return 0; } - oh = skb_header_pointer(skb, ptr, sizeof(_optsh), &_optsh); - BUG_ON(oh == NULL); - DEBUGP("IPv6 OPTS LEN %u %u ", hdrlen, oh->hdrlen); DEBUGP("len %02X %04X %02X ", diff --git a/net/ipv6/netfilter/ip6t_esp.c b/net/ipv6/netfilter/ip6t_esp.c index e39dd23..24bc0cd 100644 --- a/net/ipv6/netfilter/ip6t_esp.c +++ b/net/ipv6/netfilter/ip6t_esp.c @@ -48,87 +48,22 @@ match(const struct sk_buff *skb, unsigned int protoff, int *hotdrop) { - struct ip_esp_hdr _esp, *eh = NULL; + struct ip_esp_hdr _esp, *eh; const struct ip6t_esp *espinfo = matchinfo; - unsigned int temp; - int len; - u8 nexthdr; unsigned int ptr; /* Make sure this isn't an evil packet */ /*DEBUGP("ipv6_esp entered \n");*/ - /* type of the 1st exthdr */ - nexthdr = skb->nh.ipv6h->nexthdr; - /* pointer to the 1st exthdr */ - ptr = sizeof(struct ipv6hdr); - /* available length */ - len = skb->len - ptr; - temp = 0; - - while (ip6t_ext_hdr(nexthdr)) { - struct ipv6_opt_hdr _hdr, *hp; - int hdrlen; - - DEBUGP("ipv6_esp header iteration \n"); - - /* Is there enough space for the next ext header? */ - if (len < sizeof(struct ipv6_opt_hdr)) - return 0; - /* No more exthdr -> evaluate */ - if (nexthdr == NEXTHDR_NONE) - break; - /* ESP -> evaluate */ - if (nexthdr == NEXTHDR_ESP) { - temp |= MASK_ESP; - break; - } - - hp = skb_header_pointer(skb, ptr, sizeof(_hdr), &_hdr); - BUG_ON(hp == NULL); - - /* Calculate the header length */ - if (nexthdr == NEXTHDR_FRAGMENT) - hdrlen = 8; - else if (nexthdr == NEXTHDR_AUTH) - hdrlen = (hp->hdrlen+2)<<2; - else - hdrlen = ipv6_optlen(hp); - - /* set the flag */ - switch (nexthdr) { - case NEXTHDR_HOP: - case NEXTHDR_ROUTING: - case NEXTHDR_FRAGMENT: - case NEXTHDR_AUTH: - case NEXTHDR_DEST: - break; - default: - DEBUGP("ipv6_esp match: unknown nextheader %u\n",nexthdr); - return 0; - } - - nexthdr = hp->nexthdr; - len -= hdrlen; - ptr += hdrlen; - if (ptr > skb->len) { - DEBUGP("ipv6_esp: new pointer too large! \n"); - break; - } - } - - /* ESP header not found */ - if (temp != MASK_ESP) + if (ipv6_find_hdr(skb, &ptr, NEXTHDR_ESP) < 0) return 0; - if (len < sizeof(struct ip_esp_hdr)) { + eh = skb_header_pointer(skb, ptr, sizeof(_esp), &_esp); + if (eh == NULL) { *hotdrop = 1; return 0; } - eh = skb_header_pointer(skb, ptr, sizeof(_esp), &_esp); - BUG_ON(eh == NULL); - DEBUGP("IPv6 ESP SPI %u %08X\n", ntohl(eh->spi), ntohl(eh->spi)); return (eh != NULL) diff --git a/net/ipv6/netfilter/ip6t_frag.c b/net/ipv6/netfilter/ip6t_frag.c index 4bfa30a..085d5f8 100644 --- a/net/ipv6/netfilter/ip6t_frag.c +++ b/net/ipv6/netfilter/ip6t_frag.c @@ -48,90 +48,18 @@ match(const struct sk_buff *skb, unsigned int protoff, int *hotdrop) { - struct frag_hdr _frag, *fh = NULL; + struct frag_hdr _frag, *fh; const struct ip6t_frag *fraginfo = matchinfo; - unsigned int temp; - int len; - u8 nexthdr; unsigned int ptr; - unsigned int hdrlen = 0; - - /* type of the 1st exthdr */ - nexthdr = skb->nh.ipv6h->nexthdr; - /* pointer to the 1st exthdr */ - ptr = sizeof(struct ipv6hdr); - /* available length */ - len = skb->len - ptr; - temp = 0; - - while (ip6t_ext_hdr(nexthdr)) { - struct ipv6_opt_hdr _hdr, *hp; - - DEBUGP("ipv6_frag header iteration \n"); - - /* Is there enough space for the next ext header? */ - if (len < (int)sizeof(struct ipv6_opt_hdr)) - return 0; - /* No more exthdr -> evaluate */ - if (nexthdr == NEXTHDR_NONE) { - break; - } - /* ESP -> evaluate */ - if (nexthdr == NEXTHDR_ESP) { - break; - } - - hp = skb_header_pointer(skb, ptr, sizeof(_hdr), &_hdr); - BUG_ON(hp == NULL); - - /* Calculate the header length */ - if (nexthdr == NEXTHDR_FRAGMENT) { - hdrlen = 8; - } else if (nexthdr == NEXTHDR_AUTH) - hdrlen = (hp->hdrlen+2)<<2; - else - hdrlen = ipv6_optlen(hp); - - /* FRAG -> evaluate */ - if (nexthdr == NEXTHDR_FRAGMENT) { - temp |= MASK_FRAGMENT; - break; - } - - - /* set the flag */ - switch (nexthdr){ - case NEXTHDR_HOP: - case NEXTHDR_ROUTING: - case NEXTHDR_FRAGMENT: - case NEXTHDR_AUTH: - case NEXTHDR_DEST: - break; - default: - DEBUGP("ipv6_frag match: unknown nextheader %u\n",nexthdr); - return 0; - break; - } - - nexthdr = hp->nexthdr; - len -= hdrlen; - ptr += hdrlen; - if ( ptr > skb->len ) { - DEBUGP("ipv6_frag: new pointer too large! \n"); - break; - } - } - - /* FRAG header not found */ - if ( temp != MASK_FRAGMENT ) return 0; - - if (len < sizeof(struct frag_hdr)){ - *hotdrop = 1; - return 0; - } - fh = skb_header_pointer(skb, ptr, sizeof(_frag), &_frag); - BUG_ON(fh == NULL); + if (ipv6_find_hdr(skb, &ptr, NEXTHDR_FRAGMENT) < 0) + return 0; + + fh = skb_header_pointer(skb, ptr, sizeof(_frag), &_frag); + if (fh == NULL){ + *hotdrop = 1; + return 0; + } DEBUGP("INFO %04X ", fh->frag_off); DEBUGP("OFFSET %04X ", ntohs(fh->frag_off) & ~0x7); diff --git a/net/ipv6/netfilter/ip6t_hbh.c b/net/ipv6/netfilter/ip6t_hbh.c index 27f3650..1d09485 100644 --- a/net/ipv6/netfilter/ip6t_hbh.c +++ b/net/ipv6/netfilter/ip6t_hbh.c @@ -63,8 +63,6 @@ match(const struct sk_buff *skb, struct ipv6_opt_hdr _optsh, *oh; const struct ip6t_opts *optinfo = matchinfo; unsigned int temp; - unsigned int len; - u8 nexthdr; unsigned int ptr; unsigned int hdrlen = 0; unsigned int ret = 0; @@ -72,97 +70,25 @@ match(const struct sk_buff *skb, u8 _optlen, *lp = NULL; unsigned int optlen; - /* type of the 1st exthdr */ - nexthdr = skb->nh.ipv6h->nexthdr; - /* pointer to the 1st exthdr */ - ptr = sizeof(struct ipv6hdr); - /* available length */ - len = skb->len - ptr; - temp = 0; - - while (ip6t_ext_hdr(nexthdr)) { - struct ipv6_opt_hdr _hdr, *hp; - - DEBUGP("ipv6_opts header iteration \n"); - - /* Is there enough space for the next ext header? */ - if (len < (int)sizeof(struct ipv6_opt_hdr)) - return 0; - /* No more exthdr -> evaluate */ - if (nexthdr == NEXTHDR_NONE) { - break; - } - /* ESP -> evaluate */ - if (nexthdr == NEXTHDR_ESP) { - break; - } - - hp = skb_header_pointer(skb, ptr, sizeof(_hdr), &_hdr); - BUG_ON(hp == NULL); - - /* Calculate the header length */ - if (nexthdr == NEXTHDR_FRAGMENT) { - hdrlen = 8; - } else if (nexthdr == NEXTHDR_AUTH) - hdrlen = (hp->hdrlen+2)<<2; - else - hdrlen = ipv6_optlen(hp); - - /* OPTS -> evaluate */ #if HOPBYHOP - if (nexthdr == NEXTHDR_HOP) { - temp |= MASK_HOPOPTS; + if (ipv6_find_hdr(skb, &ptr, NEXTHDR_HOP) < 0) #else - if (nexthdr == NEXTHDR_DEST) { - temp |= MASK_DSTOPTS; + if (ipv6_find_hdr(skb, &ptr, NEXTHDR_DEST) < 0) #endif - break; - } - + return 0; - /* set the flag */ - switch (nexthdr){ - case NEXTHDR_HOP: - case NEXTHDR_ROUTING: - case NEXTHDR_FRAGMENT: - case NEXTHDR_AUTH: - case NEXTHDR_DEST: - break; - default: - DEBUGP("ipv6_opts match: unknown nextheader %u\n",nexthdr); - return 0; - break; - } - - nexthdr = hp->nexthdr; - len -= hdrlen; - ptr += hdrlen; - if ( ptr > skb->len ) { - DEBUGP("ipv6_opts: new pointer is too large! \n"); - break; - } - } - - /* OPTIONS header not found */ -#if HOPBYHOP - if ( temp != MASK_HOPOPTS ) return 0; -#else - if ( temp != MASK_DSTOPTS ) return 0; -#endif - - if (len < (int)sizeof(struct ipv6_opt_hdr)){ + oh = skb_header_pointer(skb, ptr, sizeof(_optsh), &_optsh); + if (oh == NULL){ *hotdrop = 1; return 0; } - if (len < hdrlen){ + hdrlen = ipv6_optlen(oh); + if (skb->len - ptr < hdrlen){ /* Packet smaller than it's length field */ return 0; } - oh = skb_header_pointer(skb, ptr, sizeof(_optsh), &_optsh); - BUG_ON(oh == NULL); - DEBUGP("IPv6 OPTS LEN %u %u ", hdrlen, oh->hdrlen); DEBUGP("len %02X %04X %02X ", diff --git a/net/ipv6/netfilter/ip6t_rt.c b/net/ipv6/netfilter/ip6t_rt.c index 2bb6700..beb2fd5 100644 --- a/net/ipv6/netfilter/ip6t_rt.c +++ b/net/ipv6/netfilter/ip6t_rt.c @@ -50,98 +50,29 @@ match(const struct sk_buff *skb, unsigned int protoff, int *hotdrop) { - struct ipv6_rt_hdr _route, *rh = NULL; + struct ipv6_rt_hdr _route, *rh; const struct ip6t_rt *rtinfo = matchinfo; unsigned int temp; - unsigned int len; - u8 nexthdr; unsigned int ptr; unsigned int hdrlen = 0; unsigned int ret = 0; struct in6_addr *ap, _addr; - /* type of the 1st exthdr */ - nexthdr = skb->nh.ipv6h->nexthdr; - /* pointer to the 1st exthdr */ - ptr = sizeof(struct ipv6hdr); - /* available length */ - len = skb->len - ptr; - temp = 0; + if (ipv6_find_hdr(skb, &ptr, NEXTHDR_ROUTING) < 0) + return 0; - while (ip6t_ext_hdr(nexthdr)) { - struct ipv6_opt_hdr _hdr, *hp; - - DEBUGP("ipv6_rt header iteration \n"); - - /* Is there enough space for the next ext header? */ - if (len < (int)sizeof(struct ipv6_opt_hdr)) - return 0; - /* No more exthdr -> evaluate */ - if (nexthdr == NEXTHDR_NONE) { - break; - } - /* ESP -> evaluate */ - if (nexthdr == NEXTHDR_ESP) { - break; - } - - hp = skb_header_pointer(skb, ptr, sizeof(_hdr), &_hdr); - BUG_ON(hp == NULL); - - /* Calculate the header length */ - if (nexthdr == NEXTHDR_FRAGMENT) { - hdrlen = 8; - } else if (nexthdr == NEXTHDR_AUTH) - hdrlen = (hp->hdrlen+2)<<2; - else - hdrlen = ipv6_optlen(hp); - - /* ROUTING -> evaluate */ - if (nexthdr == NEXTHDR_ROUTING) { - temp |= MASK_ROUTING; - break; - } - - - /* set the flag */ - switch (nexthdr){ - case NEXTHDR_HOP: - case NEXTHDR_ROUTING: - case NEXTHDR_FRAGMENT: - case NEXTHDR_AUTH: - case NEXTHDR_DEST: - break; - default: - DEBUGP("ipv6_rt match: unknown nextheader %u\n",nexthdr); - return 0; - break; - } - - nexthdr = hp->nexthdr; - len -= hdrlen; - ptr += hdrlen; - if ( ptr > skb->len ) { - DEBUGP("ipv6_rt: new pointer is too large! \n"); - break; - } - } - - /* ROUTING header not found */ - if ( temp != MASK_ROUTING ) return 0; - - if (len < (int)sizeof(struct ipv6_rt_hdr)){ + rh = skb_header_pointer(skb, ptr, sizeof(_route), &_route); + if (rh == NULL){ *hotdrop = 1; return 0; } - if (len < hdrlen){ + hdrlen = ipv6_optlen(rh); + if (skb->len - ptr < hdrlen){ /* Pcket smaller than its length field */ return 0; } - rh = skb_header_pointer(skb, ptr, sizeof(_route), &_route); - BUG_ON(rh == NULL); - DEBUGP("IPv6 RT LEN %u %u ", hdrlen, rh->hdrlen); DEBUGP("TYPE %04X ", rh->type); DEBUGP("SGS_LEFT %u %02X\n", rh->segments_left, rh->segments_left); diff --git a/net/ipv6/raw.c b/net/ipv6/raw.c index 5aa3691..a1265a3 100644 --- a/net/ipv6/raw.c +++ b/net/ipv6/raw.c @@ -627,7 +627,7 @@ static void rawv6_probe_proto_opt(struct flowi *fl, struct msghdr *msg) if (type && code) { get_user(fl->fl_icmp_type, type); - __get_user(fl->fl_icmp_code, code); + get_user(fl->fl_icmp_code, code); probed = 1; } break; diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c index 69b1468..6001948 100644 --- a/net/ipv6/udp.c +++ b/net/ipv6/udp.c @@ -405,9 +405,8 @@ static struct sock *udp_v6_mcast_next(struct sock *sk, continue; if (!ipv6_addr_any(&np->rcv_saddr)) { - if (ipv6_addr_equal(&np->rcv_saddr, loc_addr)) - return s; - continue; + if (!ipv6_addr_equal(&np->rcv_saddr, loc_addr)) + continue; } if(!inet6_mc_check(s, loc_addr, rmt_addr)) continue; @@ -640,6 +639,7 @@ static int udpv6_sendmsg(struct kiocb *iocb, struct sock *sk, int tclass = -1; int corkreq = up->corkflag || msg->msg_flags&MSG_MORE; int err; + int connected = 0; /* destination address check */ if (sin6) { @@ -749,6 +749,7 @@ do_udp_sendmsg: fl->fl_ip_dport = inet->dport; daddr = &np->daddr; fl->fl6_flowlabel = np->flow_label; + connected = 1; } if (!fl->oif) @@ -771,6 +772,7 @@ do_udp_sendmsg: } if (!(opt->opt_nflen|opt->opt_flen)) opt = NULL; + connected = 0; } if (opt == NULL) opt = np->opt; @@ -788,10 +790,13 @@ do_udp_sendmsg: ipv6_addr_copy(&final, &fl->fl6_dst); ipv6_addr_copy(&fl->fl6_dst, rt0->addr); final_p = &final; + connected = 0; } - if (!fl->oif && ipv6_addr_is_multicast(&fl->fl6_dst)) + if (!fl->oif && ipv6_addr_is_multicast(&fl->fl6_dst)) { fl->oif = np->mcast_oif; + connected = 0; + } err = ip6_dst_lookup(sk, &dst, fl); if (err) @@ -847,7 +852,7 @@ do_append_data: else if (!corkreq) err = udp_v6_push_pending_frames(sk, up); - if (dst) + if (dst && connected) ip6_dst_store(sk, dst, ipv6_addr_equal(&fl->fl6_dst, &np->daddr) ? &np->daddr : NULL); diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c index 8690f17..ee865d8 100644 --- a/net/packet/af_packet.c +++ b/net/packet/af_packet.c @@ -36,6 +36,11 @@ * Michal Ostrowski : Module initialization cleanup. * Ulises Alonso : Frame number limit removal and * packet_set_ring memory leak. + * Eric Biederman : Allow for > 8 byte hardware addresses. + * The convention is that longer addresses + * will simply extend the hardware address + * byte arrays at the end of sockaddr_ll + * and packet_mreq. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -161,7 +166,17 @@ struct packet_mclist int count; unsigned short type; unsigned short alen; - unsigned char addr[8]; + unsigned char addr[MAX_ADDR_LEN]; +}; +/* identical to struct packet_mreq except it has + * a longer address field. + */ +struct packet_mreq_max +{ + int mr_ifindex; + unsigned short mr_type; + unsigned short mr_alen; + unsigned char mr_address[MAX_ADDR_LEN]; }; #endif #ifdef CONFIG_PACKET_MMAP @@ -716,6 +731,8 @@ static int packet_sendmsg(struct kiocb *iocb, struct socket *sock, err = -EINVAL; if (msg->msg_namelen < sizeof(struct sockaddr_ll)) goto out; + if (msg->msg_namelen < (saddr->sll_halen + offsetof(struct sockaddr_ll, sll_addr))) + goto out; ifindex = saddr->sll_ifindex; proto = saddr->sll_protocol; addr = saddr->sll_addr; @@ -744,6 +761,12 @@ static int packet_sendmsg(struct kiocb *iocb, struct socket *sock, if (dev->hard_header) { int res; err = -EINVAL; + if (saddr) { + if (saddr->sll_halen != dev->addr_len) + goto out_free; + if (saddr->sll_hatype != dev->type) + goto out_free; + } res = dev->hard_header(skb, dev, ntohs(proto), addr, NULL, len); if (sock->type != SOCK_DGRAM) { skb->tail = skb->data; @@ -1045,6 +1068,7 @@ static int packet_recvmsg(struct kiocb *iocb, struct socket *sock, struct sock *sk = sock->sk; struct sk_buff *skb; int copied, err; + struct sockaddr_ll *sll; err = -EINVAL; if (flags & ~(MSG_PEEK|MSG_DONTWAIT|MSG_TRUNC|MSG_CMSG_COMPAT)) @@ -1057,16 +1081,6 @@ static int packet_recvmsg(struct kiocb *iocb, struct socket *sock, #endif /* - * If the address length field is there to be filled in, we fill - * it in now. - */ - - if (sock->type == SOCK_PACKET) - msg->msg_namelen = sizeof(struct sockaddr_pkt); - else - msg->msg_namelen = sizeof(struct sockaddr_ll); - - /* * Call the generic datagram receiver. This handles all sorts * of horrible races and re-entrancy so we can forget about it * in the protocol layers. @@ -1087,6 +1101,17 @@ static int packet_recvmsg(struct kiocb *iocb, struct socket *sock, goto out; /* + * If the address length field is there to be filled in, we fill + * it in now. + */ + + sll = (struct sockaddr_ll*)skb->cb; + if (sock->type == SOCK_PACKET) + msg->msg_namelen = sizeof(struct sockaddr_pkt); + else + msg->msg_namelen = sll->sll_halen + offsetof(struct sockaddr_ll, sll_addr); + + /* * You lose any data beyond the buffer you gave. If it worries a * user program they can ask the device for its MTU anyway. */ @@ -1166,7 +1191,7 @@ static int packet_getname(struct socket *sock, struct sockaddr *uaddr, sll->sll_hatype = 0; /* Bad: we have no ARPHRD_UNSPEC */ sll->sll_halen = 0; } - *uaddr_len = sizeof(*sll); + *uaddr_len = offsetof(struct sockaddr_ll, sll_addr) + sll->sll_halen; return 0; } @@ -1199,7 +1224,7 @@ static void packet_dev_mclist(struct net_device *dev, struct packet_mclist *i, i } } -static int packet_mc_add(struct sock *sk, struct packet_mreq *mreq) +static int packet_mc_add(struct sock *sk, struct packet_mreq_max *mreq) { struct packet_sock *po = pkt_sk(sk); struct packet_mclist *ml, *i; @@ -1249,7 +1274,7 @@ done: return err; } -static int packet_mc_drop(struct sock *sk, struct packet_mreq *mreq) +static int packet_mc_drop(struct sock *sk, struct packet_mreq_max *mreq) { struct packet_mclist *ml, **mlp; @@ -1315,11 +1340,17 @@ packet_setsockopt(struct socket *sock, int level, int optname, char __user *optv case PACKET_ADD_MEMBERSHIP: case PACKET_DROP_MEMBERSHIP: { - struct packet_mreq mreq; - if (optlen<sizeof(mreq)) + struct packet_mreq_max mreq; + int len = optlen; + memset(&mreq, 0, sizeof(mreq)); + if (len < sizeof(struct packet_mreq)) return -EINVAL; - if (copy_from_user(&mreq,optval,sizeof(mreq))) + if (len > sizeof(mreq)) + len = sizeof(mreq); + if (copy_from_user(&mreq,optval,len)) return -EFAULT; + if (len < (mreq.mr_alen + offsetof(struct packet_mreq, mr_address))) + return -EINVAL; if (optname == PACKET_ADD_MEMBERSHIP) ret = packet_mc_add(sk, &mreq); else diff --git a/net/sctp/sm_statefuns.c b/net/sctp/sm_statefuns.c index 86073df..505c7de1 100644 --- a/net/sctp/sm_statefuns.c +++ b/net/sctp/sm_statefuns.c @@ -2414,6 +2414,17 @@ sctp_disposition_t sctp_sf_do_9_2_shutdown(const struct sctp_endpoint *ep, skb_pull(chunk->skb, sizeof(sctp_shutdownhdr_t)); chunk->subh.shutdown_hdr = sdh; + /* API 5.3.1.5 SCTP_SHUTDOWN_EVENT + * When a peer sends a SHUTDOWN, SCTP delivers this notification to + * inform the application that it should cease sending data. + */ + ev = sctp_ulpevent_make_shutdown_event(asoc, 0, GFP_ATOMIC); + if (!ev) { + disposition = SCTP_DISPOSITION_NOMEM; + goto out; + } + sctp_add_cmd_sf(commands, SCTP_CMD_EVENT_ULP, SCTP_ULPEVENT(ev)); + /* Upon the reception of the SHUTDOWN, the peer endpoint shall * - enter the SHUTDOWN-RECEIVED state, * - stop accepting new data from its SCTP user @@ -2439,17 +2450,6 @@ sctp_disposition_t sctp_sf_do_9_2_shutdown(const struct sctp_endpoint *ep, sctp_add_cmd_sf(commands, SCTP_CMD_PROCESS_CTSN, SCTP_U32(chunk->subh.shutdown_hdr->cum_tsn_ack)); - /* API 5.3.1.5 SCTP_SHUTDOWN_EVENT - * When a peer sends a SHUTDOWN, SCTP delivers this notification to - * inform the application that it should cease sending data. - */ - ev = sctp_ulpevent_make_shutdown_event(asoc, 0, GFP_ATOMIC); - if (!ev) { - disposition = SCTP_DISPOSITION_NOMEM; - goto out; - } - sctp_add_cmd_sf(commands, SCTP_CMD_EVENT_ULP, SCTP_ULPEVENT(ev)); - out: return disposition; } diff --git a/net/socket.c b/net/socket.c index c699e93..f926447 100644 --- a/net/socket.c +++ b/net/socket.c @@ -1862,7 +1862,8 @@ asmlinkage long sys_recvmsg(int fd, struct msghdr __user *msg, unsigned int flag if (err < 0) goto out_freeiov; } - err = __put_user(msg_sys.msg_flags, COMPAT_FLAGS(msg)); + err = __put_user((msg_sys.msg_flags & ~MSG_CMSG_COMPAT), + COMPAT_FLAGS(msg)); if (err) goto out_freeiov; if (MSG_CMSG_COMPAT & flags) diff --git a/net/sunrpc/svcsock.c b/net/sunrpc/svcsock.c index 51885b5..30ec3ef 100644 --- a/net/sunrpc/svcsock.c +++ b/net/sunrpc/svcsock.c @@ -512,15 +512,14 @@ svc_sock_setbufsize(struct socket *sock, unsigned int snd, unsigned int rcv) static void svc_udp_data_ready(struct sock *sk, int count) { - struct svc_sock *svsk = (struct svc_sock *)(sk->sk_user_data); + struct svc_sock *svsk = (struct svc_sock *)sk->sk_user_data; - if (!svsk) - goto out; - dprintk("svc: socket %p(inet %p), count=%d, busy=%d\n", - svsk, sk, count, test_bit(SK_BUSY, &svsk->sk_flags)); - set_bit(SK_DATA, &svsk->sk_flags); - svc_sock_enqueue(svsk); - out: + if (svsk) { + dprintk("svc: socket %p(inet %p), count=%d, busy=%d\n", + svsk, sk, count, test_bit(SK_BUSY, &svsk->sk_flags)); + set_bit(SK_DATA, &svsk->sk_flags); + svc_sock_enqueue(svsk); + } if (sk->sk_sleep && waitqueue_active(sk->sk_sleep)) wake_up_interruptible(sk->sk_sleep); } @@ -540,7 +539,7 @@ svc_write_space(struct sock *sk) } if (sk->sk_sleep && waitqueue_active(sk->sk_sleep)) { - printk(KERN_WARNING "RPC svc_write_space: some sleeping on %p\n", + dprintk("RPC svc_write_space: someone sleeping on %p\n", svsk); wake_up_interruptible(sk->sk_sleep); } @@ -692,31 +691,29 @@ svc_udp_init(struct svc_sock *svsk) static void svc_tcp_listen_data_ready(struct sock *sk, int count_unused) { - struct svc_sock *svsk; + struct svc_sock *svsk = (struct svc_sock *)sk->sk_user_data; dprintk("svc: socket %p TCP (listen) state change %d\n", - sk, sk->sk_state); + sk, sk->sk_state); - if (sk->sk_state != TCP_LISTEN) { - /* - * This callback may called twice when a new connection - * is established as a child socket inherits everything - * from a parent LISTEN socket. - * 1) data_ready method of the parent socket will be called - * when one of child sockets become ESTABLISHED. - * 2) data_ready method of the child socket may be called - * when it receives data before the socket is accepted. - * In case of 2, we should ignore it silently. - */ - goto out; - } - if (!(svsk = (struct svc_sock *) sk->sk_user_data)) { - printk("svc: socket %p: no user data\n", sk); - goto out; + /* + * This callback may called twice when a new connection + * is established as a child socket inherits everything + * from a parent LISTEN socket. + * 1) data_ready method of the parent socket will be called + * when one of child sockets become ESTABLISHED. + * 2) data_ready method of the child socket may be called + * when it receives data before the socket is accepted. + * In case of 2, we should ignore it silently. + */ + if (sk->sk_state == TCP_LISTEN) { + if (svsk) { + set_bit(SK_CONN, &svsk->sk_flags); + svc_sock_enqueue(svsk); + } else + printk("svc: socket %p: no user data\n", sk); } - set_bit(SK_CONN, &svsk->sk_flags); - svc_sock_enqueue(svsk); - out: + if (sk->sk_sleep && waitqueue_active(sk->sk_sleep)) wake_up_interruptible_all(sk->sk_sleep); } @@ -727,18 +724,17 @@ svc_tcp_listen_data_ready(struct sock *sk, int count_unused) static void svc_tcp_state_change(struct sock *sk) { - struct svc_sock *svsk; + struct svc_sock *svsk = (struct svc_sock *)sk->sk_user_data; dprintk("svc: socket %p TCP (connected) state change %d (svsk %p)\n", - sk, sk->sk_state, sk->sk_user_data); + sk, sk->sk_state, sk->sk_user_data); - if (!(svsk = (struct svc_sock *) sk->sk_user_data)) { + if (!svsk) printk("svc: socket %p: no user data\n", sk); - goto out; + else { + set_bit(SK_CLOSE, &svsk->sk_flags); + svc_sock_enqueue(svsk); } - set_bit(SK_CLOSE, &svsk->sk_flags); - svc_sock_enqueue(svsk); - out: if (sk->sk_sleep && waitqueue_active(sk->sk_sleep)) wake_up_interruptible_all(sk->sk_sleep); } @@ -746,15 +742,14 @@ svc_tcp_state_change(struct sock *sk) static void svc_tcp_data_ready(struct sock *sk, int count) { - struct svc_sock * svsk; + struct svc_sock *svsk = (struct svc_sock *)sk->sk_user_data; dprintk("svc: socket %p TCP data ready (svsk %p)\n", - sk, sk->sk_user_data); - if (!(svsk = (struct svc_sock *)(sk->sk_user_data))) - goto out; - set_bit(SK_DATA, &svsk->sk_flags); - svc_sock_enqueue(svsk); - out: + sk, sk->sk_user_data); + if (svsk) { + set_bit(SK_DATA, &svsk->sk_flags); + svc_sock_enqueue(svsk); + } if (sk->sk_sleep && waitqueue_active(sk->sk_sleep)) wake_up_interruptible(sk->sk_sleep); } diff --git a/security/Kconfig b/security/Kconfig index dcf04a0..64d3f1e 100644 --- a/security/Kconfig +++ b/security/Kconfig @@ -35,6 +35,7 @@ config KEYS_DEBUG_PROC_KEYS config SECURITY bool "Enable different security models" + depends on SYSFS help This allows you to choose different security modules to be configured into your kernel. diff --git a/security/Makefile b/security/Makefile index 197cc2f..8cbbf2f 100644 --- a/security/Makefile +++ b/security/Makefile @@ -11,7 +11,7 @@ obj-y += commoncap.o endif # Object file lists -obj-$(CONFIG_SECURITY) += security.o dummy.o +obj-$(CONFIG_SECURITY) += security.o dummy.o inode.o # Must precede capability.o in order to stack properly. obj-$(CONFIG_SECURITY_SELINUX) += selinux/built-in.o obj-$(CONFIG_SECURITY_CAPABILITIES) += commoncap.o capability.o diff --git a/security/inode.c b/security/inode.c new file mode 100644 index 0000000..a596450 --- /dev/null +++ b/security/inode.c @@ -0,0 +1,347 @@ +/* + * inode.c - securityfs + * + * Copyright (C) 2005 Greg Kroah-Hartman <gregkh@suse.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. + * + * Based on fs/debugfs/inode.c which had the following copyright notice: + * Copyright (C) 2004 Greg Kroah-Hartman <greg@kroah.com> + * Copyright (C) 2004 IBM Inc. + */ + +/* #define DEBUG */ +#include <linux/config.h> +#include <linux/module.h> +#include <linux/fs.h> +#include <linux/mount.h> +#include <linux/pagemap.h> +#include <linux/init.h> +#include <linux/namei.h> +#include <linux/security.h> + +#define SECURITYFS_MAGIC 0x73636673 + +static struct vfsmount *mount; +static int mount_count; + +/* + * TODO: + * I think I can get rid of these default_file_ops, but not quite sure... + */ +static ssize_t default_read_file(struct file *file, char __user *buf, + size_t count, loff_t *ppos) +{ + return 0; +} + +static ssize_t default_write_file(struct file *file, const char __user *buf, + size_t count, loff_t *ppos) +{ + return count; +} + +static int default_open(struct inode *inode, struct file *file) +{ + if (inode->u.generic_ip) + file->private_data = inode->u.generic_ip; + + return 0; +} + +static struct file_operations default_file_ops = { + .read = default_read_file, + .write = default_write_file, + .open = default_open, +}; + +static struct inode *get_inode(struct super_block *sb, int mode, dev_t dev) +{ + struct inode *inode = new_inode(sb); + + if (inode) { + inode->i_mode = mode; + inode->i_uid = 0; + inode->i_gid = 0; + inode->i_blksize = PAGE_CACHE_SIZE; + inode->i_blocks = 0; + inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME; + switch (mode & S_IFMT) { + default: + init_special_inode(inode, mode, dev); + break; + case S_IFREG: + inode->i_fop = &default_file_ops; + break; + case S_IFDIR: + inode->i_op = &simple_dir_inode_operations; + inode->i_fop = &simple_dir_operations; + + /* directory inodes start off with i_nlink == 2 (for "." entry) */ + inode->i_nlink++; + break; + } + } + return inode; +} + +/* SMP-safe */ +static int mknod(struct inode *dir, struct dentry *dentry, + int mode, dev_t dev) +{ + struct inode *inode; + int error = -EPERM; + + if (dentry->d_inode) + return -EEXIST; + + inode = get_inode(dir->i_sb, mode, dev); + if (inode) { + d_instantiate(dentry, inode); + dget(dentry); + error = 0; + } + return error; +} + +static int mkdir(struct inode *dir, struct dentry *dentry, int mode) +{ + int res; + + mode = (mode & (S_IRWXUGO | S_ISVTX)) | S_IFDIR; + res = mknod(dir, dentry, mode, 0); + if (!res) + dir->i_nlink++; + return res; +} + +static int create(struct inode *dir, struct dentry *dentry, int mode) +{ + mode = (mode & S_IALLUGO) | S_IFREG; + return mknod(dir, dentry, mode, 0); +} + +static inline int positive(struct dentry *dentry) +{ + return dentry->d_inode && !d_unhashed(dentry); +} + +static int fill_super(struct super_block *sb, void *data, int silent) +{ + static struct tree_descr files[] = {{""}}; + + return simple_fill_super(sb, SECURITYFS_MAGIC, files); +} + +static struct super_block *get_sb(struct file_system_type *fs_type, + int flags, const char *dev_name, + void *data) +{ + return get_sb_single(fs_type, flags, data, fill_super); +} + +static struct file_system_type fs_type = { + .owner = THIS_MODULE, + .name = "securityfs", + .get_sb = get_sb, + .kill_sb = kill_litter_super, +}; + +static int create_by_name(const char *name, mode_t mode, + struct dentry *parent, + struct dentry **dentry) +{ + int error = 0; + + *dentry = NULL; + + /* If the parent is not specified, we create it in the root. + * We need the root dentry to do this, which is in the super + * block. A pointer to that is in the struct vfsmount that we + * have around. + */ + if (!parent ) { + if (mount && mount->mnt_sb) { + parent = mount->mnt_sb->s_root; + } + } + if (!parent) { + pr_debug("securityfs: Ah! can not find a parent!\n"); + return -EFAULT; + } + + down(&parent->d_inode->i_sem); + *dentry = lookup_one_len(name, parent, strlen(name)); + if (!IS_ERR(dentry)) { + if ((mode & S_IFMT) == S_IFDIR) + error = mkdir(parent->d_inode, *dentry, mode); + else + error = create(parent->d_inode, *dentry, mode); + } else + error = PTR_ERR(dentry); + up(&parent->d_inode->i_sem); + + return error; +} + +/** + * securityfs_create_file - create a file in the securityfs filesystem + * + * @name: a pointer to a string containing the name of the file to create. + * @mode: the permission that the file should have + * @parent: a pointer to the parent dentry for this file. This should be a + * directory dentry if set. If this paramater is NULL, then the + * file will be created in the root of the securityfs filesystem. + * @data: a pointer to something that the caller will want to get to later + * on. The inode.u.generic_ip pointer will point to this value on + * the open() call. + * @fops: a pointer to a struct file_operations that should be used for + * this file. + * + * This is the basic "create a file" function for securityfs. It allows for a + * wide range of flexibility in createing a file, or a directory (if you + * want to create a directory, the securityfs_create_dir() function is + * recommended to be used instead.) + * + * This function will return a pointer to a dentry if it succeeds. This + * pointer must be passed to the securityfs_remove() function when the file is + * to be removed (no automatic cleanup happens if your module is unloaded, + * you are responsible here.) If an error occurs, NULL will be returned. + * + * If securityfs is not enabled in the kernel, the value -ENODEV will be + * returned. It is not wise to check for this value, but rather, check for + * NULL or !NULL instead as to eliminate the need for #ifdef in the calling + * code. + */ +struct dentry *securityfs_create_file(const char *name, mode_t mode, + struct dentry *parent, void *data, + struct file_operations *fops) +{ + struct dentry *dentry = NULL; + int error; + + pr_debug("securityfs: creating file '%s'\n",name); + + error = simple_pin_fs("securityfs", &mount, &mount_count); + if (error) { + dentry = ERR_PTR(error); + goto exit; + } + + error = create_by_name(name, mode, parent, &dentry); + if (error) { + dentry = ERR_PTR(error); + simple_release_fs(&mount, &mount_count); + goto exit; + } + + if (dentry->d_inode) { + if (fops) + dentry->d_inode->i_fop = fops; + if (data) + dentry->d_inode->u.generic_ip = data; + } +exit: + return dentry; +} +EXPORT_SYMBOL_GPL(securityfs_create_file); + +/** + * securityfs_create_dir - create a directory in the securityfs filesystem + * + * @name: a pointer to a string containing the name of the directory to + * create. + * @parent: a pointer to the parent dentry for this file. This should be a + * directory dentry if set. If this paramater is NULL, then the + * directory will be created in the root of the securityfs filesystem. + * + * This function creates a directory in securityfs with the given name. + * + * This function will return a pointer to a dentry if it succeeds. This + * pointer must be passed to the securityfs_remove() function when the file is + * to be removed (no automatic cleanup happens if your module is unloaded, + * you are responsible here.) If an error occurs, NULL will be returned. + * + * If securityfs is not enabled in the kernel, the value -ENODEV will be + * returned. It is not wise to check for this value, but rather, check for + * NULL or !NULL instead as to eliminate the need for #ifdef in the calling + * code. + */ +struct dentry *securityfs_create_dir(const char *name, struct dentry *parent) +{ + return securityfs_create_file(name, + S_IFDIR | S_IRWXU | S_IRUGO | S_IXUGO, + parent, NULL, NULL); +} +EXPORT_SYMBOL_GPL(securityfs_create_dir); + +/** + * securityfs_remove - removes a file or directory from the securityfs filesystem + * + * @dentry: a pointer to a the dentry of the file or directory to be + * removed. + * + * This function removes a file or directory in securityfs that was previously + * created with a call to another securityfs function (like + * securityfs_create_file() or variants thereof.) + * + * This function is required to be called in order for the file to be + * removed, no automatic cleanup of files will happen when a module is + * removed, you are responsible here. + */ +void securityfs_remove(struct dentry *dentry) +{ + struct dentry *parent; + + if (!dentry) + return; + + parent = dentry->d_parent; + if (!parent || !parent->d_inode) + return; + + down(&parent->d_inode->i_sem); + if (positive(dentry)) { + if (dentry->d_inode) { + if (S_ISDIR(dentry->d_inode->i_mode)) + simple_rmdir(parent->d_inode, dentry); + else + simple_unlink(parent->d_inode, dentry); + dput(dentry); + } + } + up(&parent->d_inode->i_sem); + simple_release_fs(&mount, &mount_count); +} +EXPORT_SYMBOL_GPL(securityfs_remove); + +static decl_subsys(security, NULL, NULL); + +static int __init securityfs_init(void) +{ + int retval; + + kset_set_kset_s(&security_subsys, kernel_subsys); + retval = subsystem_register(&security_subsys); + if (retval) + return retval; + + retval = register_filesystem(&fs_type); + if (retval) + subsystem_unregister(&security_subsys); + return retval; +} + +static void __exit securityfs_exit(void) +{ + simple_release_fs(&mount, &mount_count); + unregister_filesystem(&fs_type); + subsystem_unregister(&security_subsys); +} + +core_initcall(securityfs_init); +module_exit(securityfs_exit); +MODULE_LICENSE("GPL"); + diff --git a/security/seclvl.c b/security/seclvl.c index 96b1f21..1caac01 100644 --- a/security/seclvl.c +++ b/security/seclvl.c @@ -119,69 +119,6 @@ MODULE_PARM_DESC(hideHash, "When set to 0, reading seclvl/passwd from sysfs " } while (0) /** - * kobject stuff - */ - -struct subsystem seclvl_subsys; - -struct seclvl_obj { - char *name; - struct list_head slot_list; - struct kobject kobj; -}; - -/** - * There is a seclvl_attribute struct for each file in sysfs. - * - * In our case, we have one of these structs for "passwd" and another - * for "seclvl". - */ -struct seclvl_attribute { - struct attribute attr; - ssize_t(*show) (struct seclvl_obj *, char *); - ssize_t(*store) (struct seclvl_obj *, const char *, size_t); -}; - -/** - * When this function is called, one of the files in sysfs is being - * written to. attribute->store is a function pointer to whatever the - * struct seclvl_attribute store function pointer points to. It is - * unique for "passwd" and "seclvl". - */ -static ssize_t -seclvl_attr_store(struct kobject *kobj, - struct attribute *attr, const char *buf, size_t len) -{ - struct seclvl_obj *obj = container_of(kobj, struct seclvl_obj, kobj); - struct seclvl_attribute *attribute = - container_of(attr, struct seclvl_attribute, attr); - return attribute->store ? attribute->store(obj, buf, len) : -EIO; -} - -static ssize_t -seclvl_attr_show(struct kobject *kobj, struct attribute *attr, char *buf) -{ - struct seclvl_obj *obj = container_of(kobj, struct seclvl_obj, kobj); - struct seclvl_attribute *attribute = - container_of(attr, struct seclvl_attribute, attr); - return attribute->show ? attribute->show(obj, buf) : -EIO; -} - -/** - * Callback function pointers for show and store - */ -static struct sysfs_ops seclvlfs_sysfs_ops = { - .show = seclvl_attr_show, - .store = seclvl_attr_store, -}; - -static struct kobj_type seclvl_ktype = { - .sysfs_ops = &seclvlfs_sysfs_ops -}; - -decl_subsys(seclvl, &seclvl_ktype, NULL); - -/** * The actual security level. Ranges between -1 and 2 inclusive. */ static int seclvl; @@ -213,97 +150,44 @@ static int seclvl_sanity(int reqlvl) } /** - * Called whenever the user reads the sysfs handle to this kernel - * object - */ -static ssize_t seclvl_read_file(struct seclvl_obj *obj, char *buff) -{ - return snprintf(buff, PAGE_SIZE, "%d\n", seclvl); -} - -/** * security level advancement rules: * Valid levels are -1 through 2, inclusive. * From -1, stuck. [ in case compiled into kernel ] * From 0 or above, can only increment. */ -static int do_seclvl_advance(int newlvl) +static void do_seclvl_advance(void *data, u64 val) { - if (newlvl <= seclvl) { - seclvl_printk(1, KERN_WARNING, "Cannot advance to seclvl " - "[%d]\n", newlvl); - return -EINVAL; - } + int ret; + int newlvl = (int)val; + + ret = seclvl_sanity(newlvl); + if (ret) + return; + if (newlvl > 2) { seclvl_printk(1, KERN_WARNING, "Cannot advance to seclvl " "[%d]\n", newlvl); - return -EINVAL; + return; } if (seclvl == -1) { seclvl_printk(1, KERN_WARNING, "Not allowed to advance to " "seclvl [%d]\n", seclvl); - return -EPERM; + return; } - seclvl = newlvl; - return 0; + seclvl = newlvl; /* would it be more "correct" to set *data? */ + return; } -/** - * Called whenever the user writes to the sysfs handle to this kernel - * object (seclvl/seclvl). It expects a single-digit number. - */ -static ssize_t -seclvl_write_file(struct seclvl_obj *obj, const char *buff, size_t count) +static u64 seclvl_int_get(void *data) { - unsigned long val; - if (count > 2 || (count == 2 && buff[1] != '\n')) { - seclvl_printk(1, KERN_WARNING, "Invalid value passed to " - "seclvl: [%s]\n", buff); - return -EINVAL; - } - val = buff[0] - 48; - if (seclvl_sanity(val)) { - seclvl_printk(1, KERN_WARNING, "Illegal secure level " - "requested: [%d]\n", (int)val); - return -EPERM; - } - if (do_seclvl_advance(val)) { - seclvl_printk(0, KERN_ERR, "Failure advancing security level " - "to %lu\n", val); - } - return count; + return *(int *)data; } -/* Generate sysfs_attr_seclvl */ -static struct seclvl_attribute sysfs_attr_seclvl = -__ATTR(seclvl, (S_IFREG | S_IRUGO | S_IWUSR), seclvl_read_file, - seclvl_write_file); +DEFINE_SIMPLE_ATTRIBUTE(seclvl_file_ops, seclvl_int_get, do_seclvl_advance, "%lld\n"); static unsigned char hashedPassword[SHA1_DIGEST_SIZE]; /** - * Called whenever the user reads the sysfs passwd handle. - */ -static ssize_t seclvl_read_passwd(struct seclvl_obj *obj, char *buff) -{ - /* So just how good *is* your password? :-) */ - char tmp[3]; - int i = 0; - buff[0] = '\0'; - if (hideHash) { - /* Security through obscurity */ - return 0; - } - while (i < SHA1_DIGEST_SIZE) { - snprintf(tmp, 3, "%02x", hashedPassword[i]); - strncat(buff, tmp, 2); - i++; - } - strcat(buff, "\n"); - return ((SHA1_DIGEST_SIZE * 2) + 1); -} - -/** * Converts a block of plaintext of into its SHA1 hashed value. * * It would be nice if crypto had a wrapper to do this for us linear @@ -347,12 +231,15 @@ plaintext_to_sha1(unsigned char *hash, const char *plaintext, int len) * object. It hashes the password and compares the hashed results. */ static ssize_t -seclvl_write_passwd(struct seclvl_obj *obj, const char *buff, size_t count) +passwd_write_file(struct file * file, const char __user * buf, + size_t count, loff_t *ppos) { int i; unsigned char tmp[SHA1_DIGEST_SIZE]; + char *page; int rc; int len; + if (!*passwd && !*sha1_passwd) { seclvl_printk(0, KERN_ERR, "Attempt to password-unlock the " "seclvl module, but neither a plain text " @@ -363,32 +250,45 @@ seclvl_write_passwd(struct seclvl_obj *obj, const char *buff, size_t count) "maintainer about this event.\n"); return -EINVAL; } - len = strlen(buff); + + if (count < 0 || count >= PAGE_SIZE) + return -EINVAL; + if (*ppos != 0) + return -EINVAL; + page = (char *)get_zeroed_page(GFP_KERNEL); + if (!page) + return -ENOMEM; + len = -EFAULT; + if (copy_from_user(page, buf, count)) + goto out; + + len = strlen(page); /* ``echo "secret" > seclvl/passwd'' includes a newline */ - if (buff[len - 1] == '\n') { + if (page[len - 1] == '\n') len--; - } /* Hash the password, then compare the hashed values */ - if ((rc = plaintext_to_sha1(tmp, buff, len))) { + if ((rc = plaintext_to_sha1(tmp, page, len))) { seclvl_printk(0, KERN_ERR, "Error hashing password: rc = " "[%d]\n", rc); return rc; } for (i = 0; i < SHA1_DIGEST_SIZE; i++) { - if (hashedPassword[i] != tmp[i]) { + if (hashedPassword[i] != tmp[i]) return -EPERM; - } } seclvl_printk(0, KERN_INFO, "Password accepted; seclvl reduced to 0.\n"); seclvl = 0; - return count; + len = count; + +out: + free_page((unsigned long)page); + return len; } -/* Generate sysfs_attr_passwd */ -static struct seclvl_attribute sysfs_attr_passwd = -__ATTR(passwd, (S_IFREG | S_IRUGO | S_IWUSR), seclvl_read_passwd, - seclvl_write_passwd); +static struct file_operations passwd_file_ops = { + .write = passwd_write_file, +}; /** * Explicitely disallow ptrace'ing the init process. @@ -579,9 +479,8 @@ static void seclvl_file_free_security(struct file *filp) */ static int seclvl_umount(struct vfsmount *mnt, int flags) { - if (current->pid == 1) { + if (current->pid == 1) return 0; - } if (seclvl == 2) { seclvl_printk(1, KERN_WARNING, "Attempt to unmount in secure " "level %d\n", seclvl); @@ -647,22 +546,34 @@ static int processPassword(void) } /** - * Sysfs registrations + * securityfs registrations */ -static int doSysfsRegistrations(void) +struct dentry *dir_ino, *seclvl_ino, *passwd_ino; + +static int seclvlfs_register(void) { - int rc = 0; - if ((rc = subsystem_register(&seclvl_subsys))) { - seclvl_printk(0, KERN_WARNING, - "Error [%d] registering seclvl subsystem\n", rc); - return rc; - } - sysfs_create_file(&seclvl_subsys.kset.kobj, &sysfs_attr_seclvl.attr); + dir_ino = securityfs_create_dir("seclvl", NULL); + if (!dir_ino) + return -EFAULT; + + seclvl_ino = securityfs_create_file("seclvl", S_IRUGO | S_IWUSR, + dir_ino, &seclvl, &seclvl_file_ops); + if (!seclvl_ino) + goto out_deldir; if (*passwd || *sha1_passwd) { - sysfs_create_file(&seclvl_subsys.kset.kobj, - &sysfs_attr_passwd.attr); + passwd_ino = securityfs_create_file("passwd", S_IRUGO | S_IWUSR, + dir_ino, NULL, &passwd_file_ops); + if (!passwd_ino) + goto out_delf; } return 0; + +out_deldir: + securityfs_remove(dir_ino); +out_delf: + securityfs_remove(seclvl_ino); + + return -EFAULT; } /** @@ -677,8 +588,6 @@ static int __init seclvl_init(void) rc = -EINVAL; goto exit; } - sysfs_attr_seclvl.attr.owner = THIS_MODULE; - sysfs_attr_passwd.attr.owner = THIS_MODULE; if (initlvl < -1 || initlvl > 2) { seclvl_printk(0, KERN_ERR, "Error: bad initial securelevel " "[%d].\n", initlvl); @@ -706,7 +615,7 @@ static int __init seclvl_init(void) } /* if primary module registered */ secondary = 1; } /* if we registered ourselves with the security framework */ - if ((rc = doSysfsRegistrations())) { + if ((rc = seclvlfs_register())) { seclvl_printk(0, KERN_ERR, "Error registering with sysfs\n"); goto exit; } @@ -724,12 +633,10 @@ static int __init seclvl_init(void) */ static void __exit seclvl_exit(void) { - sysfs_remove_file(&seclvl_subsys.kset.kobj, &sysfs_attr_seclvl.attr); - if (*passwd || *sha1_passwd) { - sysfs_remove_file(&seclvl_subsys.kset.kobj, - &sysfs_attr_passwd.attr); - } - subsystem_unregister(&seclvl_subsys); + securityfs_remove(seclvl_ino); + if (*passwd || *sha1_passwd) + securityfs_remove(passwd_ino); + securityfs_remove(dir_ino); if (secondary == 1) { mod_unreg_security(MY_NAME, &seclvl_ops); } else if (unregister_security(&seclvl_ops)) { diff --git a/security/selinux/avc.c b/security/selinux/avc.c index cf6020f..12e4fb7 100644 --- a/security/selinux/avc.c +++ b/security/selinux/avc.c @@ -242,7 +242,7 @@ void __init avc_init(void) avc_node_cachep = kmem_cache_create("avc_node", sizeof(struct avc_node), 0, SLAB_PANIC, NULL, NULL); - audit_log(current->audit_context, AUDIT_KERNEL, "AVC INITIALIZED\n"); + audit_log(current->audit_context, GFP_KERNEL, AUDIT_KERNEL, "AVC INITIALIZED\n"); } int avc_get_hash_stats(char *page) @@ -550,7 +550,7 @@ void avc_audit(u32 ssid, u32 tsid, return; } - ab = audit_log_start(current->audit_context, AUDIT_AVC); + ab = audit_log_start(current->audit_context, GFP_ATOMIC, AUDIT_AVC); if (!ab) return; /* audit_panic has been called */ audit_log_format(ab, "avc: %s ", denied ? "denied" : "granted"); diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index f40c822..6e4937f 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c @@ -3389,7 +3389,7 @@ static int selinux_nlmsg_perm(struct sock *sk, struct sk_buff *skb) err = selinux_nlmsg_lookup(isec->sclass, nlh->nlmsg_type, &perm); if (err) { if (err == -EINVAL) { - audit_log(current->audit_context, AUDIT_SELINUX_ERR, + audit_log(current->audit_context, GFP_KERNEL, AUDIT_SELINUX_ERR, "SELinux: unrecognized netlink message" " type=%hu for sclass=%hu\n", nlh->nlmsg_type, isec->sclass); diff --git a/security/selinux/ss/services.c b/security/selinux/ss/services.c index 92b89dc..aecdded 100644 --- a/security/selinux/ss/services.c +++ b/security/selinux/ss/services.c @@ -381,7 +381,7 @@ static int security_validtrans_handle_fail(struct context *ocontext, goto out; if (context_struct_to_string(tcontext, &t, &tlen) < 0) goto out; - audit_log(current->audit_context, AUDIT_SELINUX_ERR, + audit_log(current->audit_context, GFP_ATOMIC, AUDIT_SELINUX_ERR, "security_validate_transition: denied for" " oldcontext=%s newcontext=%s taskcontext=%s tclass=%s", o, n, t, policydb.p_class_val_to_name[tclass-1]); @@ -787,7 +787,7 @@ static int compute_sid_handle_invalid_context( goto out; if (context_struct_to_string(newcontext, &n, &nlen) < 0) goto out; - audit_log(current->audit_context, AUDIT_SELINUX_ERR, + audit_log(current->audit_context, GFP_ATOMIC, AUDIT_SELINUX_ERR, "security_compute_sid: invalid context %s" " for scontext=%s" " tcontext=%s" diff --git a/sound/arm/Kconfig b/sound/arm/Kconfig index 2e4a5e0..0864a7c 100644 --- a/sound/arm/Kconfig +++ b/sound/arm/Kconfig @@ -7,6 +7,7 @@ config SND_SA11XX_UDA1341 tristate "SA11xx UDA1341TS driver (iPaq H3600)" depends on ARCH_SA1100 && SND && L3 select SND_PCM + select SND_GENERIC_DRIVER help Say Y here if you have a Compaq iPaq H3x00 handheld computer and want to use its Philips UDA 1341 audio chip. diff --git a/sound/arm/aaci.c b/sound/arm/aaci.c index 9887703..b2d5db2 100644 --- a/sound/arm/aaci.c +++ b/sound/arm/aaci.c @@ -650,7 +650,7 @@ static int aaci_do_resume(snd_card_t *card, unsigned int state) return 0; } -static int aaci_suspend(struct amba_device *dev, u32 state) +static int aaci_suspend(struct amba_device *dev, pm_message_t state) { snd_card_t *card = amba_get_drvdata(dev); return card ? aaci_do_suspend(card) : 0; @@ -900,6 +900,8 @@ static int __devinit aaci_probe(struct amba_device *dev, void *id) if (ret) goto out; + snd_card_set_dev(aaci->card, &dev->dev); + ret = snd_card_register(aaci->card); if (ret == 0) { dev_info(&dev->dev, "%s, fifo %d\n", aaci->card->longname, diff --git a/sound/arm/sa11xx-uda1341.c b/sound/arm/sa11xx-uda1341.c index 174bc03..6ee9122 100644 --- a/sound/arm/sa11xx-uda1341.c +++ b/sound/arm/sa11xx-uda1341.c @@ -21,7 +21,7 @@ * merged HAL layer (patches from Brian) */ -/* $Id: sa11xx-uda1341.c,v 1.21 2005/01/28 19:34:04 tiwai Exp $ */ +/* $Id: sa11xx-uda1341.c,v 1.23 2005/09/09 13:22:34 tiwai Exp $ */ /*************************************************************************************************** * @@ -918,7 +918,7 @@ static int __init sa11xx_uda1341_init(void) if (card == NULL) return -ENOMEM; - sa11xx_uda1341 = kcalloc(1, sizeof(*sa11xx_uda1341), GFP_KERNEL); + sa11xx_uda1341 = kzalloc(sizeof(*sa11xx_uda1341), GFP_KERNEL); if (sa11xx_uda1341 == NULL) return -ENOMEM; spin_lock_init(&chip->s[0].dma_lock); @@ -946,6 +946,9 @@ static int __init sa11xx_uda1341_init(void) strcpy(card->shortname, "H3600 UDA1341TS"); sprintf(card->longname, "Compaq iPAQ H3600 with Philips UDA1341TS"); + if ((err = snd_card_set_generic_dev(card)) < 0) + goto nodev; + if ((err = snd_card_register(card)) == 0) { printk( KERN_INFO "iPAQ audio support initialized\n" ); return 0; diff --git a/sound/core/Kconfig b/sound/core/Kconfig index d1e800b..48cf45c 100644 --- a/sound/core/Kconfig +++ b/sound/core/Kconfig @@ -99,6 +99,18 @@ config SND_RTCTIMER To compile this driver as a module, choose M here: the module will be called snd-rtctimer. +config SND_SEQ_RTCTIMER_DEFAULT + bool "Use RTC as default sequencer timer" + depends on SND_RTCTIMER && SND_SEQUENCER + default y + help + Say Y here to use the RTC timer as the default sequencer + timer. This is strongly recommended because it ensures + precise MIDI timing even when the system timer runs at less + than 1000 Hz. + + If in doubt, say Y. + config SND_VERBOSE_PRINTK bool "Verbose printk" depends on SND @@ -128,6 +140,6 @@ config SND_DEBUG_DETECT Say Y here to enable extra-verbose log messages printed when detecting devices. -config SND_GENERIC_PM +config SND_GENERIC_DRIVER bool depends on SND diff --git a/sound/core/control.c b/sound/core/control.c index 227f3cf..736edf3 100644 --- a/sound/core/control.c +++ b/sound/core/control.c @@ -69,7 +69,7 @@ static int snd_ctl_open(struct inode *inode, struct file *file) err = -EFAULT; goto __error2; } - ctl = kcalloc(1, sizeof(*ctl), GFP_KERNEL); + ctl = kzalloc(sizeof(*ctl), GFP_KERNEL); if (ctl == NULL) { err = -ENOMEM; goto __error; @@ -162,7 +162,7 @@ void snd_ctl_notify(snd_card_t *card, unsigned int mask, snd_ctl_elem_id_t *id) goto _found; } } - ev = kcalloc(1, sizeof(*ev), GFP_ATOMIC); + ev = kzalloc(sizeof(*ev), GFP_ATOMIC); if (ev) { ev->id = *id; ev->mask = mask; @@ -195,7 +195,7 @@ snd_kcontrol_t *snd_ctl_new(snd_kcontrol_t * control, unsigned int access) snd_runtime_check(control != NULL, return NULL); snd_runtime_check(control->count > 0, return NULL); - kctl = kcalloc(1, sizeof(*kctl) + sizeof(snd_kcontrol_volatile_t) * control->count, GFP_KERNEL); + kctl = kzalloc(sizeof(*kctl) + sizeof(snd_kcontrol_volatile_t) * control->count, GFP_KERNEL); if (kctl == NULL) return NULL; *kctl = *control; @@ -521,7 +521,7 @@ static int snd_ctl_card_info(snd_card_t * card, snd_ctl_file_t * ctl, { snd_ctl_card_info_t *info; - info = kcalloc(1, sizeof(*info), GFP_KERNEL); + info = kzalloc(sizeof(*info), GFP_KERNEL); if (! info) return -ENOMEM; down_read(&snd_ioctl_rwsem); @@ -929,7 +929,7 @@ static int snd_ctl_elem_add(snd_ctl_file_t *file, snd_ctl_elem_info_t *info, int return -EINVAL; } private_size *= info->count; - ue = kcalloc(1, sizeof(struct user_element) + private_size, GFP_KERNEL); + ue = kzalloc(sizeof(struct user_element) + private_size, GFP_KERNEL); if (ue == NULL) return -ENOMEM; ue->info = *info; @@ -1185,7 +1185,7 @@ static int _snd_ctl_register_ioctl(snd_kctl_ioctl_func_t fcn, struct list_head * { snd_kctl_ioctl_t *pn; - pn = kcalloc(1, sizeof(snd_kctl_ioctl_t), GFP_KERNEL); + pn = kzalloc(sizeof(snd_kctl_ioctl_t), GFP_KERNEL); if (pn == NULL) return -ENOMEM; pn->fioctl = fcn; diff --git a/sound/core/control_compat.c b/sound/core/control_compat.c index 7fdabea..207c7de 100644 --- a/sound/core/control_compat.c +++ b/sound/core/control_compat.c @@ -92,7 +92,7 @@ static int snd_ctl_elem_info_compat(snd_ctl_file_t *ctl, struct sndrv_ctl_elem_i struct sndrv_ctl_elem_info *data; int err; - data = kcalloc(1, sizeof(*data), GFP_KERNEL); + data = kzalloc(sizeof(*data), GFP_KERNEL); if (! data) return -ENOMEM; @@ -271,7 +271,7 @@ static int snd_ctl_elem_read_user_compat(snd_card_t *card, struct sndrv_ctl_elem_value *data; int err, type, count; - data = kcalloc(1, sizeof(*data), GFP_KERNEL); + data = kzalloc(sizeof(*data), GFP_KERNEL); if (data == NULL) return -ENOMEM; @@ -291,7 +291,7 @@ static int snd_ctl_elem_write_user_compat(snd_ctl_file_t *file, struct sndrv_ctl_elem_value *data; int err, type, count; - data = kcalloc(1, sizeof(*data), GFP_KERNEL); + data = kzalloc(sizeof(*data), GFP_KERNEL); if (data == NULL) return -ENOMEM; @@ -313,7 +313,7 @@ static int snd_ctl_elem_add_compat(snd_ctl_file_t *file, struct sndrv_ctl_elem_info *data; int err; - data = kcalloc(1, sizeof(*data), GFP_KERNEL); + data = kzalloc(sizeof(*data), GFP_KERNEL); if (! data) return -ENOMEM; diff --git a/sound/core/device.c b/sound/core/device.c index ca00ad7..1f509f5 100644 --- a/sound/core/device.c +++ b/sound/core/device.c @@ -49,7 +49,7 @@ int snd_device_new(snd_card_t *card, snd_device_type_t type, snd_assert(card != NULL, return -ENXIO); snd_assert(device_data != NULL, return -ENXIO); snd_assert(ops != NULL, return -ENXIO); - dev = kcalloc(1, sizeof(*dev), GFP_KERNEL); + dev = kzalloc(sizeof(*dev), GFP_KERNEL); if (dev == NULL) return -ENOMEM; dev->card = card; diff --git a/sound/core/hwdep.c b/sound/core/hwdep.c index 997dd41..9383f12 100644 --- a/sound/core/hwdep.c +++ b/sound/core/hwdep.c @@ -359,7 +359,7 @@ int snd_hwdep_new(snd_card_t * card, char *id, int device, snd_hwdep_t ** rhwdep snd_assert(rhwdep != NULL, return -EINVAL); *rhwdep = NULL; snd_assert(card != NULL, return -ENXIO); - hwdep = kcalloc(1, sizeof(*hwdep), GFP_KERNEL); + hwdep = kzalloc(sizeof(*hwdep), GFP_KERNEL); if (hwdep == NULL) return -ENOMEM; hwdep->card = card; diff --git a/sound/core/info.c b/sound/core/info.c index 7f8bdf7..37024d6 100644 --- a/sound/core/info.c +++ b/sound/core/info.c @@ -295,7 +295,7 @@ static int snd_info_entry_open(struct inode *inode, struct file *file) goto __error; } } - data = kcalloc(1, sizeof(*data), GFP_KERNEL); + data = kzalloc(sizeof(*data), GFP_KERNEL); if (data == NULL) { err = -ENOMEM; goto __error; @@ -304,7 +304,7 @@ static int snd_info_entry_open(struct inode *inode, struct file *file) switch (entry->content) { case SNDRV_INFO_CONTENT_TEXT: if (mode == O_RDONLY || mode == O_RDWR) { - buffer = kcalloc(1, sizeof(*buffer), GFP_KERNEL); + buffer = kzalloc(sizeof(*buffer), GFP_KERNEL); if (buffer == NULL) { kfree(data); err = -ENOMEM; @@ -323,7 +323,7 @@ static int snd_info_entry_open(struct inode *inode, struct file *file) data->rbuffer = buffer; } if (mode == O_WRONLY || mode == O_RDWR) { - buffer = kcalloc(1, sizeof(*buffer), GFP_KERNEL); + buffer = kzalloc(sizeof(*buffer), GFP_KERNEL); if (buffer == NULL) { if (mode == O_RDWR) { vfree(data->rbuffer->buffer); @@ -752,7 +752,7 @@ char *snd_info_get_str(char *dest, char *src, int len) static snd_info_entry_t *snd_info_create_entry(const char *name) { snd_info_entry_t *entry; - entry = kcalloc(1, sizeof(*entry), GFP_KERNEL); + entry = kzalloc(sizeof(*entry), GFP_KERNEL); if (entry == NULL) return NULL; entry->name = kstrdup(name, GFP_KERNEL); diff --git a/sound/core/init.c b/sound/core/init.c index d72f58f..a570201 100644 --- a/sound/core/init.c +++ b/sound/core/init.c @@ -72,7 +72,7 @@ snd_card_t *snd_card_new(int idx, const char *xid, if (extra_size < 0) extra_size = 0; - card = kcalloc(1, sizeof(*card) + extra_size, GFP_KERNEL); + card = kzalloc(sizeof(*card) + extra_size, GFP_KERNEL); if (card == NULL) return NULL; if (xid) { @@ -226,8 +226,10 @@ int snd_card_disconnect(snd_card_t * card) return 0; } -#if defined(CONFIG_PM) && defined(CONFIG_SND_GENERIC_PM) -static void snd_generic_device_unregister(struct snd_generic_device *dev); +#ifdef CONFIG_SND_GENERIC_DRIVER +static void snd_generic_device_unregister(snd_card_t *card); +#else +#define snd_generic_device_unregister(x) /*NOP*/ #endif /** @@ -253,14 +255,7 @@ int snd_card_free(snd_card_t * card) #ifdef CONFIG_PM wake_up(&card->power_sleep); -#ifdef CONFIG_SND_GENERIC_PM - if (card->pm_dev) { - snd_generic_device_unregister(card->pm_dev); - card->pm_dev = NULL; - } -#endif #endif - /* wait, until all devices are ready for the free operation */ wait_event(card->shutdown_sleep, card->files == NULL); @@ -288,6 +283,7 @@ int snd_card_free(snd_card_t * card) snd_printk(KERN_WARNING "unable to free card info\n"); /* Not fatal error */ } + snd_generic_device_unregister(card); while (card->s_f_ops) { s_f_ops = card->s_f_ops; card->s_f_ops = s_f_ops->next; @@ -665,6 +661,96 @@ int snd_card_file_remove(snd_card_t *card, struct file *file) return 0; } +#ifdef CONFIG_SND_GENERIC_DRIVER +/* + * generic device without a proper bus using platform_device + * (e.g. ISA) + */ +struct snd_generic_device { + struct platform_device pdev; + snd_card_t *card; +}; + +#define get_snd_generic_card(dev) container_of(to_platform_device(dev), struct snd_generic_device, pdev)->card + +#define SND_GENERIC_NAME "snd_generic" + +#ifdef CONFIG_PM +static int snd_generic_suspend(struct device *dev, pm_message_t state, u32 level); +static int snd_generic_resume(struct device *dev, u32 level); +#endif + +/* initialized in sound.c */ +struct device_driver snd_generic_driver = { + .name = SND_GENERIC_NAME, + .bus = &platform_bus_type, +#ifdef CONFIG_PM + .suspend = snd_generic_suspend, + .resume = snd_generic_resume, +#endif +}; + +void snd_generic_device_release(struct device *dev) +{ +} + +static int snd_generic_device_register(snd_card_t *card) +{ + struct snd_generic_device *dev; + int err; + + if (card->generic_dev) + return 0; /* already registered */ + + dev = kzalloc(sizeof(*dev), GFP_KERNEL); + if (! dev) { + snd_printk(KERN_ERR "can't allocate generic_device\n"); + return -ENOMEM; + } + + dev->pdev.name = SND_GENERIC_NAME; + dev->pdev.id = card->number; + dev->pdev.dev.release = snd_generic_device_release; + dev->card = card; + if ((err = platform_device_register(&dev->pdev)) < 0) { + kfree(dev); + return err; + } + card->generic_dev = dev; + return 0; +} + +static void snd_generic_device_unregister(snd_card_t *card) +{ + struct snd_generic_device *dev = card->generic_dev; + if (dev) { + platform_device_unregister(&dev->pdev); + kfree(dev); + card->generic_dev = NULL; + } +} + +/** + * snd_card_set_generic_dev - assign the generic device to the card + * @card: soundcard structure + * + * Assigns a generic device to the card. This function is provided as the + * last resort, for devices without any proper bus. Thus this won't override + * the device already assigned to the card. + * + * Returns zero if successful, or a negative error code. + */ +int snd_card_set_generic_dev(snd_card_t *card) +{ + int err; + if ((err = snd_generic_device_register(card)) < 0) + return err; + if (! card->dev) + snd_card_set_dev(card, &card->generic_dev->pdev.dev); + return 0; +} +#endif /* CONFIG_SND_GENERIC_DRIVER */ + #ifdef CONFIG_PM /** * snd_power_wait - wait until the power-state is changed. @@ -730,75 +816,7 @@ int snd_card_set_pm_callback(snd_card_t *card, return 0; } -#ifdef CONFIG_SND_GENERIC_PM -/* - * use platform_device for generic power-management without a proper bus - * (e.g. ISA) - */ -struct snd_generic_device { - struct platform_device pdev; - snd_card_t *card; -}; - -#define get_snd_generic_card(dev) container_of(to_platform_device(dev), struct snd_generic_device, pdev)->card - -#define SND_GENERIC_NAME "snd_generic_pm" - -static int snd_generic_suspend(struct device *dev, pm_message_t state, u32 level); -static int snd_generic_resume(struct device *dev, u32 level); - -static struct device_driver snd_generic_driver = { - .name = SND_GENERIC_NAME, - .bus = &platform_bus_type, - .suspend = snd_generic_suspend, - .resume = snd_generic_resume, -}; - -static int generic_driver_registered; - -static void generic_driver_unregister(void) -{ - if (generic_driver_registered) { - generic_driver_registered--; - if (! generic_driver_registered) - driver_unregister(&snd_generic_driver); - } -} - -static struct snd_generic_device *snd_generic_device_register(snd_card_t *card) -{ - struct snd_generic_device *dev; - - if (! generic_driver_registered) { - if (driver_register(&snd_generic_driver) < 0) - return NULL; - } - generic_driver_registered++; - - dev = kcalloc(1, sizeof(*dev), GFP_KERNEL); - if (! dev) { - generic_driver_unregister(); - return NULL; - } - - dev->pdev.name = SND_GENERIC_NAME; - dev->pdev.id = card->number; - dev->card = card; - if (platform_device_register(&dev->pdev) < 0) { - kfree(dev); - generic_driver_unregister(); - return NULL; - } - return dev; -} - -static void snd_generic_device_unregister(struct snd_generic_device *dev) -{ - platform_device_unregister(&dev->pdev); - kfree(dev); - generic_driver_unregister(); -} - +#ifdef CONFIG_SND_GENERIC_DRIVER /* suspend/resume callbacks for snd_generic platform device */ static int snd_generic_suspend(struct device *dev, pm_message_t state, u32 level) { @@ -846,13 +864,12 @@ int snd_card_set_generic_pm_callback(snd_card_t *card, int (*resume)(snd_card_t *), void *private_data) { - card->pm_dev = snd_generic_device_register(card); - if (! card->pm_dev) - return -ENOMEM; - snd_card_set_pm_callback(card, suspend, resume, private_data); - return 0; + int err; + if ((err = snd_generic_device_register(card)) < 0) + return err; + return snd_card_set_pm_callback(card, suspend, resume, private_data); } -#endif /* CONFIG_SND_GENERIC_PM */ +#endif /* CONFIG_SND_GENERIC_DRIVER */ #ifdef CONFIG_PCI int snd_card_pci_suspend(struct pci_dev *dev, pm_message_t state) diff --git a/sound/core/memalloc.c b/sound/core/memalloc.c index 39a54a4..91124dd 100644 --- a/sound/core/memalloc.c +++ b/sound/core/memalloc.c @@ -590,7 +590,7 @@ static int snd_mem_proc_write(struct file *file, const char __user *buffer, alloced = 0; pci = NULL; - while ((pci = pci_find_device(vendor, device, pci)) != NULL) { + while ((pci = pci_get_device(vendor, device, pci)) != NULL) { if (mask > 0 && mask < 0xffffffff) { if (pci_set_dma_mask(pci, mask) < 0 || pci_set_consistent_dma_mask(pci, mask) < 0) { @@ -604,6 +604,7 @@ static int snd_mem_proc_write(struct file *file, const char __user *buffer, if (snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(pci), size, &dmab) < 0) { printk(KERN_ERR "snd-page-alloc: cannot allocate buffer pages (size = %d)\n", size); + pci_dev_put(pci); return (int)count; } snd_dma_reserve_buf(&dmab, snd_dma_pci_buf_id(pci)); diff --git a/sound/core/memory.c b/sound/core/memory.c index 291b476..8fa888f 100644 --- a/sound/core/memory.c +++ b/sound/core/memory.c @@ -249,7 +249,7 @@ int __exit snd_memory_info_done(void) int copy_to_user_fromio(void __user *dst, const volatile void __iomem *src, size_t count) { #if defined(__i386__) || defined(CONFIG_SPARC32) - return copy_to_user(dst, (const void*)src, count) ? -EFAULT : 0; + return copy_to_user(dst, (const void __force*)src, count) ? -EFAULT : 0; #else char buf[256]; while (count) { @@ -280,7 +280,7 @@ int copy_to_user_fromio(void __user *dst, const volatile void __iomem *src, size int copy_from_user_toio(volatile void __iomem *dst, const void __user *src, size_t count) { #if defined(__i386__) || defined(CONFIG_SPARC32) - return copy_from_user((void*)dst, src, count) ? -EFAULT : 0; + return copy_from_user((void __force *)dst, src, count) ? -EFAULT : 0; #else char buf[256]; while (count) { diff --git a/sound/core/oss/mixer_oss.c b/sound/core/oss/mixer_oss.c index 98fc076..69e1059 100644 --- a/sound/core/oss/mixer_oss.c +++ b/sound/core/oss/mixer_oss.c @@ -53,7 +53,7 @@ static int snd_mixer_oss_open(struct inode *inode, struct file *file) err = snd_card_file_add(card, file); if (err < 0) return err; - fmixer = kcalloc(1, sizeof(*fmixer), GFP_KERNEL); + fmixer = kzalloc(sizeof(*fmixer), GFP_KERNEL); if (fmixer == NULL) { snd_card_file_remove(card, file); return -ENOMEM; @@ -517,8 +517,8 @@ static void snd_mixer_oss_get_volume1_vol(snd_mixer_oss_file_t *fmixer, up_read(&card->controls_rwsem); return; } - uinfo = kcalloc(1, sizeof(*uinfo), GFP_KERNEL); - uctl = kcalloc(1, sizeof(*uctl), GFP_KERNEL); + uinfo = kzalloc(sizeof(*uinfo), GFP_KERNEL); + uctl = kzalloc(sizeof(*uctl), GFP_KERNEL); if (uinfo == NULL || uctl == NULL) goto __unalloc; snd_runtime_check(!kctl->info(kctl, uinfo), goto __unalloc); @@ -551,8 +551,8 @@ static void snd_mixer_oss_get_volume1_sw(snd_mixer_oss_file_t *fmixer, up_read(&card->controls_rwsem); return; } - uinfo = kcalloc(1, sizeof(*uinfo), GFP_KERNEL); - uctl = kcalloc(1, sizeof(*uctl), GFP_KERNEL); + uinfo = kzalloc(sizeof(*uinfo), GFP_KERNEL); + uctl = kzalloc(sizeof(*uctl), GFP_KERNEL); if (uinfo == NULL || uctl == NULL) goto __unalloc; snd_runtime_check(!kctl->info(kctl, uinfo), goto __unalloc); @@ -612,8 +612,8 @@ static void snd_mixer_oss_put_volume1_vol(snd_mixer_oss_file_t *fmixer, down_read(&card->controls_rwsem); if ((kctl = snd_ctl_find_numid(card, numid)) == NULL) return; - uinfo = kcalloc(1, sizeof(*uinfo), GFP_KERNEL); - uctl = kcalloc(1, sizeof(*uctl), GFP_KERNEL); + uinfo = kzalloc(sizeof(*uinfo), GFP_KERNEL); + uctl = kzalloc(sizeof(*uctl), GFP_KERNEL); if (uinfo == NULL || uctl == NULL) goto __unalloc; snd_runtime_check(!kctl->info(kctl, uinfo), goto __unalloc); @@ -649,8 +649,8 @@ static void snd_mixer_oss_put_volume1_sw(snd_mixer_oss_file_t *fmixer, up_read(&fmixer->card->controls_rwsem); return; } - uinfo = kcalloc(1, sizeof(*uinfo), GFP_KERNEL); - uctl = kcalloc(1, sizeof(*uctl), GFP_KERNEL); + uinfo = kzalloc(sizeof(*uinfo), GFP_KERNEL); + uctl = kzalloc(sizeof(*uctl), GFP_KERNEL); if (uinfo == NULL || uctl == NULL) goto __unalloc; snd_runtime_check(!kctl->info(kctl, uinfo), goto __unalloc); @@ -768,8 +768,8 @@ static int snd_mixer_oss_get_recsrc2(snd_mixer_oss_file_t *fmixer, unsigned int snd_ctl_elem_value_t *uctl; int err, idx; - uinfo = kcalloc(1, sizeof(*uinfo), GFP_KERNEL); - uctl = kcalloc(1, sizeof(*uctl), GFP_KERNEL); + uinfo = kzalloc(sizeof(*uinfo), GFP_KERNEL); + uctl = kzalloc(sizeof(*uctl), GFP_KERNEL); if (uinfo == NULL || uctl == NULL) { err = -ENOMEM; goto __unlock; @@ -813,8 +813,8 @@ static int snd_mixer_oss_put_recsrc2(snd_mixer_oss_file_t *fmixer, unsigned int int err; unsigned int idx; - uinfo = kcalloc(1, sizeof(*uinfo), GFP_KERNEL); - uctl = kcalloc(1, sizeof(*uctl), GFP_KERNEL); + uinfo = kzalloc(sizeof(*uinfo), GFP_KERNEL); + uctl = kzalloc(sizeof(*uctl), GFP_KERNEL); if (uinfo == NULL || uctl == NULL) { err = -ENOMEM; goto __unlock; diff --git a/sound/core/oss/pcm_oss.c b/sound/core/oss/pcm_oss.c index a13bd7b..842c28b 100644 --- a/sound/core/oss/pcm_oss.c +++ b/sound/core/oss/pcm_oss.c @@ -850,7 +850,9 @@ static ssize_t snd_pcm_oss_write1(snd_pcm_substream_t *substream, const char __u return xfer > 0 ? xfer : -EAGAIN; } } else { - tmp = snd_pcm_oss_write2(substream, (const char *)buf, runtime->oss.period_bytes, 0); + tmp = snd_pcm_oss_write2(substream, + (const char __force *)buf, + runtime->oss.period_bytes, 0); if (tmp <= 0) return xfer > 0 ? (snd_pcm_sframes_t)xfer : tmp; runtime->oss.bytes += tmp; @@ -926,7 +928,8 @@ static ssize_t snd_pcm_oss_read1(snd_pcm_substream_t *substream, char __user *bu xfer += tmp; runtime->oss.buffer_used -= tmp; } else { - tmp = snd_pcm_oss_read2(substream, (char *)buf, runtime->oss.period_bytes, 0); + tmp = snd_pcm_oss_read2(substream, (char __force *)buf, + runtime->oss.period_bytes, 0); if (tmp <= 0) return xfer > 0 ? (snd_pcm_sframes_t)xfer : tmp; runtime->oss.bytes += tmp; @@ -1540,7 +1543,11 @@ static int snd_pcm_oss_get_ptr(snd_pcm_oss_file_t *pcm_oss_file, int stream, str } else { delay = snd_pcm_oss_bytes(substream, delay); if (stream == SNDRV_PCM_STREAM_PLAYBACK) { - info.blocks = (runtime->oss.buffer_bytes - delay - fixup) / runtime->oss.period_bytes; + snd_pcm_oss_setup_t *setup = substream->oss.setup; + if (setup && setup->buggyptr) + info.blocks = (runtime->oss.buffer_bytes - delay - fixup) / runtime->oss.period_bytes; + else + info.blocks = (delay + fixup) / runtime->oss.period_bytes; info.bytes = (runtime->oss.bytes - delay) & INT_MAX; } else { delay += fixup; @@ -1733,7 +1740,7 @@ static int snd_pcm_oss_open_file(struct file *file, snd_assert(rpcm_oss_file != NULL, return -EINVAL); *rpcm_oss_file = NULL; - pcm_oss_file = kcalloc(1, sizeof(*pcm_oss_file), GFP_KERNEL); + pcm_oss_file = kzalloc(sizeof(*pcm_oss_file), GFP_KERNEL); if (pcm_oss_file == NULL) return -ENOMEM; @@ -2347,6 +2354,8 @@ static void snd_pcm_oss_proc_write(snd_info_entry_t *entry, template.partialfrag = 1; } else if (!strcmp(str, "no-silence")) { template.nosilence = 1; + } else if (!strcmp(str, "buggy-ptr")) { + template.buggyptr = 1; } } while (*str); if (setup == NULL) { diff --git a/sound/core/oss/pcm_plugin.c b/sound/core/oss/pcm_plugin.c index 6430410..fc23373 100644 --- a/sound/core/oss/pcm_plugin.c +++ b/sound/core/oss/pcm_plugin.c @@ -171,7 +171,7 @@ int snd_pcm_plugin_build(snd_pcm_plug_t *plug, snd_assert(plug != NULL, return -ENXIO); snd_assert(src_format != NULL && dst_format != NULL, return -ENXIO); - plugin = kcalloc(1, sizeof(*plugin) + extra, GFP_KERNEL); + plugin = kzalloc(sizeof(*plugin) + extra, GFP_KERNEL); if (plugin == NULL) return -ENOMEM; plugin->name = name; diff --git a/sound/core/pcm.c b/sound/core/pcm.c index 9f4c920..1be470e 100644 --- a/sound/core/pcm.c +++ b/sound/core/pcm.c @@ -597,7 +597,7 @@ int snd_pcm_new_stream(snd_pcm_t *pcm, int stream, int substream_count) } prev = NULL; for (idx = 0, prev = NULL; idx < substream_count; idx++) { - substream = kcalloc(1, sizeof(*substream), GFP_KERNEL); + substream = kzalloc(sizeof(*substream), GFP_KERNEL); if (substream == NULL) return -ENOMEM; substream->pcm = pcm; @@ -657,7 +657,7 @@ int snd_pcm_new(snd_card_t * card, char *id, int device, snd_assert(rpcm != NULL, return -EINVAL); *rpcm = NULL; snd_assert(card != NULL, return -ENXIO); - pcm = kcalloc(1, sizeof(*pcm), GFP_KERNEL); + pcm = kzalloc(sizeof(*pcm), GFP_KERNEL); if (pcm == NULL) return -ENOMEM; pcm->card = card; @@ -795,7 +795,7 @@ int snd_pcm_open_substream(snd_pcm_t *pcm, int stream, if (substream == NULL) return -EAGAIN; - runtime = kcalloc(1, sizeof(*runtime), GFP_KERNEL); + runtime = kzalloc(sizeof(*runtime), GFP_KERNEL); if (runtime == NULL) return -ENOMEM; diff --git a/sound/core/pcm_lib.c b/sound/core/pcm_lib.c index 0082914..0503980 100644 --- a/sound/core/pcm_lib.c +++ b/sound/core/pcm_lib.c @@ -524,6 +524,9 @@ void snd_interval_mul(const snd_interval_t *a, const snd_interval_t *b, snd_inte /** * snd_interval_div - refine the interval value with division + * @a: dividend + * @b: divisor + * @c: quotient * * c = a / b * @@ -555,7 +558,11 @@ void snd_interval_div(const snd_interval_t *a, const snd_interval_t *b, snd_inte /** * snd_interval_muldivk - refine the interval value - * + * @a: dividend 1 + * @b: dividend 2 + * @k: divisor (as integer) + * @c: result + * * c = a * b / k * * Returns non-zero if the value is changed, zero if not changed. @@ -582,6 +589,10 @@ void snd_interval_muldivk(const snd_interval_t *a, const snd_interval_t *b, /** * snd_interval_mulkdiv - refine the interval value + * @a: dividend 1 + * @k: dividend 2 (as integer) + * @b: divisor + * @c: result * * c = a * k / b * @@ -618,6 +629,11 @@ void snd_interval_mulkdiv(const snd_interval_t *a, unsigned int k, /** * snd_interval_ratnum - refine the interval value + * @i: interval to refine + * @rats_count: number of ratnum_t + * @rats: ratnum_t array + * @nump: pointer to store the resultant numerator + * @denp: pointer to store the resultant denominator * * Returns non-zero if the value is changed, zero if not changed. */ @@ -715,6 +731,11 @@ int snd_interval_ratnum(snd_interval_t *i, /** * snd_interval_ratden - refine the interval value + * @i: interval to refine + * @rats_count: number of ratden_t + * @rats: ratden_t array + * @nump: pointer to store the resultant numerator + * @denp: pointer to store the resultant denominator * * Returns non-zero if the value is changed, zero if not changed. */ @@ -936,6 +957,11 @@ int snd_pcm_hw_rule_add(snd_pcm_runtime_t *runtime, unsigned int cond, /** * snd_pcm_hw_constraint_mask + * @runtime: PCM runtime instance + * @var: hw_params variable to apply the mask + * @mask: the bitmap mask + * + * Apply the constraint of the given bitmap mask to a mask parameter. */ int snd_pcm_hw_constraint_mask(snd_pcm_runtime_t *runtime, snd_pcm_hw_param_t var, u_int32_t mask) @@ -951,6 +977,11 @@ int snd_pcm_hw_constraint_mask(snd_pcm_runtime_t *runtime, snd_pcm_hw_param_t va /** * snd_pcm_hw_constraint_mask64 + * @runtime: PCM runtime instance + * @var: hw_params variable to apply the mask + * @mask: the 64bit bitmap mask + * + * Apply the constraint of the given bitmap mask to a mask parameter. */ int snd_pcm_hw_constraint_mask64(snd_pcm_runtime_t *runtime, snd_pcm_hw_param_t var, u_int64_t mask) @@ -967,6 +998,10 @@ int snd_pcm_hw_constraint_mask64(snd_pcm_runtime_t *runtime, snd_pcm_hw_param_t /** * snd_pcm_hw_constraint_integer + * @runtime: PCM runtime instance + * @var: hw_params variable to apply the integer constraint + * + * Apply the constraint of integer to an interval parameter. */ int snd_pcm_hw_constraint_integer(snd_pcm_runtime_t *runtime, snd_pcm_hw_param_t var) { @@ -976,6 +1011,12 @@ int snd_pcm_hw_constraint_integer(snd_pcm_runtime_t *runtime, snd_pcm_hw_param_t /** * snd_pcm_hw_constraint_minmax + * @runtime: PCM runtime instance + * @var: hw_params variable to apply the range + * @min: the minimal value + * @max: the maximal value + * + * Apply the min/max range constraint to an interval parameter. */ int snd_pcm_hw_constraint_minmax(snd_pcm_runtime_t *runtime, snd_pcm_hw_param_t var, unsigned int min, unsigned int max) @@ -999,6 +1040,12 @@ static int snd_pcm_hw_rule_list(snd_pcm_hw_params_t *params, /** * snd_pcm_hw_constraint_list + * @runtime: PCM runtime instance + * @cond: condition bits + * @var: hw_params variable to apply the list constraint + * @l: list + * + * Apply the list of constraints to an interval parameter. */ int snd_pcm_hw_constraint_list(snd_pcm_runtime_t *runtime, unsigned int cond, @@ -1027,6 +1074,10 @@ static int snd_pcm_hw_rule_ratnums(snd_pcm_hw_params_t *params, /** * snd_pcm_hw_constraint_ratnums + * @runtime: PCM runtime instance + * @cond: condition bits + * @var: hw_params variable to apply the ratnums constraint + * @r: ratnums_t constriants */ int snd_pcm_hw_constraint_ratnums(snd_pcm_runtime_t *runtime, unsigned int cond, @@ -1054,6 +1105,10 @@ static int snd_pcm_hw_rule_ratdens(snd_pcm_hw_params_t *params, /** * snd_pcm_hw_constraint_ratdens + * @runtime: PCM runtime instance + * @cond: condition bits + * @var: hw_params variable to apply the ratdens constraint + * @r: ratdens_t constriants */ int snd_pcm_hw_constraint_ratdens(snd_pcm_runtime_t *runtime, unsigned int cond, @@ -1079,6 +1134,10 @@ static int snd_pcm_hw_rule_msbits(snd_pcm_hw_params_t *params, /** * snd_pcm_hw_constraint_msbits + * @runtime: PCM runtime instance + * @cond: condition bits + * @width: sample bits width + * @msbits: msbits width */ int snd_pcm_hw_constraint_msbits(snd_pcm_runtime_t *runtime, unsigned int cond, @@ -1101,6 +1160,10 @@ static int snd_pcm_hw_rule_step(snd_pcm_hw_params_t *params, /** * snd_pcm_hw_constraint_step + * @runtime: PCM runtime instance + * @cond: condition bits + * @var: hw_params variable to apply the step constraint + * @step: step size */ int snd_pcm_hw_constraint_step(snd_pcm_runtime_t *runtime, unsigned int cond, @@ -1126,6 +1189,9 @@ static int snd_pcm_hw_rule_pow2(snd_pcm_hw_params_t *params, snd_pcm_hw_rule_t * /** * snd_pcm_hw_constraint_pow2 + * @runtime: PCM runtime instance + * @cond: condition bits + * @var: hw_params variable to apply the power-of-2 constraint */ int snd_pcm_hw_constraint_pow2(snd_pcm_runtime_t *runtime, unsigned int cond, @@ -1162,7 +1228,7 @@ static void _snd_pcm_hw_param_any(snd_pcm_hw_params_t *params, } #if 0 -/** +/* * snd_pcm_hw_param_any */ int snd_pcm_hw_param_any(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, @@ -1185,7 +1251,7 @@ void _snd_pcm_hw_params_any(snd_pcm_hw_params_t *params) } #if 0 -/** +/* * snd_pcm_hw_params_any * * Fill PARAMS with full configuration space boundaries @@ -1199,6 +1265,9 @@ int snd_pcm_hw_params_any(snd_pcm_t *pcm, snd_pcm_hw_params_t *params) /** * snd_pcm_hw_param_value + * @params: the hw_params instance + * @var: parameter to retrieve + * @dir: pointer to the direction (-1,0,1) or NULL * * Return the value for field PAR if it's fixed in configuration space * defined by PARAMS. Return -EINVAL otherwise @@ -1228,6 +1297,9 @@ static int snd_pcm_hw_param_value(const snd_pcm_hw_params_t *params, /** * snd_pcm_hw_param_value_min + * @params: the hw_params instance + * @var: parameter to retrieve + * @dir: pointer to the direction (-1,0,1) or NULL * * Return the minimum value for field PAR. */ @@ -1251,6 +1323,9 @@ unsigned int snd_pcm_hw_param_value_min(const snd_pcm_hw_params_t *params, /** * snd_pcm_hw_param_value_max + * @params: the hw_params instance + * @var: parameter to retrieve + * @dir: pointer to the direction (-1,0,1) or NULL * * Return the maximum value for field PAR. */ @@ -1302,7 +1377,7 @@ int _snd_pcm_hw_param_setinteger(snd_pcm_hw_params_t *params, } #if 0 -/** +/* * snd_pcm_hw_param_setinteger * * Inside configuration space defined by PARAMS remove from PAR all @@ -1347,6 +1422,10 @@ static int _snd_pcm_hw_param_first(snd_pcm_hw_params_t *params, /** * snd_pcm_hw_param_first + * @pcm: PCM instance + * @params: the hw_params instance + * @var: parameter to retrieve + * @dir: pointer to the direction (-1,0,1) or NULL * * Inside configuration space defined by PARAMS remove from PAR all * values > minimum. Reduce configuration space accordingly. @@ -1388,6 +1467,10 @@ static int _snd_pcm_hw_param_last(snd_pcm_hw_params_t *params, /** * snd_pcm_hw_param_last + * @pcm: PCM instance + * @params: the hw_params instance + * @var: parameter to retrieve + * @dir: pointer to the direction (-1,0,1) or NULL * * Inside configuration space defined by PARAMS remove from PAR all * values < maximum. Reduce configuration space accordingly. @@ -1439,6 +1522,11 @@ int _snd_pcm_hw_param_min(snd_pcm_hw_params_t *params, /** * snd_pcm_hw_param_min + * @pcm: PCM instance + * @params: the hw_params instance + * @var: parameter to retrieve + * @val: minimal value + * @dir: pointer to the direction (-1,0,1) or NULL * * Inside configuration space defined by PARAMS remove from PAR all * values < VAL. Reduce configuration space accordingly. @@ -1494,6 +1582,11 @@ static int _snd_pcm_hw_param_max(snd_pcm_hw_params_t *params, /** * snd_pcm_hw_param_max + * @pcm: PCM instance + * @params: the hw_params instance + * @var: parameter to retrieve + * @val: maximal value + * @dir: pointer to the direction (-1,0,1) or NULL * * Inside configuration space defined by PARAMS remove from PAR all * values >= VAL + 1. Reduce configuration space accordingly. @@ -1565,6 +1658,11 @@ int _snd_pcm_hw_param_set(snd_pcm_hw_params_t *params, /** * snd_pcm_hw_param_set + * @pcm: PCM instance + * @params: the hw_params instance + * @var: parameter to retrieve + * @val: value to set + * @dir: pointer to the direction (-1,0,1) or NULL * * Inside configuration space defined by PARAMS remove from PAR all * values != VAL. Reduce configuration space accordingly. @@ -1599,6 +1697,10 @@ static int _snd_pcm_hw_param_mask(snd_pcm_hw_params_t *params, /** * snd_pcm_hw_param_mask + * @pcm: PCM instance + * @params: the hw_params instance + * @var: parameter to retrieve + * @val: mask to apply * * Inside configuration space defined by PARAMS remove from PAR all values * not contained in MASK. Reduce configuration space accordingly. @@ -1671,6 +1773,11 @@ static int boundary_nearer(int min, int mindir, /** * snd_pcm_hw_param_near + * @pcm: PCM instance + * @params: the hw_params instance + * @var: parameter to retrieve + * @best: value to set + * @dir: pointer to the direction (-1,0,1) or NULL * * Inside configuration space defined by PARAMS set PAR to the available value * nearest to VAL. Reduce configuration space accordingly. @@ -1747,6 +1854,8 @@ int snd_pcm_hw_param_near(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, /** * snd_pcm_hw_param_choose + * @pcm: PCM instance + * @params: the hw_params instance * * Choose one configuration from configuration space defined by PARAMS * The configuration chosen is that obtained fixing in this order: diff --git a/sound/core/pcm_memory.c b/sound/core/pcm_memory.c index 9a174fb..b3f5344 100644 --- a/sound/core/pcm_memory.c +++ b/sound/core/pcm_memory.c @@ -244,7 +244,7 @@ int snd_pcm_lib_preallocate_pages(snd_pcm_substream_t *substream, /** * snd_pcm_lib_preallocate_pages_for_all - pre-allocation for continous memory type (all substreams) - * @substream: the pcm substream instance + * @pcm: the pcm instance * @type: DMA type (SNDRV_DMA_TYPE_*) * @data: DMA type dependant data * @size: the requested pre-allocation size in bytes @@ -321,7 +321,7 @@ int snd_pcm_lib_malloc_pages(snd_pcm_substream_t *substream, size_t size) if (substream->dma_buffer.area != NULL && substream->dma_buffer.bytes >= size) { dmab = &substream->dma_buffer; /* use the pre-allocated buffer */ } else { - dmab = kcalloc(1, sizeof(*dmab), GFP_KERNEL); + dmab = kzalloc(sizeof(*dmab), GFP_KERNEL); if (! dmab) return -ENOMEM; dmab->dev = substream->dma_buffer.dev; diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c index 03c1715..67abeba 100644 --- a/sound/core/pcm_native.c +++ b/sound/core/pcm_native.c @@ -859,6 +859,7 @@ static struct action_ops snd_pcm_action_start = { /** * snd_pcm_start + * @substream: the PCM substream instance * * Start all linked streams. */ @@ -908,6 +909,8 @@ static struct action_ops snd_pcm_action_stop = { /** * snd_pcm_stop + * @substream: the PCM substream instance + * @state: PCM state after stopping the stream * * Try to stop all running streams in the substream group. * The state of each stream is changed to the given value after that unconditionally. @@ -919,6 +922,7 @@ int snd_pcm_stop(snd_pcm_substream_t *substream, int state) /** * snd_pcm_drain_done + * @substream: the PCM substream * * Stop the DMA only when the given stream is playback. * The state is changed to SETUP. @@ -1040,6 +1044,7 @@ static struct action_ops snd_pcm_action_suspend = { /** * snd_pcm_suspend + * @substream: the PCM substream * * Trigger SUSPEND to all linked streams. * After this call, all streams are changed to SUSPENDED state. @@ -1057,6 +1062,7 @@ int snd_pcm_suspend(snd_pcm_substream_t *substream) /** * snd_pcm_suspend_all + * @pcm: the PCM instance * * Trigger SUSPEND to all substreams in the given pcm. * After this call, all streams are changed to SUSPENDED state. @@ -1272,6 +1278,9 @@ static struct action_ops snd_pcm_action_prepare = { /** * snd_pcm_prepare + * @substream: the PCM substream instance + * + * Prepare the PCM substream to be triggerable. */ int snd_pcm_prepare(snd_pcm_substream_t *substream) { @@ -1992,7 +2001,7 @@ static int snd_pcm_open_file(struct file *file, snd_assert(rpcm_file != NULL, return -EINVAL); *rpcm_file = NULL; - pcm_file = kcalloc(1, sizeof(*pcm_file), GFP_KERNEL); + pcm_file = kzalloc(sizeof(*pcm_file), GFP_KERNEL); if (pcm_file == NULL) { return -ENOMEM; } diff --git a/sound/core/rawmidi.c b/sound/core/rawmidi.c index edba411..7c20eaf 100644 --- a/sound/core/rawmidi.c +++ b/sound/core/rawmidi.c @@ -101,7 +101,7 @@ static int snd_rawmidi_runtime_create(snd_rawmidi_substream_t * substream) { snd_rawmidi_runtime_t *runtime; - if ((runtime = kcalloc(1, sizeof(*runtime), GFP_KERNEL)) == NULL) + if ((runtime = kzalloc(sizeof(*runtime), GFP_KERNEL)) == NULL) return -ENOMEM; spin_lock_init(&runtime->lock); init_waitqueue_head(&runtime->sleep); @@ -984,7 +984,9 @@ static ssize_t snd_rawmidi_read(struct file *file, char __user *buf, size_t coun spin_lock_irq(&runtime->lock); } spin_unlock_irq(&runtime->lock); - count1 = snd_rawmidi_kernel_read1(substream, (unsigned char *)buf, count, 0); + count1 = snd_rawmidi_kernel_read1(substream, + (unsigned char __force *)buf, + count, 0); if (count1 < 0) return result > 0 ? result : count1; result += count1; @@ -1107,7 +1109,7 @@ int snd_rawmidi_transmit_ack(snd_rawmidi_substream_t * substream, int count) /** * snd_rawmidi_transmit - copy from the buffer to the device * @substream: the rawmidi substream - * @buf: the buffer pointer + * @buffer: the buffer pointer * @count: the data size to transfer * * Copies data from the buffer to the device and advances the pointer. @@ -1213,7 +1215,9 @@ static ssize_t snd_rawmidi_write(struct file *file, const char __user *buf, size spin_lock_irq(&runtime->lock); } spin_unlock_irq(&runtime->lock); - count1 = snd_rawmidi_kernel_write1(substream, (unsigned char *)buf, count, 0); + count1 = snd_rawmidi_kernel_write1(substream, + (unsigned char __force *)buf, + count, 0); if (count1 < 0) return result > 0 ? result : count1; result += count1; @@ -1370,7 +1374,7 @@ static int snd_rawmidi_alloc_substreams(snd_rawmidi_t *rmidi, INIT_LIST_HEAD(&stream->substreams); for (idx = 0; idx < count; idx++) { - substream = kcalloc(1, sizeof(*substream), GFP_KERNEL); + substream = kzalloc(sizeof(*substream), GFP_KERNEL); if (substream == NULL) return -ENOMEM; substream->stream = direction; @@ -1413,7 +1417,7 @@ int snd_rawmidi_new(snd_card_t * card, char *id, int device, snd_assert(rrawmidi != NULL, return -EINVAL); *rrawmidi = NULL; snd_assert(card != NULL, return -ENXIO); - rmidi = kcalloc(1, sizeof(*rmidi), GFP_KERNEL); + rmidi = kzalloc(sizeof(*rmidi), GFP_KERNEL); if (rmidi == NULL) return -ENOMEM; rmidi->card = card; diff --git a/sound/core/seq/instr/ainstr_gf1.c b/sound/core/seq/instr/ainstr_gf1.c index 32e91c6..207c2c5 100644 --- a/sound/core/seq/instr/ainstr_gf1.c +++ b/sound/core/seq/instr/ainstr_gf1.c @@ -61,7 +61,7 @@ static int snd_seq_gf1_copy_wave_from_stream(snd_gf1_ops_t *ops, return -EFAULT; *data += sizeof(xp); *len -= sizeof(xp); - wp = kcalloc(1, sizeof(*wp), gfp_mask); + wp = kzalloc(sizeof(*wp), gfp_mask); if (wp == NULL) return -ENOMEM; wp->share_id[0] = le32_to_cpu(xp.share_id[0]); diff --git a/sound/core/seq/instr/ainstr_iw.c b/sound/core/seq/instr/ainstr_iw.c index 2622b86..b3cee09 100644 --- a/sound/core/seq/instr/ainstr_iw.c +++ b/sound/core/seq/instr/ainstr_iw.c @@ -92,7 +92,7 @@ static int snd_seq_iwffff_copy_env_from_stream(__u32 req_stype, points_size = (le16_to_cpu(rx.nattack) + le16_to_cpu(rx.nrelease)) * 2 * sizeof(__u16); if (points_size > *len) return -EINVAL; - rp = kcalloc(1, sizeof(*rp) + points_size, gfp_mask); + rp = kzalloc(sizeof(*rp) + points_size, gfp_mask); if (rp == NULL) return -ENOMEM; rp->nattack = le16_to_cpu(rx.nattack); @@ -139,7 +139,7 @@ static int snd_seq_iwffff_copy_wave_from_stream(snd_iwffff_ops_t *ops, return -EFAULT; *data += sizeof(xp); *len -= sizeof(xp); - wp = kcalloc(1, sizeof(*wp), gfp_mask); + wp = kzalloc(sizeof(*wp), gfp_mask); if (wp == NULL) return -ENOMEM; wp->share_id[0] = le32_to_cpu(xp.share_id[0]); @@ -273,7 +273,7 @@ static int snd_seq_iwffff_put(void *private_data, snd_seq_kinstr_t *instr, snd_seq_iwffff_instr_free(ops, ip, atomic); return -EINVAL; } - lp = kcalloc(1, sizeof(*lp), gfp_mask); + lp = kzalloc(sizeof(*lp), gfp_mask); if (lp == NULL) { snd_seq_iwffff_instr_free(ops, ip, atomic); return -ENOMEM; diff --git a/sound/core/seq/oss/seq_oss_init.c b/sound/core/seq/oss/seq_oss_init.c index bac4b4f..1ab1cf8 100644 --- a/sound/core/seq/oss/seq_oss_init.c +++ b/sound/core/seq/oss/seq_oss_init.c @@ -193,7 +193,7 @@ snd_seq_oss_open(struct file *file, int level) int i, rc; seq_oss_devinfo_t *dp; - if ((dp = kcalloc(1, sizeof(*dp), GFP_KERNEL)) == NULL) { + if ((dp = kzalloc(sizeof(*dp), GFP_KERNEL)) == NULL) { snd_printk(KERN_ERR "can't malloc device info\n"); return -ENOMEM; } diff --git a/sound/core/seq/oss/seq_oss_midi.c b/sound/core/seq/oss/seq_oss_midi.c index 9aece6c..f0e95c8 100644 --- a/sound/core/seq/oss/seq_oss_midi.c +++ b/sound/core/seq/oss/seq_oss_midi.c @@ -76,8 +76,8 @@ snd_seq_oss_midi_lookup_ports(int client) snd_seq_client_info_t *clinfo; snd_seq_port_info_t *pinfo; - clinfo = kcalloc(1, sizeof(*clinfo), GFP_KERNEL); - pinfo = kcalloc(1, sizeof(*pinfo), GFP_KERNEL); + clinfo = kzalloc(sizeof(*clinfo), GFP_KERNEL); + pinfo = kzalloc(sizeof(*pinfo), GFP_KERNEL); if (! clinfo || ! pinfo) { kfree(clinfo); kfree(pinfo); @@ -172,7 +172,7 @@ snd_seq_oss_midi_check_new_port(snd_seq_port_info_t *pinfo) /* * allocate midi info record */ - if ((mdev = kcalloc(1, sizeof(*mdev), GFP_KERNEL)) == NULL) { + if ((mdev = kzalloc(sizeof(*mdev), GFP_KERNEL)) == NULL) { snd_printk(KERN_ERR "can't malloc midi info\n"); return -ENOMEM; } diff --git a/sound/core/seq/oss/seq_oss_readq.c b/sound/core/seq/oss/seq_oss_readq.c index 0a6f2a6..55571e1 100644 --- a/sound/core/seq/oss/seq_oss_readq.c +++ b/sound/core/seq/oss/seq_oss_readq.c @@ -46,7 +46,7 @@ snd_seq_oss_readq_new(seq_oss_devinfo_t *dp, int maxlen) { seq_oss_readq_t *q; - if ((q = kcalloc(1, sizeof(*q), GFP_KERNEL)) == NULL) { + if ((q = kzalloc(sizeof(*q), GFP_KERNEL)) == NULL) { snd_printk(KERN_ERR "can't malloc read queue\n"); return NULL; } diff --git a/sound/core/seq/oss/seq_oss_synth.c b/sound/core/seq/oss/seq_oss_synth.c index 1a7736c..8257fce 100644 --- a/sound/core/seq/oss/seq_oss_synth.c +++ b/sound/core/seq/oss/seq_oss_synth.c @@ -103,7 +103,7 @@ snd_seq_oss_synth_register(snd_seq_device_t *dev) snd_seq_oss_reg_t *reg = SNDRV_SEQ_DEVICE_ARGPTR(dev); unsigned long flags; - if ((rec = kcalloc(1, sizeof(*rec), GFP_KERNEL)) == NULL) { + if ((rec = kzalloc(sizeof(*rec), GFP_KERNEL)) == NULL) { snd_printk(KERN_ERR "can't malloc synth info\n"); return -ENOMEM; } @@ -499,7 +499,7 @@ snd_seq_oss_synth_sysex(seq_oss_devinfo_t *dp, int dev, unsigned char *buf, snd_ sysex = dp->synths[dev].sysex; if (sysex == NULL) { - sysex = kcalloc(1, sizeof(*sysex), GFP_KERNEL); + sysex = kzalloc(sizeof(*sysex), GFP_KERNEL); if (sysex == NULL) return -ENOMEM; dp->synths[dev].sysex = sysex; diff --git a/sound/core/seq/oss/seq_oss_timer.c b/sound/core/seq/oss/seq_oss_timer.c index 42ca949..64d594b 100644 --- a/sound/core/seq/oss/seq_oss_timer.c +++ b/sound/core/seq/oss/seq_oss_timer.c @@ -46,7 +46,7 @@ snd_seq_oss_timer_new(seq_oss_devinfo_t *dp) { seq_oss_timer_t *rec; - rec = kcalloc(1, sizeof(*rec), GFP_KERNEL); + rec = kzalloc(sizeof(*rec), GFP_KERNEL); if (rec == NULL) return NULL; diff --git a/sound/core/seq/oss/seq_oss_writeq.c b/sound/core/seq/oss/seq_oss_writeq.c index 87f85f7..b203780 100644 --- a/sound/core/seq/oss/seq_oss_writeq.c +++ b/sound/core/seq/oss/seq_oss_writeq.c @@ -38,7 +38,7 @@ snd_seq_oss_writeq_new(seq_oss_devinfo_t *dp, int maxlen) seq_oss_writeq_t *q; snd_seq_client_pool_t pool; - if ((q = kcalloc(1, sizeof(*q), GFP_KERNEL)) == NULL) + if ((q = kzalloc(sizeof(*q), GFP_KERNEL)) == NULL) return NULL; q->dp = dp; q->maxlen = maxlen; diff --git a/sound/core/seq/seq.c b/sound/core/seq/seq.c index 7449d2a..24644150 100644 --- a/sound/core/seq/seq.c +++ b/sound/core/seq/seq.c @@ -43,7 +43,13 @@ int seq_client_load[64] = {[0 ... 63] = -1}; int seq_default_timer_class = SNDRV_TIMER_CLASS_GLOBAL; int seq_default_timer_sclass = SNDRV_TIMER_SCLASS_NONE; int seq_default_timer_card = -1; -int seq_default_timer_device = SNDRV_TIMER_GLOBAL_SYSTEM; +int seq_default_timer_device = +#ifdef CONFIG_SND_SEQ_RTCTIMER_DEFAULT + SNDRV_TIMER_GLOBAL_RTC +#else + SNDRV_TIMER_GLOBAL_SYSTEM +#endif + ; int seq_default_timer_subdevice = 0; int seq_default_timer_resolution = 0; /* Hz */ diff --git a/sound/core/seq/seq_clientmgr.c b/sound/core/seq/seq_clientmgr.c index d8f76af..a886db9 100644 --- a/sound/core/seq/seq_clientmgr.c +++ b/sound/core/seq/seq_clientmgr.c @@ -203,7 +203,7 @@ static client_t *seq_create_client1(int client_index, int poolsize) client_t *client; /* init client data */ - client = kcalloc(1, sizeof(*client), GFP_KERNEL); + client = kzalloc(sizeof(*client), GFP_KERNEL); if (client == NULL) return NULL; client->pool = snd_seq_pool_new(poolsize); @@ -413,7 +413,9 @@ static ssize_t snd_seq_read(struct file *file, char __user *buf, size_t count, l } count -= sizeof(snd_seq_event_t); buf += sizeof(snd_seq_event_t); - err = snd_seq_expand_var_event(&cell->event, count, (char *)buf, 0, sizeof(snd_seq_event_t)); + err = snd_seq_expand_var_event(&cell->event, count, + (char __force *)buf, 0, + sizeof(snd_seq_event_t)); if (err < 0) break; result += err; @@ -1009,7 +1011,8 @@ static ssize_t snd_seq_write(struct file *file, const char __user *buf, size_t c } /* set user space pointer */ event.data.ext.len = extlen | SNDRV_SEQ_EXT_USRPTR; - event.data.ext.ptr = (char*)buf + sizeof(snd_seq_event_t); + event.data.ext.ptr = (char __force *)buf + + sizeof(snd_seq_event_t); len += extlen; /* increment data length */ } else { #ifdef CONFIG_COMPAT diff --git a/sound/core/seq/seq_device.c b/sound/core/seq/seq_device.c index 4d80f39..252b527 100644 --- a/sound/core/seq/seq_device.c +++ b/sound/core/seq/seq_device.c @@ -200,7 +200,7 @@ int snd_seq_device_new(snd_card_t *card, int device, char *id, int argsize, if (ops == NULL) return -ENOMEM; - dev = kcalloc(1, sizeof(*dev)*2 + argsize, GFP_KERNEL); + dev = kzalloc(sizeof(*dev)*2 + argsize, GFP_KERNEL); if (dev == NULL) { unlock_driver(ops); return -ENOMEM; diff --git a/sound/core/seq/seq_dummy.c b/sound/core/seq/seq_dummy.c index ea945a5..5dd0e6a 100644 --- a/sound/core/seq/seq_dummy.c +++ b/sound/core/seq/seq_dummy.c @@ -153,7 +153,7 @@ create_port(int idx, int type) snd_seq_port_callback_t pcb; snd_seq_dummy_port_t *rec; - if ((rec = kcalloc(1, sizeof(*rec), GFP_KERNEL)) == NULL) + if ((rec = kzalloc(sizeof(*rec), GFP_KERNEL)) == NULL) return NULL; rec->client = my_client; diff --git a/sound/core/seq/seq_fifo.c b/sound/core/seq/seq_fifo.c index 3b7647c..4767cfd 100644 --- a/sound/core/seq/seq_fifo.c +++ b/sound/core/seq/seq_fifo.c @@ -33,7 +33,7 @@ fifo_t *snd_seq_fifo_new(int poolsize) { fifo_t *f; - f = kcalloc(1, sizeof(*f), GFP_KERNEL); + f = kzalloc(sizeof(*f), GFP_KERNEL); if (f == NULL) { snd_printd("malloc failed for snd_seq_fifo_new() \n"); return NULL; diff --git a/sound/core/seq/seq_instr.c b/sound/core/seq/seq_instr.c index 5b40ea2..019d43a 100644 --- a/sound/core/seq/seq_instr.c +++ b/sound/core/seq/seq_instr.c @@ -53,7 +53,7 @@ static snd_seq_kinstr_t *snd_seq_instr_new(int add_len, int atomic) { snd_seq_kinstr_t *instr; - instr = kcalloc(1, sizeof(snd_seq_kinstr_t) + add_len, atomic ? GFP_ATOMIC : GFP_KERNEL); + instr = kzalloc(sizeof(snd_seq_kinstr_t) + add_len, atomic ? GFP_ATOMIC : GFP_KERNEL); if (instr == NULL) return NULL; instr->add_len = add_len; @@ -77,7 +77,7 @@ snd_seq_kinstr_list_t *snd_seq_instr_list_new(void) { snd_seq_kinstr_list_t *list; - list = kcalloc(1, sizeof(snd_seq_kinstr_list_t), GFP_KERNEL); + list = kzalloc(sizeof(snd_seq_kinstr_list_t), GFP_KERNEL); if (list == NULL) return NULL; spin_lock_init(&list->lock); diff --git a/sound/core/seq/seq_memory.c b/sound/core/seq/seq_memory.c index 03acb2d..d4d7d32 100644 --- a/sound/core/seq/seq_memory.c +++ b/sound/core/seq/seq_memory.c @@ -452,7 +452,7 @@ pool_t *snd_seq_pool_new(int poolsize) pool_t *pool; /* create pool block */ - pool = kcalloc(1, sizeof(*pool), GFP_KERNEL); + pool = kzalloc(sizeof(*pool), GFP_KERNEL); if (pool == NULL) { snd_printd("seq: malloc failed for pool\n"); return NULL; diff --git a/sound/core/seq/seq_midi.c b/sound/core/seq/seq_midi.c index 4374829..b4674ae 100644 --- a/sound/core/seq/seq_midi.c +++ b/sound/core/seq/seq_midi.c @@ -322,7 +322,7 @@ snd_seq_midisynth_register_port(snd_seq_device_t *dev) client = synths[card->number]; if (client == NULL) { newclient = 1; - client = kcalloc(1, sizeof(*client), GFP_KERNEL); + client = kzalloc(sizeof(*client), GFP_KERNEL); if (client == NULL) { up(®ister_mutex); kfree(info); diff --git a/sound/core/seq/seq_midi_event.c b/sound/core/seq/seq_midi_event.c index 603b637..2dc1aec 100644 --- a/sound/core/seq/seq_midi_event.c +++ b/sound/core/seq/seq_midi_event.c @@ -118,7 +118,7 @@ int snd_midi_event_new(int bufsize, snd_midi_event_t **rdev) snd_midi_event_t *dev; *rdev = NULL; - dev = kcalloc(1, sizeof(*dev), GFP_KERNEL); + dev = kzalloc(sizeof(*dev), GFP_KERNEL); if (dev == NULL) return -ENOMEM; if (bufsize > 0) { diff --git a/sound/core/seq/seq_ports.c b/sound/core/seq/seq_ports.c index b976951..57ec31d 100644 --- a/sound/core/seq/seq_ports.c +++ b/sound/core/seq/seq_ports.c @@ -141,7 +141,7 @@ client_port_t *snd_seq_create_port(client_t *client, int port) } /* create a new port */ - new_port = kcalloc(1, sizeof(*new_port), GFP_KERNEL); + new_port = kzalloc(sizeof(*new_port), GFP_KERNEL); if (! new_port) { snd_printd("malloc failed for registering client port\n"); return NULL; /* failure, out of memory */ @@ -488,7 +488,7 @@ int snd_seq_port_connect(client_t *connector, unsigned long flags; int exclusive; - subs = kcalloc(1, sizeof(*subs), GFP_KERNEL); + subs = kzalloc(sizeof(*subs), GFP_KERNEL); if (! subs) return -ENOMEM; diff --git a/sound/core/seq/seq_prioq.c b/sound/core/seq/seq_prioq.c index a519732e..cd641bc 100644 --- a/sound/core/seq/seq_prioq.c +++ b/sound/core/seq/seq_prioq.c @@ -59,7 +59,7 @@ prioq_t *snd_seq_prioq_new(void) { prioq_t *f; - f = kcalloc(1, sizeof(*f), GFP_KERNEL); + f = kzalloc(sizeof(*f), GFP_KERNEL); if (f == NULL) { snd_printd("oops: malloc failed for snd_seq_prioq_new()\n"); return NULL; diff --git a/sound/core/seq/seq_queue.c b/sound/core/seq/seq_queue.c index 98de2e7..5f5c3cb 100644 --- a/sound/core/seq/seq_queue.c +++ b/sound/core/seq/seq_queue.c @@ -111,7 +111,7 @@ static queue_t *queue_new(int owner, int locked) { queue_t *q; - q = kcalloc(1, sizeof(*q), GFP_KERNEL); + q = kzalloc(sizeof(*q), GFP_KERNEL); if (q == NULL) { snd_printd("malloc failed for snd_seq_queue_new()\n"); return NULL; diff --git a/sound/core/seq/seq_system.c b/sound/core/seq/seq_system.c index e8f0a66..0d9eff8 100644 --- a/sound/core/seq/seq_system.c +++ b/sound/core/seq/seq_system.c @@ -126,8 +126,8 @@ int __init snd_seq_system_client_init(void) snd_seq_client_info_t *inf; snd_seq_port_info_t *port; - inf = kcalloc(1, sizeof(*inf), GFP_KERNEL); - port = kcalloc(1, sizeof(*port), GFP_KERNEL); + inf = kzalloc(sizeof(*inf), GFP_KERNEL); + port = kzalloc(sizeof(*port), GFP_KERNEL); if (! inf || ! port) { kfree(inf); kfree(port); diff --git a/sound/core/seq/seq_timer.c b/sound/core/seq/seq_timer.c index a7f76fc..b57a3c0 100644 --- a/sound/core/seq/seq_timer.c +++ b/sound/core/seq/seq_timer.c @@ -60,7 +60,7 @@ seq_timer_t *snd_seq_timer_new(void) { seq_timer_t *tmr; - tmr = kcalloc(1, sizeof(*tmr), GFP_KERNEL); + tmr = kzalloc(sizeof(*tmr), GFP_KERNEL); if (tmr == NULL) { snd_printd("malloc failed for snd_seq_timer_new() \n"); return NULL; diff --git a/sound/core/seq/seq_virmidi.c b/sound/core/seq/seq_virmidi.c index a66484b5..e4f512a 100644 --- a/sound/core/seq/seq_virmidi.c +++ b/sound/core/seq/seq_virmidi.c @@ -205,7 +205,7 @@ static int snd_virmidi_input_open(snd_rawmidi_substream_t * substream) snd_virmidi_t *vmidi; unsigned long flags; - vmidi = kcalloc(1, sizeof(*vmidi), GFP_KERNEL); + vmidi = kzalloc(sizeof(*vmidi), GFP_KERNEL); if (vmidi == NULL) return -ENOMEM; vmidi->substream = substream; @@ -233,7 +233,7 @@ static int snd_virmidi_output_open(snd_rawmidi_substream_t * substream) snd_rawmidi_runtime_t *runtime = substream->runtime; snd_virmidi_t *vmidi; - vmidi = kcalloc(1, sizeof(*vmidi), GFP_KERNEL); + vmidi = kzalloc(sizeof(*vmidi), GFP_KERNEL); if (vmidi == NULL) return -ENOMEM; vmidi->substream = substream; @@ -508,7 +508,7 @@ int snd_virmidi_new(snd_card_t *card, int device, snd_rawmidi_t **rrmidi) &rmidi)) < 0) return err; strcpy(rmidi->name, rmidi->id); - rdev = kcalloc(1, sizeof(*rdev), GFP_KERNEL); + rdev = kzalloc(sizeof(*rdev), GFP_KERNEL); if (rdev == NULL) { snd_device_free(card, rmidi); return -ENOMEM; diff --git a/sound/core/sound.c b/sound/core/sound.c index 3271e92..9e76bdd 100644 --- a/sound/core/sound.c +++ b/sound/core/sound.c @@ -328,6 +328,10 @@ int __exit snd_minor_info_done(void) * INIT PART */ +#ifdef CONFIG_SND_GENERIC_DRIVER +extern struct device_driver snd_generic_driver; +#endif + static int __init alsa_sound_init(void) { short controlnum; @@ -354,6 +358,9 @@ static int __init alsa_sound_init(void) return -ENOMEM; } snd_info_minor_register(); +#ifdef CONFIG_SND_GENERIC_DRIVER + driver_register(&snd_generic_driver); +#endif for (controlnum = 0; controlnum < cards_limit; controlnum++) devfs_mk_cdev(MKDEV(major, controlnum<<5), S_IFCHR | device_mode, "snd/controlC%d", controlnum); #ifndef MODULE @@ -369,6 +376,9 @@ static void __exit alsa_sound_exit(void) for (controlnum = 0; controlnum < cards_limit; controlnum++) devfs_remove("snd/controlC%d", controlnum); +#ifdef CONFIG_SND_GENERIC_DRIVER + driver_unregister(&snd_generic_driver); +#endif snd_info_minor_unregister(); snd_info_done(); snd_memory_done(); @@ -416,10 +426,13 @@ EXPORT_SYMBOL(snd_card_register); EXPORT_SYMBOL(snd_component_add); EXPORT_SYMBOL(snd_card_file_add); EXPORT_SYMBOL(snd_card_file_remove); +#ifdef CONFIG_SND_GENERIC_DRIVER +EXPORT_SYMBOL(snd_card_set_generic_dev); +#endif #ifdef CONFIG_PM EXPORT_SYMBOL(snd_power_wait); EXPORT_SYMBOL(snd_card_set_pm_callback); -#if defined(CONFIG_PM) && defined(CONFIG_SND_GENERIC_PM) +#ifdef CONFIG_SND_GENERIC_DRIVER EXPORT_SYMBOL(snd_card_set_generic_pm_callback); #endif #ifdef CONFIG_PCI diff --git a/sound/core/timer.c b/sound/core/timer.c index 4104f6e..22b1046 100644 --- a/sound/core/timer.c +++ b/sound/core/timer.c @@ -98,7 +98,7 @@ static void snd_timer_reschedule(snd_timer_t * timer, unsigned long ticks_left); static snd_timer_instance_t *snd_timer_instance_new(char *owner, snd_timer_t *timer) { snd_timer_instance_t *timeri; - timeri = kcalloc(1, sizeof(*timeri), GFP_KERNEL); + timeri = kzalloc(sizeof(*timeri), GFP_KERNEL); if (timeri == NULL) return NULL; timeri->owner = kstrdup(owner, GFP_KERNEL); @@ -764,7 +764,7 @@ int snd_timer_new(snd_card_t *card, char *id, snd_timer_id_t *tid, snd_timer_t * snd_assert(tid != NULL, return -EINVAL); snd_assert(rtimer != NULL, return -EINVAL); *rtimer = NULL; - timer = kcalloc(1, sizeof(*timer), GFP_KERNEL); + timer = kzalloc(sizeof(*timer), GFP_KERNEL); if (timer == NULL) return -ENOMEM; timer->tmr_class = tid->dev_class; @@ -1017,7 +1017,7 @@ static int snd_timer_register_system(void) return err; strcpy(timer->name, "system timer"); timer->hw = snd_timer_system; - priv = kcalloc(1, sizeof(*priv), GFP_KERNEL); + priv = kzalloc(sizeof(*priv), GFP_KERNEL); if (priv == NULL) { snd_timer_free(timer); return -ENOMEM; @@ -1202,7 +1202,7 @@ static int snd_timer_user_open(struct inode *inode, struct file *file) { snd_timer_user_t *tu; - tu = kcalloc(1, sizeof(*tu), GFP_KERNEL); + tu = kzalloc(sizeof(*tu), GFP_KERNEL); if (tu == NULL) return -ENOMEM; spin_lock_init(&tu->qlock); @@ -1513,7 +1513,7 @@ static int snd_timer_user_info(struct file *file, snd_timer_info_t __user *_info t = tu->timeri->timer; snd_assert(t != NULL, return -ENXIO); - info = kcalloc(1, sizeof(*info), GFP_KERNEL); + info = kzalloc(sizeof(*info), GFP_KERNEL); if (! info) return -ENOMEM; info->card = t->card ? t->card->number : -1; diff --git a/sound/drivers/Kconfig b/sound/drivers/Kconfig index 3b2bee1..efcb4eb 100644 --- a/sound/drivers/Kconfig +++ b/sound/drivers/Kconfig @@ -29,6 +29,7 @@ config SND_DUMMY tristate "Dummy (/dev/null) soundcard" depends on SND select SND_PCM + select SND_GENERIC_DRIVER help Say Y here to include the dummy driver. This driver does nothing, but emulates various mixer controls and PCM devices. @@ -44,6 +45,7 @@ config SND_VIRMIDI depends on SND_SEQUENCER select SND_TIMER select SND_RAWMIDI + select SND_GENERIC_DRIVER help Say Y here to include the virtual MIDI driver. This driver allows to connect applications using raw MIDI devices to @@ -59,6 +61,7 @@ config SND_MTPAV depends on SND select SND_TIMER select SND_RAWMIDI + select SND_GENERIC_DRIVER help To use a MOTU MidiTimePiece AV multiport MIDI adapter connected to the parallel port, say Y here and make sure that @@ -72,6 +75,7 @@ config SND_SERIAL_U16550 depends on SND select SND_TIMER select SND_RAWMIDI + select SND_GENERIC_DRIVER help To include support for MIDI serial port interfaces, say Y here and read <file:Documentation/sound/alsa/serial-u16550.txt>. @@ -88,6 +92,7 @@ config SND_MPU401 tristate "Generic MPU-401 UART driver" depends on SND select SND_MPU401_UART + select SND_GENERIC_DRIVER help Say Y here to include support for MIDI ports compatible with the Roland MPU-401 interface in UART mode. diff --git a/sound/drivers/dummy.c b/sound/drivers/dummy.c index a61640c..64ef7f6 100644 --- a/sound/drivers/dummy.c +++ b/sound/drivers/dummy.c @@ -337,7 +337,7 @@ static int snd_card_dummy_playback_open(snd_pcm_substream_t * substream) snd_card_dummy_pcm_t *dpcm; int err; - dpcm = kcalloc(1, sizeof(*dpcm), GFP_KERNEL); + dpcm = kzalloc(sizeof(*dpcm), GFP_KERNEL); if (dpcm == NULL) return -ENOMEM; init_timer(&dpcm->timer); @@ -368,7 +368,7 @@ static int snd_card_dummy_capture_open(snd_pcm_substream_t * substream) snd_card_dummy_pcm_t *dpcm; int err; - dpcm = kcalloc(1, sizeof(*dpcm), GFP_KERNEL); + dpcm = kzalloc(sizeof(*dpcm), GFP_KERNEL); if (dpcm == NULL) return -ENOMEM; init_timer(&dpcm->timer); @@ -600,6 +600,10 @@ static int __init snd_card_dummy_probe(int dev) strcpy(card->driver, "Dummy"); strcpy(card->shortname, "Dummy"); sprintf(card->longname, "Dummy %i", dev + 1); + + if ((err = snd_card_set_generic_dev(card)) < 0) + goto __nodev; + if ((err = snd_card_register(card)) == 0) { snd_dummy_cards[dev] = card; return 0; diff --git a/sound/drivers/mpu401/mpu401.c b/sound/drivers/mpu401/mpu401.c index cb36ecb..54e2ff9 100644 --- a/sound/drivers/mpu401/mpu401.c +++ b/sound/drivers/mpu401/mpu401.c @@ -77,20 +77,26 @@ static int snd_mpu401_create(int dev, snd_card_t **rcard) strcat(card->longname, "polled"); } - if (snd_mpu401_uart_new(card, 0, - MPU401_HW_MPU401, - port[dev], 0, - irq[dev], irq[dev] >= 0 ? SA_INTERRUPT : 0, NULL) < 0) { + if ((err = snd_mpu401_uart_new(card, 0, + MPU401_HW_MPU401, + port[dev], 0, + irq[dev], irq[dev] >= 0 ? SA_INTERRUPT : 0, NULL)) < 0) { printk(KERN_ERR "MPU401 not detected at 0x%lx\n", port[dev]); - snd_card_free(card); - return -ENODEV; - } - if ((err = snd_card_register(card)) < 0) { - snd_card_free(card); - return err; + goto _err; } + + if ((err = snd_card_set_generic_dev(card)) < 0) + goto _err; + + if ((err = snd_card_register(card)) < 0) + goto _err; + *rcard = card; return 0; + + _err: + snd_card_free(card); + return err; } static int __devinit snd_mpu401_probe(int dev) diff --git a/sound/drivers/mpu401/mpu401_uart.c b/sound/drivers/mpu401/mpu401_uart.c index 0f83c52..fe3f921 100644 --- a/sound/drivers/mpu401/mpu401_uart.c +++ b/sound/drivers/mpu401/mpu401_uart.c @@ -463,7 +463,7 @@ int snd_mpu401_uart_new(snd_card_t * card, int device, *rrawmidi = NULL; if ((err = snd_rawmidi_new(card, "MPU-401U", device, 1, 1, &rmidi)) < 0) return err; - mpu = kcalloc(1, sizeof(*mpu), GFP_KERNEL); + mpu = kzalloc(sizeof(*mpu), GFP_KERNEL); if (mpu == NULL) { snd_device_free(card, rmidi); return -ENOMEM; diff --git a/sound/drivers/mtpav.c b/sound/drivers/mtpav.c index 1280a57..3a25c89 100644 --- a/sound/drivers/mtpav.c +++ b/sound/drivers/mtpav.c @@ -688,7 +688,7 @@ static int snd_mtpav_get_RAWMIDI(mtpav_t * mcard) static mtpav_t *new_mtpav(void) { - mtpav_t *ncrd = kcalloc(1, sizeof(*ncrd), GFP_KERNEL); + mtpav_t *ncrd = kzalloc(sizeof(*ncrd), GFP_KERNEL); if (ncrd != NULL) { spin_lock_init(&ncrd->spinlock); @@ -757,6 +757,9 @@ static int __init alsa_card_mtpav_init(void) if (err < 0) goto __error; + if ((err = snd_card_set_generic_dev(mtp_card->card)) < 0) + goto __error; + err = snd_card_register(mtp_card->card); // don't snd_card_register until AFTER all cards reources done! //printk("snd_card_register returned %d\n", err); diff --git a/sound/drivers/opl3/opl3_lib.c b/sound/drivers/opl3/opl3_lib.c index c313e52..1f84d78 100644 --- a/sound/drivers/opl3/opl3_lib.c +++ b/sound/drivers/opl3/opl3_lib.c @@ -354,7 +354,7 @@ int snd_opl3_new(snd_card_t *card, int err; *ropl3 = NULL; - opl3 = kcalloc(1, sizeof(*opl3), GFP_KERNEL); + opl3 = kzalloc(sizeof(*opl3), GFP_KERNEL); if (opl3 == NULL) return -ENOMEM; diff --git a/sound/drivers/opl3/opl3_oss.c b/sound/drivers/opl3/opl3_oss.c index 33da334..21a2b40 100644 --- a/sound/drivers/opl3/opl3_oss.c +++ b/sound/drivers/opl3/opl3_oss.c @@ -241,7 +241,7 @@ static int snd_opl3_load_patch_seq_oss(snd_seq_oss_arg_t *arg, int format, } size = sizeof(*put) + sizeof(fm_xinstrument_t); - put = kcalloc(1, size, GFP_KERNEL); + put = kzalloc(size, GFP_KERNEL); if (put == NULL) return -ENOMEM; /* build header */ diff --git a/sound/drivers/opl4/opl4_lib.c b/sound/drivers/opl4/opl4_lib.c index 8261464..380c2c7 100644 --- a/sound/drivers/opl4/opl4_lib.c +++ b/sound/drivers/opl4/opl4_lib.c @@ -204,7 +204,7 @@ int snd_opl4_create(snd_card_t *card, if (ropl4) *ropl4 = NULL; - opl4 = kcalloc(1, sizeof(*opl4), GFP_KERNEL); + opl4 = kzalloc(sizeof(*opl4), GFP_KERNEL); if (!opl4) return -ENOMEM; diff --git a/sound/drivers/serial-u16550.c b/sound/drivers/serial-u16550.c index 986df35..416172e 100644 --- a/sound/drivers/serial-u16550.c +++ b/sound/drivers/serial-u16550.c @@ -779,7 +779,7 @@ static int __init snd_uart16550_create(snd_card_t * card, int err; - if ((uart = kcalloc(1, sizeof(*uart), GFP_KERNEL)) == NULL) + if ((uart = kzalloc(sizeof(*uart), GFP_KERNEL)) == NULL) return -ENOMEM; uart->adaptor = adaptor; uart->card = card; @@ -928,15 +928,11 @@ static int __init snd_serial_probe(int dev) base[dev], adaptor[dev], droponfull[dev], - &uart)) < 0) { - snd_card_free(card); - return err; - } + &uart)) < 0) + goto _err; - if ((err = snd_uart16550_rmidi(uart, 0, outs[dev], ins[dev], &uart->rmidi)) < 0) { - snd_card_free(card); - return err; - } + if ((err = snd_uart16550_rmidi(uart, 0, outs[dev], ins[dev], &uart->rmidi)) < 0) + goto _err; sprintf(card->longname, "%s at 0x%lx, irq %d speed %d div %d outs %d ins %d adaptor %s droponfull %d", card->shortname, @@ -949,12 +945,18 @@ static int __init snd_serial_probe(int dev) adaptor_names[uart->adaptor], uart->drop_on_full); - if ((err = snd_card_register(card)) < 0) { - snd_card_free(card); - return err; - } + if ((err = snd_card_set_generic_dev(card)) < 0) + goto _err; + + if ((err = snd_card_register(card)) < 0) + goto _err; + snd_serial_cards[dev] = card; return 0; + + _err: + snd_card_free(card); + return err; } static int __init alsa_card_serial_init(void) diff --git a/sound/drivers/virmidi.c b/sound/drivers/virmidi.c index 5937711..af12185 100644 --- a/sound/drivers/virmidi.c +++ b/sound/drivers/virmidi.c @@ -116,6 +116,10 @@ static int __init snd_card_virmidi_probe(int dev) strcpy(card->driver, "VirMIDI"); strcpy(card->shortname, "VirMIDI"); sprintf(card->longname, "Virtual MIDI Card %i", dev + 1); + + if ((err = snd_card_set_generic_dev(card)) < 0) + goto __nodev; + if ((err = snd_card_register(card)) == 0) { snd_virmidi_cards[dev] = card; return 0; diff --git a/sound/drivers/vx/vx_core.c b/sound/drivers/vx/vx_core.c index c6fa5af..4697b1d 100644 --- a/sound/drivers/vx/vx_core.c +++ b/sound/drivers/vx/vx_core.c @@ -782,7 +782,7 @@ vx_core_t *snd_vx_create(snd_card_t *card, struct snd_vx_hardware *hw, snd_assert(card && hw && ops, return NULL); - chip = kcalloc(1, sizeof(*chip) + extra_size, GFP_KERNEL); + chip = kzalloc(sizeof(*chip) + extra_size, GFP_KERNEL); if (! chip) { snd_printk(KERN_ERR "vx_core: no memory\n"); return NULL; diff --git a/sound/drivers/vx/vx_pcm.c b/sound/drivers/vx/vx_pcm.c index d4becf4..c2312d9 100644 --- a/sound/drivers/vx/vx_pcm.c +++ b/sound/drivers/vx/vx_pcm.c @@ -473,7 +473,7 @@ static int vx_alloc_pipe(vx_core_t *chip, int capture, return err; /* initialize the pipe record */ - pipe = kcalloc(1, sizeof(*pipe), GFP_KERNEL); + pipe = kzalloc(sizeof(*pipe), GFP_KERNEL); if (! pipe) { /* release the pipe */ vx_init_rmh(&rmh, CMD_FREE_PIPE); diff --git a/sound/i2c/cs8427.c b/sound/i2c/cs8427.c index a3fda85..a21f7d5 100644 --- a/sound/i2c/cs8427.c +++ b/sound/i2c/cs8427.c @@ -200,7 +200,7 @@ int snd_cs8427_create(snd_i2c_bus_t *bus, if ((err = snd_i2c_device_create(bus, "CS8427", CS8427_ADDR | (addr & 7), &device)) < 0) return err; - chip = device->private_data = kcalloc(1, sizeof(*chip), GFP_KERNEL); + chip = device->private_data = kzalloc(sizeof(*chip), GFP_KERNEL); if (chip == NULL) { snd_i2c_device_free(device); return -ENOMEM; diff --git a/sound/i2c/i2c.c b/sound/i2c/i2c.c index e8fa7e1..e4e505b 100644 --- a/sound/i2c/i2c.c +++ b/sound/i2c/i2c.c @@ -81,7 +81,7 @@ int snd_i2c_bus_create(snd_card_t *card, const char *name, snd_i2c_bus_t *master }; *ri2c = NULL; - bus = kcalloc(1, sizeof(*bus), GFP_KERNEL); + bus = kzalloc(sizeof(*bus), GFP_KERNEL); if (bus == NULL) return -ENOMEM; init_MUTEX(&bus->lock_mutex); @@ -108,7 +108,7 @@ int snd_i2c_device_create(snd_i2c_bus_t *bus, const char *name, unsigned char ad *rdevice = NULL; snd_assert(bus != NULL, return -EINVAL); - device = kcalloc(1, sizeof(*device), GFP_KERNEL); + device = kzalloc(sizeof(*device), GFP_KERNEL); if (device == NULL) return -ENOMEM; device->addr = addr; diff --git a/sound/i2c/l3/uda1341.c b/sound/i2c/l3/uda1341.c index e13122f..103a7dc 100644 --- a/sound/i2c/l3/uda1341.c +++ b/sound/i2c/l3/uda1341.c @@ -17,7 +17,7 @@ * 2002-05-12 Tomas Kasparek another code cleanup */ -/* $Id: uda1341.c,v 1.15 2005/01/03 12:05:20 tiwai Exp $ */ +/* $Id: uda1341.c,v 1.16 2005/09/09 13:22:34 tiwai Exp $ */ #include <sound/driver.h> #include <linux/module.h> @@ -670,7 +670,7 @@ int __init snd_chip_uda1341_mixer_new(snd_card_t *card, struct l3_client **clnt) snd_assert(card != NULL, return -EINVAL); - uda1341 = kcalloc(1, sizeof(*uda1341), GFP_KERNEL); + uda1341 = kzalloc(sizeof(*uda1341), GFP_KERNEL); if (uda1341 == NULL) return -ENOMEM; @@ -707,7 +707,7 @@ static int uda1341_attach(struct l3_client *clnt) { struct uda1341 *uda; - uda = kcalloc(1, sizeof(*uda), 0, GFP_KERNEL); + uda = kzalloc(sizeof(*uda), 0, GFP_KERNEL); if (!uda) return -ENOMEM; diff --git a/sound/i2c/other/ak4114.c b/sound/i2c/other/ak4114.c index 5adde30..af5eadc 100644 --- a/sound/i2c/other/ak4114.c +++ b/sound/i2c/other/ak4114.c @@ -92,7 +92,7 @@ int snd_ak4114_create(snd_card_t *card, .dev_free = snd_ak4114_dev_free, }; - chip = kcalloc(1, sizeof(*chip), GFP_KERNEL); + chip = kzalloc(sizeof(*chip), GFP_KERNEL); if (chip == NULL) return -ENOMEM; spin_lock_init(&chip->lock); diff --git a/sound/i2c/other/ak4117.c b/sound/i2c/other/ak4117.c index 0419c433..d51b51d 100644 --- a/sound/i2c/other/ak4117.c +++ b/sound/i2c/other/ak4117.c @@ -83,7 +83,7 @@ int snd_ak4117_create(snd_card_t *card, ak4117_read_t *read, ak4117_write_t *wri .dev_free = snd_ak4117_dev_free, }; - chip = kcalloc(1, sizeof(*chip), GFP_KERNEL); + chip = kzalloc(sizeof(*chip), GFP_KERNEL); if (chip == NULL) return -ENOMEM; spin_lock_init(&chip->lock); diff --git a/sound/i2c/tea6330t.c b/sound/i2c/tea6330t.c index 2da8d7f..fd65da6 100644 --- a/sound/i2c/tea6330t.c +++ b/sound/i2c/tea6330t.c @@ -281,7 +281,7 @@ int snd_tea6330t_update_mixer(snd_card_t * card, u8 default_treble, default_bass; unsigned char bytes[7]; - tea = kcalloc(1, sizeof(*tea), GFP_KERNEL); + tea = kzalloc(sizeof(*tea), GFP_KERNEL); if (tea == NULL) return -ENOMEM; if ((err = snd_i2c_device_create(bus, "TEA6330T", TEA6330T_ADDR, &device)) < 0) { diff --git a/sound/isa/Kconfig b/sound/isa/Kconfig index 5c39483..5d6c300a 100644 --- a/sound/isa/Kconfig +++ b/sound/isa/Kconfig @@ -6,12 +6,12 @@ menu "ISA devices" config SND_AD1848_LIB tristate select SND_PCM - select SND_GENERIC_PM + select SND_GENERIC_DRIVER config SND_CS4231_LIB tristate select SND_PCM - select SND_GENERIC_PM + select SND_GENERIC_DRIVER config SND_AD1816A tristate "Analog Devices SoundPort AD1816A" @@ -97,6 +97,7 @@ config SND_ES1688 select SND_OPL3_LIB select SND_MPU401_UART select SND_PCM + select SND_GENERIC_DRIVER help Say Y here to include support for ESS AudioDrive ES688 or ES1688 chips. @@ -110,7 +111,7 @@ config SND_ES18XX select SND_OPL3_LIB select SND_MPU401_UART select SND_PCM - select SND_GENERIC_PM + select SND_GENERIC_DRIVER help Say Y here to include support for ESS AudioDrive ES18xx chips. @@ -126,6 +127,7 @@ config SND_GUSCLASSIC select SND_RAWMIDI select SND_PCM select SND_GUS_SYNTH + select SND_GENERIC_DRIVER help Say Y here to include support for Gravis UltraSound Classic soundcards. @@ -140,6 +142,7 @@ config SND_GUSEXTREME select SND_MPU401_UART select SND_PCM select SND_GUS_SYNTH + select SND_GENERIC_DRIVER help Say Y here to include support for Gravis UltraSound Extreme soundcards. @@ -153,6 +156,7 @@ config SND_GUSMAX select SND_RAWMIDI select SND_CS4231_LIB select SND_GUS_SYNTH + select SND_GENERIC_DRIVER help Say Y here to include support for Gravis UltraSound MAX soundcards. @@ -166,7 +170,7 @@ config SND_INTERWAVE select SND_RAWMIDI select SND_CS4231_LIB select SND_GUS_SYNTH - select ISAPNP + select SND_GENERIC_DRIVER help Say Y here to include support for AMD InterWave based soundcards (Gravis UltraSound Plug & Play, STB SoundRage32, @@ -181,7 +185,7 @@ config SND_INTERWAVE_STB select SND_RAWMIDI select SND_CS4231_LIB select SND_GUS_SYNTH - select ISAPNP + select SND_GENERIC_DRIVER help Say Y here to include support for AMD InterWave based soundcards with a TEA6330T bass and treble regulator @@ -224,6 +228,7 @@ config SND_OPTI93X select SND_OPL3_LIB select SND_MPU401_UART select SND_PCM + select SND_GENERIC_DRIVER help Say Y here to include support for soundcards based on Opti 82C93x chips. @@ -237,6 +242,7 @@ config SND_SB8 select SND_OPL3_LIB select SND_RAWMIDI select SND_PCM + select SND_GENERIC_DRIVER help Say Y here to include support for Creative Sound Blaster 1.0/ 2.0/Pro (8-bit) or 100% compatible soundcards. @@ -250,6 +256,7 @@ config SND_SB16 select SND_OPL3_LIB select SND_MPU401_UART select SND_PCM + select SND_GENERIC_DRIVER help Say Y here to include support for Sound Blaster 16 soundcards (including the Plug and Play version). @@ -263,6 +270,7 @@ config SND_SBAWE select SND_OPL3_LIB select SND_MPU401_UART select SND_PCM + select SND_GENERIC_DRIVER help Say Y here to include support for Sound Blaster AWE soundcards (including the Plug and Play version). diff --git a/sound/isa/ad1816a/ad1816a_lib.c b/sound/isa/ad1816a/ad1816a_lib.c index ae86036..27a9dcf 100644 --- a/sound/isa/ad1816a/ad1816a_lib.c +++ b/sound/isa/ad1816a/ad1816a_lib.c @@ -591,7 +591,7 @@ int snd_ad1816a_create(snd_card_t *card, *rchip = NULL; - chip = kcalloc(1, sizeof(*chip), GFP_KERNEL); + chip = kzalloc(sizeof(*chip), GFP_KERNEL); if (chip == NULL) return -ENOMEM; chip->irq = -1; diff --git a/sound/isa/ad1848/ad1848.c b/sound/isa/ad1848/ad1848.c index 8c39934..3ebcc48 100644 --- a/sound/isa/ad1848/ad1848.c +++ b/sound/isa/ad1848/ad1848.c @@ -91,35 +91,36 @@ static int __init snd_card_ad1848_probe(int dev) irq[dev], dma1[dev], thinkpad[dev] ? AD1848_HW_THINKPAD : AD1848_HW_DETECT, - &chip)) < 0) { - snd_card_free(card); - return err; - } + &chip)) < 0) + goto _err; + + if ((err = snd_ad1848_pcm(chip, 0, &pcm)) < 0) + goto _err; + + if ((err = snd_ad1848_mixer(chip)) < 0) + goto _err; - if ((err = snd_ad1848_pcm(chip, 0, &pcm)) < 0) { - snd_card_free(card); - return err; - } - if ((err = snd_ad1848_mixer(chip)) < 0) { - snd_card_free(card); - return err; - } strcpy(card->driver, "AD1848"); strcpy(card->shortname, pcm->name); sprintf(card->longname, "%s at 0x%lx, irq %d, dma %d", pcm->name, chip->port, irq[dev], dma1[dev]); - if (thinkpad[dev]) { + if (thinkpad[dev]) strcat(card->longname, " [Thinkpad]"); - } - if ((err = snd_card_register(card)) < 0) { - snd_card_free(card); - return err; - } + if ((err = snd_card_set_generic_dev(card)) < 0) + goto _err; + + if ((err = snd_card_register(card)) < 0) + goto _err; + snd_ad1848_cards[dev] = card; return 0; + + _err: + snd_card_free(card); + return err; } static int __init alsa_card_ad1848_init(void) diff --git a/sound/isa/ad1848/ad1848_lib.c b/sound/isa/ad1848/ad1848_lib.c index bc642dc..303861c 100644 --- a/sound/isa/ad1848/ad1848_lib.c +++ b/sound/isa/ad1848/ad1848_lib.c @@ -890,7 +890,7 @@ int snd_ad1848_create(snd_card_t * card, int err; *rchip = NULL; - chip = kcalloc(1, sizeof(*chip), GFP_KERNEL); + chip = kzalloc(sizeof(*chip), GFP_KERNEL); if (chip == NULL) return -ENOMEM; spin_lock_init(&chip->reg_lock); diff --git a/sound/isa/cmi8330.c b/sound/isa/cmi8330.c index 1fce8b9..5252206 100644 --- a/sound/isa/cmi8330.c +++ b/sound/isa/cmi8330.c @@ -438,33 +438,37 @@ static int __devinit snd_cmi8330_pcm(snd_card_t *card, struct snd_cmi8330 *chip) /* */ +#ifdef CONFIG_PNP +#define is_isapnp_selected(dev) isapnp[dev] +#else +#define is_isapnp_selected(dev) 0 +#endif + +#define PFX "cmi8330: " + static int __devinit snd_cmi8330_probe(int dev, struct pnp_card_link *pcard, const struct pnp_card_device_id *pid) { snd_card_t *card; struct snd_cmi8330 *acard; - unsigned long flags; int i, err; -#ifdef CONFIG_PNP - if (!isapnp[dev]) { -#endif + if (! is_isapnp_selected(dev)) { if (wssport[dev] == SNDRV_AUTO_PORT) { - snd_printk("specify wssport\n"); + snd_printk(KERN_ERR PFX "specify wssport\n"); return -EINVAL; } if (sbport[dev] == SNDRV_AUTO_PORT) { - snd_printk("specify sbport\n"); + snd_printk(KERN_ERR PFX "specify sbport\n"); return -EINVAL; } -#ifdef CONFIG_PNP } -#endif + card = snd_card_new(index[dev], id[dev], THIS_MODULE, sizeof(struct snd_cmi8330)); if (card == NULL) { - snd_printk("could not get a new card\n"); + snd_printk(KERN_ERR PFX "could not get a new card\n"); return -ENOMEM; } acard = (struct snd_cmi8330 *)card->private_data; @@ -473,9 +477,8 @@ static int __devinit snd_cmi8330_probe(int dev, #ifdef CONFIG_PNP if (isapnp[dev]) { if ((err = snd_cmi8330_pnp(dev, acard, pcard, pid)) < 0) { - snd_printk("PnP detection failed\n"); - snd_card_free(card); - return err; + snd_printk(KERN_ERR PFX "PnP detection failed\n"); + goto _err; } snd_card_set_dev(card, &pcard->card->dev); } @@ -487,14 +490,13 @@ static int __devinit snd_cmi8330_probe(int dev, wssdma[dev], AD1848_HW_DETECT, &acard->wss)) < 0) { - snd_printk("(AD1848) device busy??\n"); - snd_card_free(card); - return err; + snd_printk(KERN_ERR PFX "(AD1848) device busy??\n"); + goto _err; } if (acard->wss->hardware != AD1848_HW_CMI8330) { - snd_printk("(AD1848) not found during probe\n"); - snd_card_free(card); - return -ENODEV; + snd_printk(KERN_ERR PFX "(AD1848) not found during probe\n"); + err = -ENODEV; + goto _err; } if ((err = snd_sbdsp_create(card, sbport[dev], @@ -503,32 +505,26 @@ static int __devinit snd_cmi8330_probe(int dev, sbdma8[dev], sbdma16[dev], SB_HW_AUTO, &acard->sb)) < 0) { - snd_printk("(SB16) device busy??\n"); - snd_card_free(card); - return err; + snd_printk(KERN_ERR PFX "(SB16) device busy??\n"); + goto _err; } if (acard->sb->hardware != SB_HW_16) { - snd_printk("(SB16) not found during probe\n"); - snd_card_free(card); - return -ENODEV; + snd_printk(KERN_ERR PFX "(SB16) not found during probe\n"); + goto _err; } - spin_lock_irqsave(&acard->wss->reg_lock, flags); snd_ad1848_out(acard->wss, AD1848_MISC_INFO, 0x40); /* switch on MODE2 */ for (i = CMI8330_RMUX3D; i <= CMI8330_CDINGAIN; i++) snd_ad1848_out(acard->wss, i, snd_cmi8330_image[i - CMI8330_RMUX3D]); - spin_unlock_irqrestore(&acard->wss->reg_lock, flags); if ((err = snd_cmi8330_mixer(card, acard)) < 0) { - snd_printk("failed to create mixers\n"); - snd_card_free(card); - return err; + snd_printk(KERN_ERR PFX "failed to create mixers\n"); + goto _err; } if ((err = snd_cmi8330_pcm(card, acard)) < 0) { - snd_printk("failed to create pcms\n"); - snd_card_free(card); - return err; + snd_printk(KERN_ERR PFX "failed to create pcms\n"); + goto _err; } strcpy(card->driver, "CMI8330/C3D"); @@ -539,16 +535,21 @@ static int __devinit snd_cmi8330_probe(int dev, wssirq[dev], wssdma[dev]); - if ((err = snd_card_register(card)) < 0) { - snd_card_free(card); - return err; - } + if ((err = snd_card_set_generic_dev(card)) < 0) + goto _err; + + if ((err = snd_card_register(card)) < 0) + goto _err; if (pcard) pnp_set_card_drvdata(pcard, card); else snd_cmi8330_legacy[dev] = card; return 0; + + _err: + snd_card_free(card); + return err; } #ifdef CONFIG_PNP @@ -594,10 +595,8 @@ static int __init alsa_card_cmi8330_init(void) for (dev = 0; dev < SNDRV_CARDS; dev++) { if (!enable[dev]) continue; -#ifdef CONFIG_PNP - if (isapnp[dev]) + if (is_isapnp_selected(dev)) continue; -#endif if (snd_cmi8330_probe(dev, NULL, NULL) >= 0) cards++; } diff --git a/sound/isa/cs423x/cs4231.c b/sound/isa/cs423x/cs4231.c index 7640837..9be5416 100644 --- a/sound/isa/cs423x/cs4231.c +++ b/sound/isa/cs423x/cs4231.c @@ -76,15 +76,15 @@ static int __init snd_card_cs4231_probe(int dev) int err; if (port[dev] == SNDRV_AUTO_PORT) { - snd_printk("specify port\n"); + snd_printk(KERN_ERR "specify port\n"); return -EINVAL; } if (irq[dev] == SNDRV_AUTO_IRQ) { - snd_printk("specify irq\n"); + snd_printk(KERN_ERR "specify irq\n"); return -EINVAL; } if (dma1[dev] == SNDRV_AUTO_DMA) { - snd_printk("specify dma1\n"); + snd_printk(KERN_ERR "specify dma1\n"); return -EINVAL; } card = snd_card_new(index[dev], id[dev], THIS_MODULE, 0); @@ -96,15 +96,11 @@ static int __init snd_card_cs4231_probe(int dev) dma1[dev], dma2[dev], CS4231_HW_DETECT, - 0, &chip)) < 0) { - snd_card_free(card); - return err; - } + 0, &chip)) < 0) + goto _err; - if ((err = snd_cs4231_pcm(chip, 0, &pcm)) < 0) { - snd_card_free(card); - return err; - } + if ((err = snd_cs4231_pcm(chip, 0, &pcm)) < 0) + goto _err; strcpy(card->driver, "CS4231"); strcpy(card->shortname, pcm->name); @@ -113,14 +109,10 @@ static int __init snd_card_cs4231_probe(int dev) if (dma2[dev] >= 0) sprintf(card->longname + strlen(card->longname), "&%d", dma2[dev]); - if ((err = snd_cs4231_mixer(chip)) < 0) { - snd_card_free(card); - return err; - } - if ((err = snd_cs4231_timer(chip, 0, NULL)) < 0) { - snd_card_free(card); - return err; - } + if ((err = snd_cs4231_mixer(chip)) < 0) + goto _err; + if ((err = snd_cs4231_timer(chip, 0, NULL)) < 0) + goto _err; if (mpu_port[dev] > 0 && mpu_port[dev] != SNDRV_AUTO_PORT) { if (mpu_irq[dev] == SNDRV_AUTO_IRQ) @@ -130,14 +122,20 @@ static int __init snd_card_cs4231_probe(int dev) mpu_irq[dev], mpu_irq[dev] >= 0 ? SA_INTERRUPT : 0, NULL) < 0) - printk(KERN_ERR "cs4231: MPU401 not detected\n"); - } - if ((err = snd_card_register(card)) < 0) { - snd_card_free(card); - return err; + printk(KERN_WARNING "cs4231: MPU401 not detected\n"); } + + if ((err = snd_card_set_generic_dev(card)) < 0) + goto _err; + + if ((err = snd_card_register(card)) < 0) + goto _err; snd_cs4231_cards[dev] = card; return 0; + + _err: + snd_card_free(card); + return err; } static int __init alsa_card_cs4231_init(void) diff --git a/sound/isa/cs423x/cs4231_lib.c b/sound/isa/cs423x/cs4231_lib.c index 3199941..3231825 100644 --- a/sound/isa/cs423x/cs4231_lib.c +++ b/sound/isa/cs423x/cs4231_lib.c @@ -1480,7 +1480,7 @@ static int snd_cs4231_new(snd_card_t * card, cs4231_t *chip; *rchip = NULL; - chip = kcalloc(1, sizeof(*chip), GFP_KERNEL); + chip = kzalloc(sizeof(*chip), GFP_KERNEL); if (chip == NULL) return -ENOMEM; chip->hardware = hardware; diff --git a/sound/isa/cs423x/cs4236.c b/sound/isa/cs423x/cs4236.c index 39f4eff..d28315d 100644 --- a/sound/isa/cs423x/cs4236.c +++ b/sound/isa/cs423x/cs4236.c @@ -387,6 +387,12 @@ static void snd_card_cs4236_free(snd_card_t *card) } } +#ifdef CONFIG_PNP +#define is_isapnp_selected(dev) isapnp[dev] +#else +#define is_isapnp_selected(dev) 0 +#endif + static int __devinit snd_card_cs423x_probe(int dev, struct pnp_card_link *pcard, const struct pnp_card_device_id *pid) { @@ -397,20 +403,16 @@ static int __devinit snd_card_cs423x_probe(int dev, struct pnp_card_link *pcard, opl3_t *opl3; int err; -#ifdef CONFIG_PNP - if (!isapnp[dev]) { -#endif + if (! is_isapnp_selected(dev)) { if (port[dev] == SNDRV_AUTO_PORT) { - snd_printk("specify port\n"); + snd_printk(KERN_ERR "specify port\n"); return -EINVAL; } if (cport[dev] == SNDRV_AUTO_PORT) { - snd_printk("specify cport\n"); + snd_printk(KERN_ERR "specify cport\n"); return -EINVAL; } -#ifdef CONFIG_PNP } -#endif card = snd_card_new(index[dev], id[dev], THIS_MODULE, sizeof(struct snd_card_cs4236)); if (card == NULL) @@ -421,8 +423,7 @@ static int __devinit snd_card_cs423x_probe(int dev, struct pnp_card_link *pcard, if (isapnp[dev]) { if ((err = snd_card_cs4236_pnp(dev, acard, pcard, pid))<0) { printk(KERN_ERR "isapnp detection failed and probing for " IDENT " is not supported\n"); - snd_card_free(card); - return -ENXIO; + goto _err; } snd_card_set_dev(card, &pcard->card->dev); } @@ -430,8 +431,8 @@ static int __devinit snd_card_cs423x_probe(int dev, struct pnp_card_link *pcard, if (sb_port[dev] > 0 && sb_port[dev] != SNDRV_AUTO_PORT) if ((acard->res_sb_port = request_region(sb_port[dev], 16, IDENT " SB")) == NULL) { printk(KERN_ERR IDENT ": unable to register SB port at 0x%lx\n", sb_port[dev]); - snd_card_free(card); - return -ENOMEM; + err = -EBUSY; + goto _err; } #ifdef CS4232 @@ -443,18 +444,14 @@ static int __devinit snd_card_cs423x_probe(int dev, struct pnp_card_link *pcard, dma2[dev], CS4231_HW_DETECT, 0, - &chip)) < 0) { - snd_card_free(card); - return err; - } - if ((err = snd_cs4231_pcm(chip, 0, &pcm)) < 0) { - snd_card_free(card); - return err; - } - if ((err = snd_cs4231_mixer(chip)) < 0) { - snd_card_free(card); - return err; - } + &chip)) < 0) + goto _err; + + if ((err = snd_cs4231_pcm(chip, 0, &pcm)) < 0) + goto _err; + + if ((err = snd_cs4231_mixer(chip)) < 0) + goto _err; #else /* CS4236 */ if ((err = snd_cs4236_create(card, @@ -465,18 +462,14 @@ static int __devinit snd_card_cs423x_probe(int dev, struct pnp_card_link *pcard, dma2[dev], CS4231_HW_DETECT, 0, - &chip)) < 0) { - snd_card_free(card); - return err; - } - if ((err = snd_cs4236_pcm(chip, 0, &pcm)) < 0) { - snd_card_free(card); - return err; - } - if ((err = snd_cs4236_mixer(chip)) < 0) { - snd_card_free(card); - return err; - } + &chip)) < 0) + goto _err; + + if ((err = snd_cs4236_pcm(chip, 0, &pcm)) < 0) + goto _err; + + if ((err = snd_cs4236_mixer(chip)) < 0) + goto _err; #endif strcpy(card->driver, pcm->name); strcpy(card->shortname, pcm->name); @@ -488,21 +481,17 @@ static int __devinit snd_card_cs423x_probe(int dev, struct pnp_card_link *pcard, if (dma2[dev] >= 0) sprintf(card->longname + strlen(card->longname), "&%d", dma2[dev]); - if ((err = snd_cs4231_timer(chip, 0, NULL)) < 0) { - snd_card_free(card); - return err; - } + if ((err = snd_cs4231_timer(chip, 0, NULL)) < 0) + goto _err; if (fm_port[dev] > 0 && fm_port[dev] != SNDRV_AUTO_PORT) { if (snd_opl3_create(card, fm_port[dev], fm_port[dev] + 2, OPL3_HW_OPL3_CS, 0, &opl3) < 0) { - printk(KERN_ERR IDENT ": OPL3 not detected\n"); + printk(KERN_WARNING IDENT ": OPL3 not detected\n"); } else { - if ((err = snd_opl3_hwdep_new(opl3, 0, 1, NULL)) < 0) { - snd_card_free(card); - return err; - } + if ((err = snd_opl3_hwdep_new(opl3, 0, 1, NULL)) < 0) + goto _err; } } @@ -513,17 +502,23 @@ static int __devinit snd_card_cs423x_probe(int dev, struct pnp_card_link *pcard, mpu_port[dev], 0, mpu_irq[dev], mpu_irq[dev] >= 0 ? SA_INTERRUPT : 0, NULL) < 0) - printk(KERN_ERR IDENT ": MPU401 not detected\n"); - } - if ((err = snd_card_register(card)) < 0) { - snd_card_free(card); - return err; + printk(KERN_WARNING IDENT ": MPU401 not detected\n"); } + + if ((err = snd_card_set_generic_dev(card)) < 0) + goto _err; + + if ((err = snd_card_register(card)) < 0) + goto _err; if (pcard) pnp_set_card_drvdata(pcard, card); else snd_cs4236_legacy[dev] = card; return 0; + + _err: + snd_card_free(card); + return err; } #ifdef CONFIG_PNP @@ -569,10 +564,8 @@ static int __init alsa_card_cs423x_init(void) for (dev = 0; dev < SNDRV_CARDS; dev++) { if (!enable[dev]) continue; -#ifdef CONFIG_PNP - if (isapnp[dev]) + if (is_isapnp_selected(dev)) continue; -#endif if (snd_card_cs423x_probe(dev, NULL, NULL) >= 0) cards++; } diff --git a/sound/isa/es1688/es1688.c b/sound/isa/es1688/es1688.c index c5eaec0..26a7d33 100644 --- a/sound/isa/es1688/es1688.c +++ b/sound/isa/es1688/es1688.c @@ -70,6 +70,7 @@ MODULE_PARM_DESC(dma8, "8-bit DMA # for ESx688 driver."); static snd_card_t *snd_audiodrive_cards[SNDRV_CARDS] = SNDRV_DEFAULT_PTR; +#define PFX "es1688: " static int __init snd_audiodrive_probe(int dev) { @@ -89,47 +90,41 @@ static int __init snd_audiodrive_probe(int dev) xirq = irq[dev]; if (xirq == SNDRV_AUTO_IRQ) { if ((xirq = snd_legacy_find_free_irq(possible_irqs)) < 0) { - snd_card_free(card); - snd_printk("unable to find a free IRQ\n"); - return -EBUSY; + snd_printk(KERN_ERR PFX "unable to find a free IRQ\n"); + err = -EBUSY; + goto _err; } } xmpu_irq = mpu_irq[dev]; xdma = dma8[dev]; if (xdma == SNDRV_AUTO_DMA) { if ((xdma = snd_legacy_find_free_dma(possible_dmas)) < 0) { - snd_card_free(card); - snd_printk("unable to find a free DMA\n"); - return -EBUSY; + snd_printk(KERN_ERR PFX "unable to find a free DMA\n"); + err = -EBUSY; + goto _err; } } if ((err = snd_es1688_create(card, port[dev], mpu_port[dev], xirq, xmpu_irq, xdma, - ES1688_HW_AUTO, &chip)) < 0) { - snd_card_free(card); - return err; - } - if ((err = snd_es1688_pcm(chip, 0, &pcm)) < 0) { - snd_card_free(card); - return err; - } - if ((err = snd_es1688_mixer(chip)) < 0) { - snd_card_free(card); - return err; - } + ES1688_HW_AUTO, &chip)) < 0) + goto _err; + + if ((err = snd_es1688_pcm(chip, 0, &pcm)) < 0) + goto _err; + + if ((err = snd_es1688_mixer(chip)) < 0) + goto _err; strcpy(card->driver, "ES1688"); strcpy(card->shortname, pcm->name); sprintf(card->longname, "%s at 0x%lx, irq %i, dma %i", pcm->name, chip->port, xirq, xdma); if ((snd_opl3_create(card, chip->port, chip->port + 2, OPL3_HW_OPL3, 0, &opl3)) < 0) { - printk(KERN_ERR "es1688: opl3 not detected at 0x%lx\n", chip->port); + printk(KERN_WARNING PFX "opl3 not detected at 0x%lx\n", chip->port); } else { - if ((err = snd_opl3_hwdep_new(opl3, 0, 1, NULL)) < 0) { - snd_card_free(card); - return err; - } + if ((err = snd_opl3_hwdep_new(opl3, 0, 1, NULL)) < 0) + goto _err; } if (xmpu_irq >= 0 && xmpu_irq != SNDRV_AUTO_IRQ && chip->mpu_port > 0) { @@ -137,18 +132,22 @@ static int __init snd_audiodrive_probe(int dev) chip->mpu_port, 0, xmpu_irq, SA_INTERRUPT, - NULL)) < 0) { - snd_card_free(card); - return err; - } - } - if ((err = snd_card_register(card)) < 0) { - snd_card_free(card); - return err; + NULL)) < 0) + goto _err; } + + if ((err = snd_card_set_generic_dev(card)) < 0) + goto _err; + + if ((err = snd_card_register(card)) < 0) + goto _err; + snd_audiodrive_cards[dev] = card; return 0; + _err: + snd_card_free(card); + return err; } static int __init snd_audiodrive_legacy_auto_probe(unsigned long xport) diff --git a/sound/isa/es1688/es1688_lib.c b/sound/isa/es1688/es1688_lib.c index 17f68d0..aac8987 100644 --- a/sound/isa/es1688/es1688_lib.c +++ b/sound/isa/es1688/es1688_lib.c @@ -649,7 +649,7 @@ int snd_es1688_create(snd_card_t * card, int err; *rchip = NULL; - chip = kcalloc(1, sizeof(*chip), GFP_KERNEL); + chip = kzalloc(sizeof(*chip), GFP_KERNEL); if (chip == NULL) return -ENOMEM; chip->irq = -1; diff --git a/sound/isa/es18xx.c b/sound/isa/es18xx.c index 1d832b2..d0ea19f 100644 --- a/sound/isa/es18xx.c +++ b/sound/isa/es18xx.c @@ -1686,7 +1686,7 @@ static int __devinit snd_es18xx_new_device(snd_card_t * card, int err; *rchip = NULL; - chip = kcalloc(1, sizeof(*chip), GFP_KERNEL); + chip = kzalloc(sizeof(*chip), GFP_KERNEL); if (chip == NULL) return -ENOMEM; spin_lock_init(&chip->reg_lock); @@ -1988,6 +1988,12 @@ static int __devinit snd_audiodrive_pnp(int dev, struct snd_audiodrive *acard, } #endif /* CONFIG_PNP */ +#ifdef CONFIG_PNP +#define is_isapnp_selected(dev) isapnp[dev] +#else +#define is_isapnp_selected(dev) 0 +#endif + static int __devinit snd_audiodrive_probe(int dev, struct pnp_card_link *pcard, const struct pnp_card_device_id *pid) { @@ -1996,7 +2002,6 @@ static int __devinit snd_audiodrive_probe(int dev, struct pnp_card_link *pcard, int xirq, xdma1, xdma2; snd_card_t *card; struct snd_audiodrive *acard; - snd_rawmidi_t *rmidi = NULL; es18xx_t *chip; opl3_t *opl3; int err; @@ -2019,25 +2024,25 @@ static int __devinit snd_audiodrive_probe(int dev, struct pnp_card_link *pcard, xirq = irq[dev]; if (xirq == SNDRV_AUTO_IRQ) { if ((xirq = snd_legacy_find_free_irq(possible_irqs)) < 0) { - snd_card_free(card); - snd_printk("unable to find a free IRQ\n"); - return -EBUSY; + snd_printk(KERN_ERR PFX "unable to find a free IRQ\n"); + err = -EBUSY; + goto _err; } } xdma1 = dma1[dev]; if (xdma1 == SNDRV_AUTO_DMA) { if ((xdma1 = snd_legacy_find_free_dma(possible_dmas)) < 0) { - snd_card_free(card); - snd_printk("unable to find a free DMA1\n"); - return -EBUSY; + snd_printk(KERN_ERR PFX "unable to find a free DMA1\n"); + err = -EBUSY; + goto _err; } } xdma2 = dma2[dev]; if (xdma2 == SNDRV_AUTO_DMA) { if ((xdma2 = snd_legacy_find_free_dma(possible_dmas)) < 0) { - snd_card_free(card); - snd_printk("unable to find a free DMA2\n"); - return -EBUSY; + snd_printk(KERN_ERR PFX "unable to find a free DMA2\n"); + err = -EBUSY; + goto _err; } } @@ -2046,10 +2051,8 @@ static int __devinit snd_audiodrive_probe(int dev, struct pnp_card_link *pcard, mpu_port[dev], fm_port[dev], xirq, xdma1, xdma2, - &chip)) < 0) { - snd_card_free(card); - return err; - } + &chip)) < 0) + goto _err; sprintf(card->driver, "ES%x", chip->version); sprintf(card->shortname, "ESS AudioDrive ES%x", chip->version); @@ -2064,23 +2067,18 @@ static int __devinit snd_audiodrive_probe(int dev, struct pnp_card_link *pcard, chip->port, xirq, xdma1); - if ((err = snd_es18xx_pcm(chip, 0, NULL)) < 0) { - snd_card_free(card); - return err; - } - if ((err = snd_es18xx_mixer(chip)) < 0) { - snd_card_free(card); - return err; - } + if ((err = snd_es18xx_pcm(chip, 0, NULL)) < 0) + goto _err; + + if ((err = snd_es18xx_mixer(chip)) < 0) + goto _err; if (fm_port[dev] > 0 && fm_port[dev] != SNDRV_AUTO_PORT) { if (snd_opl3_create(card, chip->fm_port, chip->fm_port + 2, OPL3_HW_OPL3, 0, &opl3) < 0) { - snd_printk(KERN_ERR PFX "opl3 not detected at 0x%lx\n", chip->fm_port); + snd_printk(KERN_WARNING PFX "opl3 not detected at 0x%lx\n", chip->fm_port); } else { - if ((err = snd_opl3_hwdep_new(opl3, 0, 1, NULL)) < 0) { - snd_card_free(card); - return err; - } + if ((err = snd_opl3_hwdep_new(opl3, 0, 1, NULL)) < 0) + goto _err; } } @@ -2088,25 +2086,28 @@ static int __devinit snd_audiodrive_probe(int dev, struct pnp_card_link *pcard, if ((err = snd_mpu401_uart_new(card, 0, MPU401_HW_ES18XX, chip->mpu_port, 0, xirq, 0, - &rmidi)) < 0) { - snd_card_free(card); - return err; - } - chip->rmidi = rmidi; + &chip->rmidi)) < 0) + goto _err; } + if ((err = snd_card_set_generic_dev(card)) < 0) + goto _err; + /* Power Management */ snd_card_set_isa_pm_callback(card, snd_es18xx_suspend, snd_es18xx_resume, chip); - if ((err = snd_card_register(card)) < 0) { - snd_card_free(card); - return err; - } + if ((err = snd_card_register(card)) < 0) + goto _err; + if (pcard) pnp_set_card_drvdata(pcard, card); else snd_audiodrive_legacy[dev] = card; return 0; + + _err: + snd_card_free(card); + return err; } static int __devinit snd_audiodrive_probe_legacy_port(unsigned long xport) @@ -2117,10 +2118,8 @@ static int __devinit snd_audiodrive_probe_legacy_port(unsigned long xport) for ( ; dev < SNDRV_CARDS; dev++) { if (!enable[dev] || port[dev] != SNDRV_AUTO_PORT) continue; -#ifdef CONFIG_PNP - if (isapnp[dev]) + if (is_isapnp_selected(dev)) continue; -#endif port[dev] = xport; res = snd_audiodrive_probe(dev, NULL, NULL); if (res < 0) @@ -2177,10 +2176,8 @@ static int __init alsa_card_es18xx_init(void) for (dev = 0; dev < SNDRV_CARDS; dev++) { if (!enable[dev] || port[dev] == SNDRV_AUTO_PORT) continue; -#ifdef CONFIG_PNP - if (isapnp[dev]) + if (is_isapnp_selected(dev)) continue; -#endif if (snd_audiodrive_probe(dev, NULL, NULL) >= 0) cards++; } diff --git a/sound/isa/gus/gus_main.c b/sound/isa/gus/gus_main.c index a636d9c..8f2872f 100644 --- a/sound/isa/gus/gus_main.c +++ b/sound/isa/gus/gus_main.c @@ -157,7 +157,7 @@ int snd_gus_create(snd_card_t * card, }; *rgus = NULL; - gus = kcalloc(1, sizeof(*gus), GFP_KERNEL); + gus = kzalloc(sizeof(*gus), GFP_KERNEL); if (gus == NULL) return -ENOMEM; gus->gf1.irq = -1; diff --git a/sound/isa/gus/gus_mem_proc.c b/sound/isa/gus/gus_mem_proc.c index 886763f..7f96ac2 100644 --- a/sound/isa/gus/gus_mem_proc.c +++ b/sound/isa/gus/gus_mem_proc.c @@ -98,7 +98,7 @@ int snd_gf1_mem_proc_init(snd_gus_card_t * gus) for (idx = 0; idx < 4; idx++) { if (gus->gf1.mem_alloc.banks_8[idx].size > 0) { - priv = kcalloc(1, sizeof(*priv), GFP_KERNEL); + priv = kzalloc(sizeof(*priv), GFP_KERNEL); if (priv == NULL) return -ENOMEM; priv->gus = gus; @@ -115,7 +115,7 @@ int snd_gf1_mem_proc_init(snd_gus_card_t * gus) } for (idx = 0; idx < 4; idx++) { if (gus->gf1.rom_present & (1 << idx)) { - priv = kcalloc(1, sizeof(*priv), GFP_KERNEL); + priv = kzalloc(sizeof(*priv), GFP_KERNEL); if (priv == NULL) return -ENOMEM; priv->rom = 1; diff --git a/sound/isa/gus/gus_pcm.c b/sound/isa/gus/gus_pcm.c index b75066a..beb0136 100644 --- a/sound/isa/gus/gus_pcm.c +++ b/sound/isa/gus/gus_pcm.c @@ -666,7 +666,7 @@ static int snd_gf1_pcm_playback_open(snd_pcm_substream_t *substream) snd_pcm_runtime_t *runtime = substream->runtime; int err; - pcmp = kcalloc(1, sizeof(*pcmp), GFP_KERNEL); + pcmp = kzalloc(sizeof(*pcmp), GFP_KERNEL); if (pcmp == NULL) return -ENOMEM; pcmp->gus = gus; diff --git a/sound/isa/gus/gusclassic.c b/sound/isa/gus/gusclassic.c index a99fa50..39cef38 100644 --- a/sound/isa/gus/gusclassic.c +++ b/sound/isa/gus/gusclassic.c @@ -72,40 +72,24 @@ MODULE_PARM_DESC(pcm_channels, "Reserved PCM channels for GUS Classic driver."); static snd_card_t *snd_gusclassic_cards[SNDRV_CARDS] = SNDRV_DEFAULT_PTR; +#define PFX "gusclassic: " static int __init snd_gusclassic_detect(snd_gus_card_t * gus) { - snd_gf1_i_write8(gus, SNDRV_GF1_GB_RESET, 0); /* reset GF1 */ -#ifdef CONFIG_SND_DEBUG_DETECT - { - unsigned char d; + unsigned char d; - if (((d = snd_gf1_i_look8(gus, SNDRV_GF1_GB_RESET)) & 0x07) != 0) { - snd_printk("[0x%lx] check 1 failed - 0x%x\n", gus->gf1.port, d); - return -ENODEV; - } - } -#else - if ((snd_gf1_i_look8(gus, SNDRV_GF1_GB_RESET) & 0x07) != 0) + snd_gf1_i_write8(gus, SNDRV_GF1_GB_RESET, 0); /* reset GF1 */ + if (((d = snd_gf1_i_look8(gus, SNDRV_GF1_GB_RESET)) & 0x07) != 0) { + snd_printdd("[0x%lx] check 1 failed - 0x%x\n", gus->gf1.port, d); return -ENODEV; -#endif + } udelay(160); snd_gf1_i_write8(gus, SNDRV_GF1_GB_RESET, 1); /* release reset */ udelay(160); -#ifdef CONFIG_SND_DEBUG_DETECT - { - unsigned char d; - - if (((d = snd_gf1_i_look8(gus, SNDRV_GF1_GB_RESET)) & 0x07) != 1) { - snd_printk("[0x%lx] check 2 failed - 0x%x\n", gus->gf1.port, d); - return -ENODEV; - } - } -#else - if ((snd_gf1_i_look8(gus, SNDRV_GF1_GB_RESET) & 0x07) != 1) + if (((d = snd_gf1_i_look8(gus, SNDRV_GF1_GB_RESET)) & 0x07) != 1) { + snd_printdd("[0x%lx] check 2 failed - 0x%x\n", gus->gf1.port, d); return -ENODEV; -#endif - + } return 0; } @@ -137,25 +121,25 @@ static int __init snd_gusclassic_probe(int dev) xirq = irq[dev]; if (xirq == SNDRV_AUTO_IRQ) { if ((xirq = snd_legacy_find_free_irq(possible_irqs)) < 0) { - snd_card_free(card); - snd_printk("unable to find a free IRQ\n"); - return -EBUSY; + snd_printk(KERN_ERR PFX "unable to find a free IRQ\n"); + err = -EBUSY; + goto _err; } } xdma1 = dma1[dev]; if (xdma1 == SNDRV_AUTO_DMA) { if ((xdma1 = snd_legacy_find_free_dma(possible_dmas)) < 0) { - snd_card_free(card); - snd_printk("unable to find a free DMA1\n"); - return -EBUSY; + snd_printk(KERN_ERR PFX "unable to find a free DMA1\n"); + err = -EBUSY; + goto _err; } } xdma2 = dma2[dev]; if (xdma2 == SNDRV_AUTO_DMA) { if ((xdma2 = snd_legacy_find_free_dma(possible_dmas)) < 0) { - snd_card_free(card); - snd_printk("unable to find a free DMA2\n"); - return -EBUSY; + snd_printk(KERN_ERR PFX "unable to find a free DMA2\n"); + err = -EBUSY; + goto _err; } } @@ -164,47 +148,48 @@ static int __init snd_gusclassic_probe(int dev) port[dev], xirq, xdma1, xdma2, 0, channels[dev], pcm_channels[dev], - 0, &gus)) < 0) { - snd_card_free(card); - return err; - } - if ((err = snd_gusclassic_detect(gus)) < 0) { - snd_card_free(card); - return err; - } + 0, &gus)) < 0) + goto _err; + + if ((err = snd_gusclassic_detect(gus)) < 0) + goto _err; + snd_gusclassic_init(dev, gus); - if ((err = snd_gus_initialize(gus)) < 0) { - snd_card_free(card); - return err; - } + if ((err = snd_gus_initialize(gus)) < 0) + goto _err; + if (gus->max_flag || gus->ess_flag) { - snd_printdd("GUS Classic or ACE soundcard was not detected at 0x%lx\n", gus->gf1.port); - snd_card_free(card); - return -ENODEV; - } - if ((err = snd_gf1_new_mixer(gus)) < 0) { - snd_card_free(card); - return err; - } - if ((err = snd_gf1_pcm_new(gus, 0, 0, NULL)) < 0) { - snd_card_free(card); - return err; + snd_printk(KERN_ERR PFX "GUS Classic or ACE soundcard was not detected at 0x%lx\n", gus->gf1.port); + err = -ENODEV; + goto _err; } + + if ((err = snd_gf1_new_mixer(gus)) < 0) + goto _err; + + if ((err = snd_gf1_pcm_new(gus, 0, 0, NULL)) < 0) + goto _err; + if (!gus->ace_flag) { - if ((err = snd_gf1_rawmidi_new(gus, 0, NULL)) < 0) { - snd_card_free(card); - return err; - } + if ((err = snd_gf1_rawmidi_new(gus, 0, NULL)) < 0) + goto _err; } sprintf(card->longname + strlen(card->longname), " at 0x%lx, irq %d, dma %d", gus->gf1.port, xirq, xdma1); if (dma2 >= 0) sprintf(card->longname + strlen(card->longname), "&%d", xdma2); - if ((err = snd_card_register(card)) < 0) { - snd_card_free(card); - return err; - } + + if ((err = snd_card_set_generic_dev(card)) < 0) + goto _err; + + if ((err = snd_card_register(card)) < 0) + goto _err; + snd_gusclassic_cards[dev] = card; return 0; + + _err: + snd_card_free(card); + return err; } static int __init snd_gusclassic_legacy_auto_probe(unsigned long xport) diff --git a/sound/isa/gus/gusextreme.c b/sound/isa/gus/gusextreme.c index bc6fecb..d2e7cb1 100644 --- a/sound/isa/gus/gusextreme.c +++ b/sound/isa/gus/gusextreme.c @@ -87,6 +87,7 @@ MODULE_PARM_DESC(pcm_channels, "Reserved PCM channels for GUS Extreme driver."); static snd_card_t *snd_gusextreme_cards[SNDRV_CARDS] = SNDRV_DEFAULT_PTR; +#define PFX "gusextreme: " static int __init snd_gusextreme_detect(int dev, snd_card_t * card, @@ -94,6 +95,7 @@ static int __init snd_gusextreme_detect(int dev, es1688_t *es1688) { unsigned long flags; + unsigned char d; /* * This is main stuff - enable access to GF1 chip... @@ -123,36 +125,17 @@ static int __init snd_gusextreme_detect(int dev, udelay(100); snd_gf1_i_write8(gus, SNDRV_GF1_GB_RESET, 0); /* reset GF1 */ -#ifdef CONFIG_SND_DEBUG_DETECT - { - unsigned char d; - - if (((d = snd_gf1_i_look8(gus, SNDRV_GF1_GB_RESET)) & 0x07) != 0) { - snd_printk("[0x%lx] check 1 failed - 0x%x\n", gus->gf1.port, d); - return -EIO; - } - } -#else - if ((snd_gf1_i_look8(gus, SNDRV_GF1_GB_RESET) & 0x07) != 0) + if (((d = snd_gf1_i_look8(gus, SNDRV_GF1_GB_RESET)) & 0x07) != 0) { + snd_printdd("[0x%lx] check 1 failed - 0x%x\n", gus->gf1.port, d); return -EIO; -#endif + } udelay(160); snd_gf1_i_write8(gus, SNDRV_GF1_GB_RESET, 1); /* release reset */ udelay(160); -#ifdef CONFIG_SND_DEBUG_DETECT - { - unsigned char d; - - if (((d = snd_gf1_i_look8(gus, SNDRV_GF1_GB_RESET)) & 0x07) != 1) { - snd_printk("[0x%lx] check 2 failed - 0x%x\n", gus->gf1.port, d); - return -EIO; - } - } -#else - if ((snd_gf1_i_look8(gus, SNDRV_GF1_GB_RESET) & 0x07) != 1) + if (((d = snd_gf1_i_look8(gus, SNDRV_GF1_GB_RESET)) & 0x07) != 1) { + snd_printdd("[0x%lx] check 2 failed - 0x%x\n", gus->gf1.port, d); return -EIO; -#endif - + } return 0; } @@ -205,7 +188,7 @@ static int __init snd_gusextreme_probe(int dev) xgf1_irq = gf1_irq[dev]; if (xgf1_irq == SNDRV_AUTO_IRQ) { if ((xgf1_irq = snd_legacy_find_free_irq(possible_gf1_irqs)) < 0) { - snd_printk("unable to find a free IRQ for GF1\n"); + snd_printk(KERN_ERR PFX "unable to find a free IRQ for GF1\n"); err = -EBUSY; goto out; } @@ -213,7 +196,7 @@ static int __init snd_gusextreme_probe(int dev) xess_irq = irq[dev]; if (xess_irq == SNDRV_AUTO_IRQ) { if ((xess_irq = snd_legacy_find_free_irq(possible_ess_irqs)) < 0) { - snd_printk("unable to find a free IRQ for ES1688\n"); + snd_printk(KERN_ERR PFX "unable to find a free IRQ for ES1688\n"); err = -EBUSY; goto out; } @@ -226,7 +209,7 @@ static int __init snd_gusextreme_probe(int dev) xgf1_dma = dma1[dev]; if (xgf1_dma == SNDRV_AUTO_DMA) { if ((xgf1_dma = snd_legacy_find_free_dma(possible_gf1_dmas)) < 0) { - snd_printk("unable to find a free DMA for GF1\n"); + snd_printk(KERN_ERR PFX "unable to find a free DMA for GF1\n"); err = -EBUSY; goto out; } @@ -234,7 +217,7 @@ static int __init snd_gusextreme_probe(int dev) xess_dma = dma8[dev]; if (xess_dma == SNDRV_AUTO_DMA) { if ((xess_dma = snd_legacy_find_free_dma(possible_ess_dmas)) < 0) { - snd_printk("unable to find a free DMA for ES1688\n"); + snd_printk(KERN_ERR PFX "unable to find a free DMA for ES1688\n"); err = -EBUSY; goto out; } @@ -264,7 +247,7 @@ static int __init snd_gusextreme_probe(int dev) goto out; if (!gus->ess_flag) { - snd_printdd("GUS Extreme soundcard was not detected at 0x%lx\n", gus->gf1.port); + snd_printk(KERN_ERR PFX "GUS Extreme soundcard was not detected at 0x%lx\n", gus->gf1.port); err = -ENODEV; goto out; } @@ -287,7 +270,7 @@ static int __init snd_gusextreme_probe(int dev) if (snd_opl3_create(card, es1688->port, es1688->port + 2, OPL3_HW_OPL3, 0, &opl3) < 0) { - printk(KERN_ERR "gusextreme: opl3 not detected at 0x%lx\n", es1688->port); + printk(KERN_ERR PFX "gusextreme: opl3 not detected at 0x%lx\n", es1688->port); } else { if ((err = snd_opl3_hwdep_new(opl3, 0, 2, NULL)) < 0) goto out; @@ -303,6 +286,10 @@ static int __init snd_gusextreme_probe(int dev) sprintf(card->longname, "Gravis UltraSound Extreme at 0x%lx, irq %i&%i, dma %i&%i", es1688->port, xgf1_irq, xess_irq, xgf1_dma, xess_dma); + + if ((err = snd_card_set_generic_dev(card)) < 0) + goto out; + if ((err = snd_card_register(card)) < 0) goto out; diff --git a/sound/isa/gus/gusmax.c b/sound/isa/gus/gusmax.c index 400ff34..0bb44b5 100644 --- a/sound/isa/gus/gusmax.c +++ b/sound/isa/gus/gusmax.c @@ -82,39 +82,25 @@ struct snd_gusmax { static snd_card_t *snd_gusmax_cards[SNDRV_CARDS] = SNDRV_DEFAULT_PTR; +#define PFX "gusmax: " static int __init snd_gusmax_detect(snd_gus_card_t * gus) { - snd_gf1_i_write8(gus, SNDRV_GF1_GB_RESET, 0); /* reset GF1 */ -#ifdef CONFIG_SND_DEBUG_DETECT - { - unsigned char d; + unsigned char d; - if (((d = snd_gf1_i_look8(gus, SNDRV_GF1_GB_RESET)) & 0x07) != 0) { - snd_printk("[0x%lx] check 1 failed - 0x%x\n", gus->gf1.port, d); - return -ENODEV; - } - } -#else - if ((snd_gf1_i_look8(gus, SNDRV_GF1_GB_RESET) & 0x07) != 0) + snd_gf1_i_write8(gus, SNDRV_GF1_GB_RESET, 0); /* reset GF1 */ + if (((d = snd_gf1_i_look8(gus, SNDRV_GF1_GB_RESET)) & 0x07) != 0) { + snd_printdd("[0x%lx] check 1 failed - 0x%x\n", gus->gf1.port, d); return -ENODEV; -#endif + } udelay(160); snd_gf1_i_write8(gus, SNDRV_GF1_GB_RESET, 1); /* release reset */ udelay(160); -#ifdef CONFIG_SND_DEBUG_DETECT - { - unsigned char d; - - if (((d = snd_gf1_i_look8(gus, SNDRV_GF1_GB_RESET)) & 0x07) != 1) { - snd_printk("[0x%lx] check 2 failed - 0x%x\n", gus->gf1.port, d); - return -ENODEV; - } - } -#else - if ((snd_gf1_i_look8(gus, SNDRV_GF1_GB_RESET) & 0x07) != 1) + if (((d = snd_gf1_i_look8(gus, SNDRV_GF1_GB_RESET)) & 0x07) != 1) { + snd_printdd("[0x%lx] check 2 failed - 0x%x\n", gus->gf1.port, d); return -ENODEV; -#endif + } + return 0; } @@ -239,25 +225,25 @@ static int __init snd_gusmax_probe(int dev) xirq = irq[dev]; if (xirq == SNDRV_AUTO_IRQ) { if ((xirq = snd_legacy_find_free_irq(possible_irqs)) < 0) { - snd_card_free(card); - snd_printk("unable to find a free IRQ\n"); - return -EBUSY; + snd_printk(KERN_ERR PFX "unable to find a free IRQ\n"); + err = -EBUSY; + goto _err; } } xdma1 = dma1[dev]; if (xdma1 == SNDRV_AUTO_DMA) { if ((xdma1 = snd_legacy_find_free_dma(possible_dmas)) < 0) { - snd_card_free(card); - snd_printk("unable to find a free DMA1\n"); - return -EBUSY; + snd_printk(KERN_ERR PFX "unable to find a free DMA1\n"); + err = -EBUSY; + goto _err; } } xdma2 = dma2[dev]; if (xdma2 == SNDRV_AUTO_DMA) { if ((xdma2 = snd_legacy_find_free_dma(possible_dmas)) < 0) { - snd_card_free(card); - snd_printk("unable to find a free DMA2\n"); - return -EBUSY; + snd_printk(KERN_ERR PFX "unable to find a free DMA2\n"); + err = -EBUSY; + goto _err; } } @@ -266,31 +252,28 @@ static int __init snd_gusmax_probe(int dev) -xirq, xdma1, xdma2, 0, channels[dev], pcm_channels[dev], - 0, &gus)) < 0) { - snd_card_free(card); - return err; - } - if ((err = snd_gusmax_detect(gus)) < 0) { - snd_card_free(card); - return err; - } + 0, &gus)) < 0) + goto _err; + + if ((err = snd_gusmax_detect(gus)) < 0) + goto _err; + maxcard->gus_status_reg = gus->gf1.reg_irqstat; maxcard->pcm_status_reg = gus->gf1.port + 0x10c + 2; snd_gusmax_init(dev, card, gus); - if ((err = snd_gus_initialize(gus)) < 0) { - snd_card_free(card); - return err; - } + if ((err = snd_gus_initialize(gus)) < 0) + goto _err; + if (!gus->max_flag) { - printk(KERN_ERR "GUS MAX soundcard was not detected at 0x%lx\n", gus->gf1.port); - snd_card_free(card); - return -ENODEV; + snd_printk(KERN_ERR PFX "GUS MAX soundcard was not detected at 0x%lx\n", gus->gf1.port); + err = -ENODEV; + goto _err; } if (request_irq(xirq, snd_gusmax_interrupt, SA_INTERRUPT, "GUS MAX", (void *)maxcard)) { - snd_card_free(card); - printk(KERN_ERR "gusmax: unable to grab IRQ %d\n", xirq); - return -EBUSY; + snd_printk(KERN_ERR PFX "unable to grab IRQ %d\n", xirq); + err = -EBUSY; + goto _err; } maxcard->irq = xirq; @@ -301,50 +284,46 @@ static int __init snd_gusmax_probe(int dev) CS4231_HWSHARE_IRQ | CS4231_HWSHARE_DMA1 | CS4231_HWSHARE_DMA2, - &cs4231)) < 0) { - snd_card_free(card); - return err; - } - if ((err = snd_cs4231_pcm(cs4231, 0, NULL)) < 0) { - snd_card_free(card); - return err; - } - if ((err = snd_cs4231_mixer(cs4231)) < 0) { - snd_card_free(card); - return err; - } - if ((err = snd_cs4231_timer(cs4231, 2, NULL)) < 0) { - snd_card_free(card); - return err; - } + &cs4231)) < 0) + goto _err; + + if ((err = snd_cs4231_pcm(cs4231, 0, NULL)) < 0) + goto _err; + + if ((err = snd_cs4231_mixer(cs4231)) < 0) + goto _err; + + if ((err = snd_cs4231_timer(cs4231, 2, NULL)) < 0) + goto _err; + if (pcm_channels[dev] > 0) { - if ((err = snd_gf1_pcm_new(gus, 1, 1, NULL)) < 0) { - snd_card_free(card); - return err; - } - } - if ((err = snd_gusmax_mixer(cs4231)) < 0) { - snd_card_free(card); - return err; + if ((err = snd_gf1_pcm_new(gus, 1, 1, NULL)) < 0) + goto _err; } + if ((err = snd_gusmax_mixer(cs4231)) < 0) + goto _err; - if ((err = snd_gf1_rawmidi_new(gus, 0, NULL)) < 0) { - snd_card_free(card); - return err; - } + if ((err = snd_gf1_rawmidi_new(gus, 0, NULL)) < 0) + goto _err; sprintf(card->longname + strlen(card->longname), " at 0x%lx, irq %i, dma %i", gus->gf1.port, xirq, xdma1); if (xdma2 >= 0) sprintf(card->longname + strlen(card->longname), "&%i", xdma2); - if ((err = snd_card_register(card)) < 0) { - snd_card_free(card); - return err; - } + + if ((err = snd_card_set_generic_dev(card)) < 0) + goto _err; + + if ((err = snd_card_register(card)) < 0) + goto _err; maxcard->gus = gus; maxcard->cs4231 = cs4231; snd_gusmax_cards[dev] = card; return 0; + + _err: + snd_card_free(card); + return err; } static int __init snd_gusmax_legacy_auto_probe(unsigned long xport) diff --git a/sound/isa/gus/interwave.c b/sound/isa/gus/interwave.c index 46e867d..358cba9 100644 --- a/sound/isa/gus/interwave.c +++ b/sound/isa/gus/interwave.c @@ -73,6 +73,12 @@ static int midi[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 0}; static int pcm_channels[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 2}; static int effect[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 0}; +#ifdef SNDRV_STB +#define PFX "interwave-stb: " +#else +#define PFX "interwave: " +#endif + module_param_array(index, int, NULL, 0444); MODULE_PARM_DESC(index, "Index value for InterWave soundcard."); module_param_array(id, charp, NULL, 0444); @@ -249,38 +255,20 @@ static int __devinit snd_interwave_detect(struct snd_interwave *iwcard, { unsigned long flags; unsigned char rev1, rev2; + int d; snd_gf1_i_write8(gus, SNDRV_GF1_GB_RESET, 0); /* reset GF1 */ -#ifdef CONFIG_SND_DEBUG_DETECT - { - int d; - - if (((d = snd_gf1_i_look8(gus, SNDRV_GF1_GB_RESET)) & 0x07) != 0) { - snd_printk("[0x%lx] check 1 failed - 0x%x\n", gus->gf1.port, d); - return -ENODEV; - } - } -#else - if ((snd_gf1_i_look8(gus, SNDRV_GF1_GB_RESET) & 0x07) != 0) + if (((d = snd_gf1_i_look8(gus, SNDRV_GF1_GB_RESET)) & 0x07) != 0) { + snd_printdd("[0x%lx] check 1 failed - 0x%x\n", gus->gf1.port, d); return -ENODEV; -#endif + } udelay(160); snd_gf1_i_write8(gus, SNDRV_GF1_GB_RESET, 1); /* release reset */ udelay(160); -#ifdef CONFIG_SND_DEBUG_DETECT - { - int d; - - if (((d = snd_gf1_i_look8(gus, SNDRV_GF1_GB_RESET)) & 0x07) != 1) { - snd_printk("[0x%lx] check 2 failed - 0x%x\n", gus->gf1.port, d); - return -ENODEV; - } - } -#else - if ((snd_gf1_i_look8(gus, SNDRV_GF1_GB_RESET) & 0x07) != 1) + if (((d = snd_gf1_i_look8(gus, SNDRV_GF1_GB_RESET)) & 0x07) != 1) { + snd_printdd("[0x%lx] check 2 failed - 0x%x\n", gus->gf1.port, d); return -ENODEV; -#endif - + } spin_lock_irqsave(&gus->reg_lock, flags); rev1 = snd_gf1_look8(gus, SNDRV_GF1_GB_VERSION_NUMBER); snd_gf1_write8(gus, SNDRV_GF1_GB_VERSION_NUMBER, ~rev1); @@ -686,35 +674,33 @@ static int __devinit snd_interwave_probe(int dev, struct pnp_card_link *pcard, card->private_free = snd_interwave_free; #ifdef CONFIG_PNP if (isapnp[dev]) { - if (snd_interwave_pnp(dev, iwcard, pcard, pid)) { - snd_card_free(card); - return -ENODEV; - } + if ((err = snd_interwave_pnp(dev, iwcard, pcard, pid)) < 0) + goto _err; snd_card_set_dev(card, &pcard->card->dev); } #endif xirq = irq[dev]; if (xirq == SNDRV_AUTO_IRQ) { if ((xirq = snd_legacy_find_free_irq(possible_irqs)) < 0) { - snd_card_free(card); - snd_printk("unable to find a free IRQ\n"); - return -EBUSY; + snd_printk(KERN_ERR PFX "unable to find a free IRQ\n"); + err = -EBUSY; + goto _err; } } xdma1 = dma1[dev]; if (xdma1 == SNDRV_AUTO_DMA) { if ((xdma1 = snd_legacy_find_free_dma(possible_dmas)) < 0) { - snd_card_free(card); - snd_printk("unable to find a free DMA1\n"); - return -EBUSY; + snd_printk(KERN_ERR PFX "unable to find a free DMA1\n"); + err = -EBUSY; + goto _err; } } xdma2 = dma2[dev]; if (xdma2 == SNDRV_AUTO_DMA) { if ((xdma2 = snd_legacy_find_free_dma(possible_dmas)) < 0) { - snd_card_free(card); - snd_printk("unable to find a free DMA2\n"); - return -EBUSY; + snd_printk(KERN_ERR PFX "unable to find a free DMA2\n"); + err = -EBUSY; + goto _err; } } @@ -722,32 +708,28 @@ static int __devinit snd_interwave_probe(int dev, struct pnp_card_link *pcard, port[dev], -xirq, xdma1, xdma2, 0, 32, - pcm_channels[dev], effect[dev], &gus)) < 0) { - snd_card_free(card); - return err; - } + pcm_channels[dev], effect[dev], &gus)) < 0) + goto _err; + if ((err = snd_interwave_detect(iwcard, gus, dev #ifdef SNDRV_STB , &i2c_bus #endif - )) < 0) { - snd_card_free(card); - return err; - } + )) < 0) + goto _err; + iwcard->gus_status_reg = gus->gf1.reg_irqstat; iwcard->pcm_status_reg = gus->gf1.port + 0x10c + 2; snd_interwave_init(dev, gus); snd_interwave_detect_memory(gus); - if ((err = snd_gus_initialize(gus)) < 0) { - snd_card_free(card); - return err; - } + if ((err = snd_gus_initialize(gus)) < 0) + goto _err; if (request_irq(xirq, snd_interwave_interrupt, SA_INTERRUPT, "InterWave", (void *)iwcard)) { - snd_card_free(card); - snd_printk("unable to grab IRQ %d\n", xirq); - return -EBUSY; + snd_printk(KERN_ERR PFX "unable to grab IRQ %d\n", xirq); + err = -EBUSY; + goto _err; } iwcard->irq = xirq; @@ -758,34 +740,28 @@ static int __devinit snd_interwave_probe(int dev, struct pnp_card_link *pcard, CS4231_HWSHARE_IRQ | CS4231_HWSHARE_DMA1 | CS4231_HWSHARE_DMA2, - &cs4231)) < 0) { - snd_card_free(card); - return err; - } - if ((err = snd_cs4231_pcm(cs4231, 0, &pcm)) < 0) { - snd_card_free(card); - return err; - } + &cs4231)) < 0) + goto _err; + + if ((err = snd_cs4231_pcm(cs4231, 0, &pcm)) < 0) + goto _err; + sprintf(pcm->name + strlen(pcm->name), " rev %c", gus->revision + 'A'); strcat(pcm->name, " (codec)"); - if ((err = snd_cs4231_timer(cs4231, 2, NULL)) < 0) { - snd_card_free(card); - return err; - } - if ((err = snd_cs4231_mixer(cs4231)) < 0) { - snd_card_free(card); - return err; - } + + if ((err = snd_cs4231_timer(cs4231, 2, NULL)) < 0) + goto _err; + + if ((err = snd_cs4231_mixer(cs4231)) < 0) + goto _err; + if (pcm_channels[dev] > 0) { - if ((err = snd_gf1_pcm_new(gus, 1, 1, NULL)) < 0) { - snd_card_free(card); - return err; - } - } - if ((err = snd_interwave_mixer(cs4231)) < 0) { - snd_card_free(card); - return err; + if ((err = snd_gf1_pcm_new(gus, 1, 1, NULL)) < 0) + goto _err; } + if ((err = snd_interwave_mixer(cs4231)) < 0) + goto _err; + #ifdef SNDRV_STB { snd_ctl_elem_id_t id1, id2; @@ -795,28 +771,20 @@ static int __devinit snd_interwave_probe(int dev, struct pnp_card_link *pcard, strcpy(id1.name, "Master Playback Switch"); strcpy(id2.name, id1.name); id2.index = 1; - if ((err = snd_ctl_rename_id(card, &id1, &id2)) < 0) { - snd_card_free(card); - return err; - } + if ((err = snd_ctl_rename_id(card, &id1, &id2)) < 0) + goto _err; strcpy(id1.name, "Master Playback Volume"); strcpy(id2.name, id1.name); - if ((err = snd_ctl_rename_id(card, &id1, &id2)) < 0) { - snd_card_free(card); - return err; - } - if ((err = snd_tea6330t_update_mixer(card, i2c_bus, 0, 1)) < 0) { - snd_card_free(card); - return err; - } + if ((err = snd_ctl_rename_id(card, &id1, &id2)) < 0) + goto _err; + if ((err = snd_tea6330t_update_mixer(card, i2c_bus, 0, 1)) < 0) + goto _err; } #endif gus->uart_enable = midi[dev]; - if ((err = snd_gf1_rawmidi_new(gus, 0, NULL)) < 0) { - snd_card_free(card); - return err; - } + if ((err = snd_gf1_rawmidi_new(gus, 0, NULL)) < 0) + goto _err; #ifndef SNDRV_STB str = "AMD InterWave"; @@ -835,10 +803,11 @@ static int __devinit snd_interwave_probe(int dev, struct pnp_card_link *pcard, if (xdma2 >= 0) sprintf(card->longname + strlen(card->longname), "&%d", xdma2); - if ((err = snd_card_register(card)) < 0) { - snd_card_free(card); - return err; - } + if ((err = snd_card_set_generic_dev(card)) < 0) + goto _err; + + if ((err = snd_card_register(card)) < 0) + goto _err; iwcard->cs4231 = cs4231; iwcard->gus = gus; @@ -847,6 +816,10 @@ static int __devinit snd_interwave_probe(int dev, struct pnp_card_link *pcard, else snd_interwave_legacy[dev++] = card; return 0; + + _err: + snd_card_free(card); + return err; } static int __devinit snd_interwave_probe_legacy_port(unsigned long xport) diff --git a/sound/isa/opl3sa2.c b/sound/isa/opl3sa2.c index 75bd6ec..e2d2bab 100644 --- a/sound/isa/opl3sa2.c +++ b/sound/isa/opl3sa2.c @@ -143,6 +143,8 @@ struct snd_opl3sa2 { static snd_card_t *snd_opl3sa2_legacy[SNDRV_CARDS] = SNDRV_DEFAULT_PTR; +#define PFX "opl3sa2: " + #ifdef CONFIG_PNP static struct pnp_device_id snd_opl3sa2_pnpbiosids[] = { @@ -231,7 +233,7 @@ static int __init snd_opl3sa2_detect(opl3sa2_t *chip) card = chip->card; port = chip->port; if ((chip->res_port = request_region(port, 2, "OPL3-SA control")) == NULL) { - snd_printk(KERN_ERR "opl3sa2: can't grab port 0x%lx\n", port); + snd_printk(KERN_ERR PFX "can't grab port 0x%lx\n", port); return -EBUSY; } // snd_printk("REG 0A = 0x%x\n", snd_opl3sa2_read(chip, 0x0a)); @@ -668,6 +670,12 @@ static int snd_opl3sa2_dev_free(snd_device_t *device) return snd_opl3sa2_free(chip); } +#ifdef CONFIG_PNP +#define is_isapnp_selected(dev) isapnp[dev] +#else +#define is_isapnp_selected(dev) 0 +#endif + static int __devinit snd_opl3sa2_probe(int dev, struct pnp_dev *pdev, struct pnp_card_link *pcard, @@ -683,34 +691,31 @@ static int __devinit snd_opl3sa2_probe(int dev, }; int err; -#ifdef CONFIG_PNP - if (!isapnp[dev]) { -#endif + if (! is_isapnp_selected(dev)) { if (port[dev] == SNDRV_AUTO_PORT) { - snd_printk("specify port\n"); + snd_printk(KERN_ERR PFX "specify port\n"); return -EINVAL; } if (wss_port[dev] == SNDRV_AUTO_PORT) { - snd_printk("specify wss_port\n"); + snd_printk(KERN_ERR PFX "specify wss_port\n"); return -EINVAL; } if (fm_port[dev] == SNDRV_AUTO_PORT) { - snd_printk("specify fm_port\n"); + snd_printk(KERN_ERR PFX "specify fm_port\n"); return -EINVAL; } if (midi_port[dev] == SNDRV_AUTO_PORT) { - snd_printk("specify midi_port\n"); + snd_printk(KERN_ERR PFX "specify midi_port\n"); return -EINVAL; } -#ifdef CONFIG_PNP } -#endif + card = snd_card_new(index[dev], id[dev], THIS_MODULE, 0); if (card == NULL) return -ENOMEM; strcpy(card->driver, "OPL3SA2"); strcpy(card->shortname, "Yamaha OPL3-SA2"); - chip = kcalloc(1, sizeof(*chip), GFP_KERNEL); + chip = kzalloc(sizeof(*chip), GFP_KERNEL); if (chip == NULL) { err = -ENOMEM; goto __error; @@ -742,7 +747,7 @@ static int __devinit snd_opl3sa2_probe(int dev, if ((err = snd_opl3sa2_detect(chip)) < 0) goto __error; if (request_irq(xirq, snd_opl3sa2_interrupt, SA_INTERRUPT, "OPL3-SA2", (void *)chip)) { - snd_printk(KERN_ERR "opl3sa2: can't grab IRQ %d\n", xirq); + snd_printk(KERN_ERR PFX "can't grab IRQ %d\n", xirq); err = -ENODEV; goto __error; } @@ -795,6 +800,9 @@ static int __devinit snd_opl3sa2_probe(int dev, if (dma2 >= 0) sprintf(card->longname + strlen(card->longname), "&%d", xdma2); + if ((err = snd_card_set_generic_dev(card)) < 0) + goto __error; + if ((err = snd_card_register(card)) < 0) goto __error; @@ -852,8 +860,10 @@ static int __devinit snd_opl3sa2_pnp_cdetect(struct pnp_card_link *card, int res; for ( ; dev < SNDRV_CARDS; dev++) { - if (!enable[dev] || !isapnp[dev]) - continue; + if (!enable[dev]) + continue; + if (is_isapnp_selected(dev)) + continue; res = snd_opl3sa2_probe(dev, NULL, card, id); if (res < 0) return res; diff --git a/sound/isa/opti9xx/opti92x-ad1848.c b/sound/isa/opti9xx/opti92x-ad1848.c index 411a702..73573cb 100644 --- a/sound/isa/opti9xx/opti92x-ad1848.c +++ b/sound/isa/opti9xx/opti92x-ad1848.c @@ -1038,8 +1038,7 @@ static int snd_opti93x_capture_prepare(snd_pcm_substream_t *substream) chip->c_dma_size = size; snd_opti93x_out_mask(chip, OPTi93X_IFACE_CONF, - OPTi93X_CAPTURE_ENABLE | OPTi93X_CAPTURE_PIO, - (unsigned char)~(OPTi93X_CAPTURE_ENABLE | OPTi93X_CAPTURE_PIO)); + OPTi93X_CAPTURE_ENABLE | OPTi93X_CAPTURE_PIO, 0); snd_dma_program(chip->dma2, runtime->dma_addr, size, DMA_MODE_READ | DMA_AUTOINIT); @@ -1274,7 +1273,7 @@ static int snd_opti93x_create(snd_card_t *card, opti9xx_t *chip, opti93x_t *codec; *rcodec = NULL; - codec = kcalloc(1, sizeof(*codec), GFP_KERNEL); + codec = kzalloc(sizeof(*codec), GFP_KERNEL); if (codec == NULL) return -ENOMEM; codec->irq = -1; @@ -1895,8 +1894,8 @@ static void snd_card_opti9xx_free(snd_card_t *card) } } -static int __devinit snd_card_opti9xx_probe(struct pnp_card_link *pcard, - const struct pnp_card_device_id *pid) +static int snd_card_opti9xx_probe(struct pnp_card_link *pcard, + const struct pnp_card_device_id *pid) { static long possible_ports[] = {0x530, 0xe80, 0xf40, 0x604, -1}; static long possible_mpu_ports[] = {0x300, 0x310, 0x320, 0x330, -1}; @@ -1966,6 +1965,10 @@ static int __devinit snd_card_opti9xx_probe(struct pnp_card_link *pcard, snd_card_free(card); return error; } + if ((error = snd_card_set_generic_dev(card)) < 0) { + snd_card_free(card); + return error; + } #ifdef CONFIG_PNP } #endif /* CONFIG_PNP */ diff --git a/sound/isa/sb/emu8000.c b/sound/isa/sb/emu8000.c index 028af40..5375705 100644 --- a/sound/isa/sb/emu8000.c +++ b/sound/isa/sb/emu8000.c @@ -1097,7 +1097,7 @@ snd_emu8000_new(snd_card_t *card, int index, long port, int seq_ports, snd_seq_d if (seq_ports <= 0) return 0; - hw = kcalloc(1, sizeof(*hw), GFP_KERNEL); + hw = kzalloc(sizeof(*hw), GFP_KERNEL); if (hw == NULL) return -ENOMEM; spin_lock_init(&hw->reg_lock); diff --git a/sound/isa/sb/emu8000_pcm.c b/sound/isa/sb/emu8000_pcm.c index db5eb8b..0209790 100644 --- a/sound/isa/sb/emu8000_pcm.c +++ b/sound/isa/sb/emu8000_pcm.c @@ -233,7 +233,7 @@ static int emu8k_pcm_open(snd_pcm_substream_t *subs) emu8k_pcm_t *rec; snd_pcm_runtime_t *runtime = subs->runtime; - rec = kcalloc(1, sizeof(*rec), GFP_KERNEL); + rec = kzalloc(sizeof(*rec), GFP_KERNEL); if (! rec) return -ENOMEM; diff --git a/sound/isa/sb/sb16.c b/sound/isa/sb/sb16.c index 60e2c53..7888783 100644 --- a/sound/isa/sb/sb16.c +++ b/sound/isa/sb/sb16.c @@ -351,6 +351,12 @@ static void snd_sb16_free(snd_card_t *card) } } +#ifdef CONFIG_PNP +#define is_isapnp_selected(dev) isapnp[dev] +#else +#define is_isapnp_selected(dev) 0 +#endif + static int __init snd_sb16_probe(int dev, struct pnp_card_link *pcard, const struct pnp_card_device_id *pid) @@ -378,10 +384,8 @@ static int __init snd_sb16_probe(int dev, card->private_free = snd_sb16_free; #ifdef CONFIG_PNP if (isapnp[dev]) { - if ((err = snd_card_sb16_pnp(dev, acard, pcard, pid))) { - snd_card_free(card); - return err; - } + if ((err = snd_card_sb16_pnp(dev, acard, pcard, pid))) + goto _err; snd_card_set_dev(card, &pcard->card->dev); } #endif @@ -389,41 +393,37 @@ static int __init snd_sb16_probe(int dev, xirq = irq[dev]; xdma8 = dma8[dev]; xdma16 = dma16[dev]; -#ifdef CONFIG_PNP - if (!isapnp[dev]) { -#endif - if (xirq == SNDRV_AUTO_IRQ) { - if ((xirq = snd_legacy_find_free_irq(possible_irqs)) < 0) { - snd_card_free(card); - snd_printk(KERN_ERR PFX "unable to find a free IRQ\n"); - return -EBUSY; + if (! is_isapnp_selected(dev)) { + if (xirq == SNDRV_AUTO_IRQ) { + if ((xirq = snd_legacy_find_free_irq(possible_irqs)) < 0) { + snd_printk(KERN_ERR PFX "unable to find a free IRQ\n"); + err = -EBUSY; + goto _err; + } } - } - if (xdma8 == SNDRV_AUTO_DMA) { - if ((xdma8 = snd_legacy_find_free_dma(possible_dmas8)) < 0) { - snd_card_free(card); - snd_printk(KERN_ERR PFX "unable to find a free 8-bit DMA\n"); - return -EBUSY; + if (xdma8 == SNDRV_AUTO_DMA) { + if ((xdma8 = snd_legacy_find_free_dma(possible_dmas8)) < 0) { + snd_printk(KERN_ERR PFX "unable to find a free 8-bit DMA\n"); + err = -EBUSY; + goto _err; + } } - } - if (xdma16 == SNDRV_AUTO_DMA) { - if ((xdma16 = snd_legacy_find_free_dma(possible_dmas16)) < 0) { - snd_card_free(card); - snd_printk(KERN_ERR PFX "unable to find a free 16-bit DMA\n"); - return -EBUSY; + if (xdma16 == SNDRV_AUTO_DMA) { + if ((xdma16 = snd_legacy_find_free_dma(possible_dmas16)) < 0) { + snd_printk(KERN_ERR PFX "unable to find a free 16-bit DMA\n"); + err = -EBUSY; + goto _err; + } } - } - /* non-PnP FM port address is hardwired with base port address */ - fm_port[dev] = port[dev]; - /* block the 0x388 port to avoid PnP conflicts */ - acard->fm_res = request_region(0x388, 4, "SoundBlaster FM"); + /* non-PnP FM port address is hardwired with base port address */ + fm_port[dev] = port[dev]; + /* block the 0x388 port to avoid PnP conflicts */ + acard->fm_res = request_region(0x388, 4, "SoundBlaster FM"); #ifdef SNDRV_SBAWE_EMU8000 - /* non-PnP AWE port address is hardwired with base port address */ - awe_port[dev] = port[dev] + 0x400; + /* non-PnP AWE port address is hardwired with base port address */ + awe_port[dev] = port[dev] + 0x400; #endif -#ifdef CONFIG_PNP } -#endif if ((err = snd_sbdsp_create(card, port[dev], @@ -432,28 +432,20 @@ static int __init snd_sb16_probe(int dev, xdma8, xdma16, SB_HW_AUTO, - &chip)) < 0) { - snd_card_free(card); - return err; - } + &chip)) < 0) + goto _err; + if (chip->hardware != SB_HW_16) { - snd_card_free(card); - snd_printdd("SB 16 chip was not detected at 0x%lx\n", port[dev]); - return -ENODEV; + snd_printk(KERN_ERR PFX "SB 16 chip was not detected at 0x%lx\n", port[dev]); + err = -ENODEV; + goto _err; } chip->mpu_port = mpu_port[dev]; -#ifdef CONFIG_PNP - if (!isapnp[dev] && (err = snd_sb16dsp_configure(chip)) < 0) { -#else - if ((err = snd_sb16dsp_configure(chip)) < 0) { -#endif - snd_card_free(card); - return -ENXIO; - } - if ((err = snd_sb16dsp_pcm(chip, 0, NULL)) < 0) { - snd_card_free(card); - return -ENXIO; - } + if (! is_isapnp_selected(dev) && (err = snd_sb16dsp_configure(chip)) < 0) + goto _err; + + if ((err = snd_sb16dsp_pcm(chip, 0, NULL)) < 0) + goto _err; strcpy(card->driver, #ifdef SNDRV_SBAWE_EMU8000 @@ -474,10 +466,8 @@ static int __init snd_sb16_probe(int dev, if (chip->mpu_port > 0 && chip->mpu_port != SNDRV_AUTO_PORT) { if ((err = snd_mpu401_uart_new(card, 0, MPU401_HW_SB, chip->mpu_port, 0, - xirq, 0, &chip->rmidi)) < 0) { - snd_card_free(card); - return -ENXIO; - } + xirq, 0, &chip->rmidi)) < 0) + goto _err; chip->rmidi_callback = snd_mpu401_uart_interrupt; } @@ -499,17 +489,13 @@ static int __init snd_sb16_probe(int dev, #else int seqdev = 1; #endif - if ((err = snd_opl3_hwdep_new(opl3, 0, seqdev, &synth)) < 0) { - snd_card_free(card); - return -ENXIO; - } + if ((err = snd_opl3_hwdep_new(opl3, 0, seqdev, &synth)) < 0) + goto _err; } } - if ((err = snd_sbmixer_new(chip)) < 0) { - snd_card_free(card); - return -ENXIO; - } + if ((err = snd_sbmixer_new(chip)) < 0) + goto _err; #ifdef CONFIG_SND_SB16_CSP /* CSP chip on SB16ASP/AWE32 */ @@ -525,11 +511,11 @@ static int __init snd_sb16_probe(int dev, #endif #ifdef SNDRV_SBAWE_EMU8000 if (awe_port[dev] > 0) { - if (snd_emu8000_new(card, 1, awe_port[dev], - seq_ports[dev], NULL) < 0) { + if ((err = snd_emu8000_new(card, 1, awe_port[dev], + seq_ports[dev], NULL)) < 0) { snd_printk(KERN_ERR PFX "fatal error - EMU-8000 synthesizer not detected at 0x%lx\n", awe_port[dev]); - snd_card_free(card); - return -ENXIO; + + goto _err; } } #endif @@ -541,15 +527,21 @@ static int __init snd_sb16_probe(int dev, (mic_agc[dev] ? 0x00 : 0x01)); spin_unlock_irqrestore(&chip->mixer_lock, flags); - if ((err = snd_card_register(card)) < 0) { - snd_card_free(card); - return err; - } + if ((err = snd_card_set_generic_dev(card)) < 0) + goto _err; + + if ((err = snd_card_register(card)) < 0) + goto _err; + if (pcard) pnp_set_card_drvdata(pcard, card); else snd_sb16_legacy[dev] = card; return 0; + + _err: + snd_card_free(card); + return err; } static int __init snd_sb16_probe_legacy_port(unsigned long xport) @@ -560,10 +552,8 @@ static int __init snd_sb16_probe_legacy_port(unsigned long xport) for ( ; dev < SNDRV_CARDS; dev++) { if (!enable[dev] || port[dev] != SNDRV_AUTO_PORT) continue; -#ifdef CONFIG_PNP - if (isapnp[dev]) + if (is_isapnp_selected(dev)) continue; -#endif port[dev] = xport; res = snd_sb16_probe(dev, NULL, NULL); if (res < 0) @@ -621,10 +611,8 @@ static int __init alsa_card_sb16_init(void) for (dev = 0; dev < SNDRV_CARDS; dev++) { if (!enable[dev] || port[dev] == SNDRV_AUTO_PORT) continue; -#ifdef CONFIG_PNP - if (isapnp[dev]) + if (is_isapnp_selected(dev)) continue; -#endif if (!snd_sb16_probe(dev, NULL, NULL)) { cards++; continue; diff --git a/sound/isa/sb/sb16_csp.c b/sound/isa/sb/sb16_csp.c index d64790b..7192d4c 100644 --- a/sound/isa/sb/sb16_csp.c +++ b/sound/isa/sb/sb16_csp.c @@ -122,7 +122,7 @@ int snd_sb_csp_new(sb_t *chip, int device, snd_hwdep_t ** rhwdep) if ((err = snd_hwdep_new(chip->card, "SB16-CSP", device, &hw)) < 0) return err; - if ((p = kcalloc(1, sizeof(*p), GFP_KERNEL)) == NULL) { + if ((p = kzalloc(sizeof(*p), GFP_KERNEL)) == NULL) { snd_device_free(chip->card, hw); return -ENOMEM; } diff --git a/sound/isa/sb/sb8.c b/sound/isa/sb/sb8.c index e2cbc42..c41ac25 100644 --- a/sound/isa/sb/sb8.c +++ b/sound/isa/sb/sb8.c @@ -107,54 +107,47 @@ static int __init snd_sb8_probe(int dev) dma8[dev], -1, SB_HW_AUTO, - &chip)) < 0) { - snd_card_free(card); - return err; - } + &chip)) < 0) + goto _err; + if (chip->hardware >= SB_HW_16) { - snd_card_free(card); if (chip->hardware == SB_HW_ALS100) - snd_printdd("ALS100 chip detected at 0x%lx, try snd-als100 module\n", + snd_printk(KERN_WARNING "ALS100 chip detected at 0x%lx, try snd-als100 module\n", port[dev]); else - snd_printdd("SB 16 chip detected at 0x%lx, try snd-sb16 module\n", - port[dev]); - return -ENODEV; + snd_printk(KERN_WARNING "SB 16 chip detected at 0x%lx, try snd-sb16 module\n", + port[dev]); + err = -ENODEV; + goto _err; } - if ((err = snd_sb8dsp_pcm(chip, 0, NULL)) < 0) { - snd_card_free(card); - return err; - } - if ((err = snd_sbmixer_new(chip)) < 0) { - snd_card_free(card); - return err; - } + if ((err = snd_sb8dsp_pcm(chip, 0, NULL)) < 0) + goto _err; + + if ((err = snd_sbmixer_new(chip)) < 0) + goto _err; + if (chip->hardware == SB_HW_10 || chip->hardware == SB_HW_20) { if ((err = snd_opl3_create(card, chip->port + 8, 0, OPL3_HW_AUTO, 1, &opl3)) < 0) { - snd_printk(KERN_ERR "sb8: no OPL device at 0x%lx\n", chip->port + 8); + snd_printk(KERN_WARNING "sb8: no OPL device at 0x%lx\n", chip->port + 8); } } else { if ((err = snd_opl3_create(card, chip->port, chip->port + 2, OPL3_HW_AUTO, 1, &opl3)) < 0) { - snd_printk(KERN_ERR "sb8: no OPL device at 0x%lx-0x%lx\n", + snd_printk(KERN_WARNING "sb8: no OPL device at 0x%lx-0x%lx\n", chip->port, chip->port + 2); } } if (err >= 0) { - if ((err = snd_opl3_hwdep_new(opl3, 0, 1, NULL)) < 0) { - snd_card_free(card); - return err; - } + if ((err = snd_opl3_hwdep_new(opl3, 0, 1, NULL)) < 0) + goto _err; } - if ((err = snd_sb8dsp_midi(chip, 0, NULL)) < 0) { - snd_card_free(card); - return err; - } + if ((err = snd_sb8dsp_midi(chip, 0, NULL)) < 0) + goto _err; strcpy(card->driver, chip->hardware == SB_HW_PRO ? "SB Pro" : "SB8"); strcpy(card->shortname, chip->name); @@ -162,12 +155,19 @@ static int __init snd_sb8_probe(int dev) chip->name, chip->port, irq[dev], dma8[dev]); - if ((err = snd_card_register(card)) < 0) { - snd_card_free(card); - return err; - } + + if ((err = snd_card_set_generic_dev(card)) < 0) + goto _err; + + if ((err = snd_card_register(card)) < 0) + goto _err; + snd_sb8_cards[dev] = card; return 0; + + _err: + snd_card_free(card); + return err; } static int __init snd_card_sb8_legacy_auto_probe(unsigned long xport) diff --git a/sound/isa/sb/sb_common.c b/sound/isa/sb/sb_common.c index 5b6bde2..f0f205a 100644 --- a/sound/isa/sb/sb_common.c +++ b/sound/isa/sb/sb_common.c @@ -221,7 +221,7 @@ int snd_sbdsp_create(snd_card_t *card, snd_assert(r_chip != NULL, return -EINVAL); *r_chip = NULL; - chip = kcalloc(1, sizeof(*chip), GFP_KERNEL); + chip = kzalloc(sizeof(*chip), GFP_KERNEL); if (chip == NULL) return -ENOMEM; spin_lock_init(&chip->reg_lock); diff --git a/sound/isa/sgalaxy.c b/sound/isa/sgalaxy.c index 17f585b..52f2294d 100644 --- a/sound/isa/sgalaxy.c +++ b/sound/isa/sgalaxy.c @@ -67,6 +67,8 @@ MODULE_PARM_DESC(dma1, "DMA1 # for Sound Galaxy driver."); static snd_card_t *snd_sgalaxy_cards[SNDRV_CARDS] = SNDRV_DEFAULT_PTR; +#define PFX "sgalaxy: " + /* */ @@ -135,7 +137,7 @@ static int __init snd_sgalaxy_setup_wss(unsigned long port, int irq, int dma) } #if 0 - snd_printdd("sgalaxy - setting up IRQ/DMA for WSS\n"); + snd_printdd(PFX "setting up IRQ/DMA for WSS\n"); #endif /* initialize IRQ for WSS codec */ @@ -160,7 +162,7 @@ static int __init snd_sgalaxy_setup_wss(unsigned long port, int irq, int dma) static int __init snd_sgalaxy_detect(int dev, int irq, int dma) { #if 0 - snd_printdd("sgalaxy - switching to WSS mode\n"); + snd_printdd(PFX "switching to WSS mode\n"); #endif /* switch to WSS mode */ @@ -223,11 +225,11 @@ static int __init snd_sgalaxy_probe(int dev) ad1848_t *chip; if (sbport[dev] == SNDRV_AUTO_PORT) { - snd_printk("specify SB port\n"); + snd_printk(KERN_ERR PFX "specify SB port\n"); return -EINVAL; } if (wssport[dev] == SNDRV_AUTO_PORT) { - snd_printk("specify WSS port\n"); + snd_printk(KERN_ERR PFX "specify WSS port\n"); return -EINVAL; } card = snd_card_new(index[dev], id[dev], THIS_MODULE, 0); @@ -237,46 +239,39 @@ static int __init snd_sgalaxy_probe(int dev) xirq = irq[dev]; if (xirq == SNDRV_AUTO_IRQ) { if ((xirq = snd_legacy_find_free_irq(possible_irqs)) < 0) { - snd_card_free(card); - snd_printk("unable to find a free IRQ\n"); - return -EBUSY; + snd_printk(KERN_ERR PFX "unable to find a free IRQ\n"); + err = -EBUSY; + goto _err; } } xdma1 = dma1[dev]; if (xdma1 == SNDRV_AUTO_DMA) { if ((xdma1 = snd_legacy_find_free_dma(possible_dmas)) < 0) { - snd_card_free(card); - snd_printk("unable to find a free DMA\n"); - return -EBUSY; + snd_printk(KERN_ERR PFX "unable to find a free DMA\n"); + err = -EBUSY; + goto _err; } } - if ((err = snd_sgalaxy_detect(dev, xirq, xdma1)) < 0) { - snd_card_free(card); - return err; - } + if ((err = snd_sgalaxy_detect(dev, xirq, xdma1)) < 0) + goto _err; if ((err = snd_ad1848_create(card, wssport[dev] + 4, xirq, xdma1, - AD1848_HW_DETECT, &chip)) < 0) { - snd_card_free(card); - return err; - } + AD1848_HW_DETECT, &chip)) < 0) + goto _err; if ((err = snd_ad1848_pcm(chip, 0, NULL)) < 0) { - snd_printdd("sgalaxy - error creating new ad1848 PCM device\n"); - snd_card_free(card); - return err; + snd_printdd(PFX "error creating new ad1848 PCM device\n"); + goto _err; } if ((err = snd_ad1848_mixer(chip)) < 0) { - snd_printdd("sgalaxy - error creating new ad1848 mixer\n"); - snd_card_free(card); - return err; + snd_printdd(PFX "error creating new ad1848 mixer\n"); + goto _err; } - if (snd_sgalaxy_mixer(chip) < 0) { - snd_printdd("sgalaxy - the mixer rewrite failed\n"); - snd_card_free(card); - return err; + if ((err = snd_sgalaxy_mixer(chip)) < 0) { + snd_printdd(PFX "the mixer rewrite failed\n"); + goto _err; } strcpy(card->driver, "Sound Galaxy"); @@ -284,12 +279,18 @@ static int __init snd_sgalaxy_probe(int dev) sprintf(card->longname, "Sound Galaxy at 0x%lx, irq %d, dma %d", wssport[dev], xirq, xdma1); - if ((err = snd_card_register(card)) < 0) { - snd_card_free(card); - return err; - } + if ((err = snd_card_set_generic_dev(card)) < 0) + goto _err; + + if ((err = snd_card_register(card)) < 0) + goto _err; + snd_sgalaxy_cards[dev] = card; return 0; + + _err: + snd_card_free(card); + return err; } static int __init alsa_card_sgalaxy_init(void) diff --git a/sound/isa/sscape.c b/sound/isa/sscape.c index 3959ed6..9f6b58c 100644 --- a/sound/isa/sscape.c +++ b/sound/isa/sscape.c @@ -1262,11 +1262,6 @@ static int __devinit create_sscape(const struct params *params, snd_card_t **rca */ sscape_write(sscape, GA_INTENA_REG, 0x80); - if ((err = snd_card_register(card)) < 0) { - printk(KERN_ERR "sscape: Failed to register sound card\n"); - goto _release_card; - } - /* * Initialize mixer */ @@ -1396,6 +1391,13 @@ static int __devinit sscape_pnp_detect(struct pnp_card_link *pcard, if (ret < 0) return ret; snd_card_set_dev(card, &pcard->card->dev); + + if ((ret = snd_card_register(card)) < 0) { + printk(KERN_ERR "sscape: Failed to register sound card\n"); + snd_card_free(card); + return ret; + } + pnp_set_card_drvdata(pcard, card); ++sscape_cards; ++idx; @@ -1460,6 +1462,16 @@ static int __init sscape_manual_probe(struct params *params) if (ret < 0) return ret; + if ((ret = snd_card_set_generic_dev(card)) < 0) { + snd_card_free(card); + return ret; + } + if ((ret = snd_card_register(card)) < 0) { + printk(KERN_ERR "sscape: Failed to register sound card\n"); + snd_card_free(card); + return ret; + } + sscape_card[sscape_cards] = card; params++; sscape_cards++; diff --git a/sound/isa/wavefront/wavefront.c b/sound/isa/wavefront/wavefront.c index 79b0220..0a572e0 100644 --- a/sound/isa/wavefront/wavefront.c +++ b/sound/isa/wavefront/wavefront.c @@ -622,6 +622,11 @@ snd_wavefront_probe (int dev, struct pnp_card_link *pcard, ics2115_port[dev], ics2115_irq[dev]); + if ((err = snd_card_set_generic_dev(card)) < 0) { + snd_card_free(card); + return err; + } + if ((err = snd_card_register(card)) < 0) { snd_card_free(card); return err; diff --git a/sound/mips/Kconfig b/sound/mips/Kconfig index 531f8ba..2433b77 100644 --- a/sound/mips/Kconfig +++ b/sound/mips/Kconfig @@ -8,6 +8,7 @@ config SND_AU1X00 depends on (SOC_AU1000 || SOC_AU1100 || SOC_AU1500) && SND select SND_PCM select SND_AC97_CODEC + select SND_GENERIC_DRIVER help ALSA Sound driver for the Au1x00's AC97 port. diff --git a/sound/mips/au1x00.c b/sound/mips/au1x00.c index c20522b..3f9684f 100644 --- a/sound/mips/au1x00.c +++ b/sound/mips/au1x00.c @@ -667,6 +667,11 @@ au1000_init(void) strcpy(au1000->card->shortname, "Au1000-AC97"); sprintf(au1000->card->longname, "AMD Au1000--AC97 ALSA Driver"); + if ((err = snd_card_set_generic_dev(au1000->card)) < 0) { + snd_card_free(au1000->card); + return err; + } + if ((err = snd_card_register(au1000->card)) < 0) { snd_card_free(au1000->card); return err; diff --git a/sound/oss/au1000.c b/sound/oss/au1000.c index 4491733..2c2ae2e 100644 --- a/sound/oss/au1000.c +++ b/sound/oss/au1000.c @@ -1295,7 +1295,7 @@ static int au1000_mmap(struct file *file, struct vm_area_struct *vma) unsigned long size; int ret = 0; - dbg(__FUNCTION__); + dbg("%s", __FUNCTION__); lock_kernel(); down(&s->sem); diff --git a/sound/oss/ite8172.c b/sound/oss/ite8172.c index 58f879f..26e5944 100644 --- a/sound/oss/ite8172.c +++ b/sound/oss/ite8172.c @@ -1859,7 +1859,7 @@ static int it8172_release(struct inode *inode, struct file *file) struct it8172_state *s = (struct it8172_state *)file->private_data; #ifdef IT8172_VERBOSE_DEBUG - dbg(__FUNCTION__); + dbg("%s", __FUNCTION__); #endif lock_kernel(); if (file->f_mode & FMODE_WRITE) diff --git a/sound/parisc/harmony.c b/sound/parisc/harmony.c index d7a8f9f..f560dd8 100644 --- a/sound/parisc/harmony.c +++ b/sound/parisc/harmony.c @@ -880,6 +880,8 @@ snd_harmony_create(snd_card_t *card, goto free_and_ret; } + snd_card_set_dev(card, &padev->dev); + *rchip = h; return 0; diff --git a/sound/pci/Kconfig b/sound/pci/Kconfig index 1e458919..a5d593c 100644 --- a/sound/pci/Kconfig +++ b/sound/pci/Kconfig @@ -316,6 +316,18 @@ config SND_YMFPCI To compile this driver as a module, choose M here: the module will be called snd-ymfpci. +config SND_AD1889 + tristate "Analog Devices AD1889" + depends on SND + select SND_AC97_CODEC + help + Say Y here to include support for the integrated AC97 sound + device found in particular on the Hewlett-Packard [BCJ]-xxx0 + class PA-RISC workstations, using the AD1819 codec. + + To compile this as a module, choose M here: the module + will be called snd-ad1889. + config SND_ALS4000 tristate "Avance Logic ALS4000" depends on SND && ISA_DMA_API diff --git a/sound/pci/Makefile b/sound/pci/Makefile index b40575c..42fabfc 100644 --- a/sound/pci/Makefile +++ b/sound/pci/Makefile @@ -3,6 +3,7 @@ # Copyright (c) 2001 by Jaroslav Kysela <perex@suse.cz> # +snd-ad1889-objs := ad1889.o snd-als4000-objs := als4000.o snd-atiixp-objs := atiixp.o snd-atiixp-modem-objs := atiixp_modem.o @@ -25,6 +26,7 @@ snd-via82xx-objs := via82xx.o snd-via82xx-modem-objs := via82xx_modem.o # Toplevel Module Dependency +obj-$(CONFIG_SND_AD1889) += snd-ad1889.o obj-$(CONFIG_SND_ALS4000) += snd-als4000.o obj-$(CONFIG_SND_ATIIXP) += snd-atiixp.o obj-$(CONFIG_SND_ATIIXP_MODEM) += snd-atiixp-modem.o diff --git a/sound/pci/ac97/ac97_codec.c b/sound/pci/ac97/ac97_codec.c index 5501f44..e64cb07 100644 --- a/sound/pci/ac97/ac97_codec.c +++ b/sound/pci/ac97/ac97_codec.c @@ -112,6 +112,7 @@ static const ac97_codec_id_t snd_ac97_codec_ids[] = { { 0x414c4723, 0xffffffff, "ALC650F", NULL, NULL }, /* already patched */ { 0x414c4720, 0xfffffff0, "ALC650", patch_alc650, NULL }, { 0x414c4760, 0xfffffff0, "ALC655", patch_alc655, NULL }, +{ 0x414c4781, 0xffffffff, "ALC658D", NULL, NULL }, /* already patched */ { 0x414c4780, 0xfffffff0, "ALC658", patch_alc655, NULL }, { 0x414c4790, 0xfffffff0, "ALC850", patch_alc850, NULL }, { 0x414c4730, 0xffffffff, "ALC101", NULL, NULL }, @@ -1796,7 +1797,7 @@ int snd_ac97_bus(snd_card_t *card, int num, ac97_bus_ops_t *ops, snd_assert(card != NULL, return -EINVAL); snd_assert(rbus != NULL, return -EINVAL); - bus = kcalloc(1, sizeof(*bus), GFP_KERNEL); + bus = kzalloc(sizeof(*bus), GFP_KERNEL); if (bus == NULL) return -ENOMEM; bus->card = card; @@ -1905,7 +1906,7 @@ int snd_ac97_mixer(ac97_bus_t *bus, ac97_template_t *template, ac97_t **rac97) } card = bus->card; - ac97 = kcalloc(1, sizeof(*ac97), GFP_KERNEL); + ac97 = kzalloc(sizeof(*ac97), GFP_KERNEL); if (ac97 == NULL) return -ENOMEM; ac97->private_data = template->private_data; diff --git a/sound/pci/ac97/ac97_id.h b/sound/pci/ac97/ac97_id.h index dadf387..6d73514 100644 --- a/sound/pci/ac97/ac97_id.h +++ b/sound/pci/ac97/ac97_id.h @@ -52,6 +52,7 @@ #define AC97_ID_ALC650F 0x414c4723 #define AC97_ID_ALC655 0x414c4760 #define AC97_ID_ALC658 0x414c4780 +#define AC97_ID_ALC658D 0x414c4781 #define AC97_ID_ALC850 0x414c4790 #define AC97_ID_YMF753 0x594d4803 #define AC97_ID_VT1616 0x49434551 diff --git a/sound/pci/ac97/ac97_patch.c b/sound/pci/ac97/ac97_patch.c index b584172..045ddc7 100644 --- a/sound/pci/ac97/ac97_patch.c +++ b/sound/pci/ac97/ac97_patch.c @@ -2134,7 +2134,13 @@ int patch_alc655(ac97_t * ac97) { unsigned int val; - ac97->spec.dev_flags = (ac97->id == 0x414c4780); /* ALC658 */ + if (ac97->id == AC97_ID_ALC658) { + ac97->spec.dev_flags = 1; /* ALC658 */ + if ((snd_ac97_read(ac97, AC97_ALC650_REVISION) & 0x3f) == 2) { + ac97->id = AC97_ID_ALC658D; + ac97->spec.dev_flags = 2; + } + } ac97->build_ops = &patch_alc655_ops; @@ -2143,10 +2149,15 @@ int patch_alc655(ac97_t * ac97) /* adjust default values */ val = snd_ac97_read(ac97, 0x7a); /* misc control */ - if (ac97->id == 0x414c4780) /* ALC658 */ + if (ac97->spec.dev_flags) /* ALC658 */ val &= ~(1 << 1); /* Pin 47 is spdif input pin */ - else /* ALC655 */ - val |= (1 << 1); /* Pin 47 is spdif input pin */ + else { /* ALC655 */ + if (ac97->subsystem_vendor == 0x1462 && + ac97->subsystem_device == 0x0131) /* MSI S270 laptop */ + val &= ~(1 << 1); /* Pin 47 is EAPD (for internal speaker) */ + else + val |= (1 << 1); /* Pin 47 is spdif input pin */ + } val &= ~(1 << 12); /* vref enable */ snd_ac97_write_cache(ac97, 0x7a, val); /* set default: spdif-in enabled, @@ -2159,6 +2170,11 @@ int patch_alc655(ac97_t * ac97) /* full DAC volume */ snd_ac97_write_cache(ac97, AC97_ALC650_SURR_DAC_VOL, 0x0808); snd_ac97_write_cache(ac97, AC97_ALC650_LFE_DAC_VOL, 0x0808); + + /* update undocumented bit... */ + if (ac97->id == AC97_ID_ALC658D) + snd_ac97_update_bits(ac97, 0x74, 0x0800, 0x0800); + return 0; } diff --git a/sound/pci/ac97/ak4531_codec.c b/sound/pci/ac97/ak4531_codec.c index f9ce0fd..4032c57 100644 --- a/sound/pci/ac97/ak4531_codec.c +++ b/sound/pci/ac97/ak4531_codec.c @@ -357,7 +357,7 @@ int snd_ak4531_mixer(snd_card_t * card, ak4531_t * _ak4531, ak4531_t ** rak4531) snd_assert(rak4531 != NULL, return -EINVAL); *rak4531 = NULL; snd_assert(card != NULL && _ak4531 != NULL, return -EINVAL); - ak4531 = kcalloc(1, sizeof(*ak4531), GFP_KERNEL); + ak4531 = kzalloc(sizeof(*ak4531), GFP_KERNEL); if (ak4531 == NULL) return -ENOMEM; *ak4531 = *_ak4531; diff --git a/sound/pci/ad1889.c b/sound/pci/ad1889.c new file mode 100644 index 0000000..d7d99a2 --- /dev/null +++ b/sound/pci/ad1889.c @@ -0,0 +1,1090 @@ +/* Analog Devices 1889 audio driver + * + * This is a driver for the AD1889 PCI audio chipset found + * on the HP PA-RISC [BCJ]-xxx0 workstations. + * + * Copyright (C) 2004-2005, Kyle McMartin <kyle@parisc-linux.org> + * Copyright (C) 2005, Thibaut Varene <varenet@parisc-linux.org> + * Based on the OSS AD1889 driver by Randolph Chung <tausq@debian.org> + * + * This program is free software; you can 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., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * TODO: + * Do we need to take care of CCS register? + * Maybe we could use finer grained locking (separate locks for pb/cap)? + * Wishlist: + * Control Interface (mixer) support + * Better AC97 support (VSR...)? + * PM support + * MIDI support + * Game Port support + * SG DMA support (this will need *alot* of work) + */ + +#include <linux/init.h> +#include <linux/pci.h> +#include <linux/slab.h> +#include <linux/interrupt.h> +#include <linux/compiler.h> +#include <linux/delay.h> + +#include <sound/driver.h> +#include <sound/core.h> +#include <sound/pcm.h> +#include <sound/initval.h> +#include <sound/ac97_codec.h> + +#include <asm/io.h> + +#include "ad1889.h" +#include "ac97/ac97_id.h" + +#define AD1889_DRVVER "$Revision: 1.3 $" + +MODULE_AUTHOR("Kyle McMartin <kyle@parisc-linux.org>, Thibaut Varene <t-bone@parisc-linux.org>"); +MODULE_DESCRIPTION("Analog Devices AD1889 ALSA sound driver"); +MODULE_LICENSE("GPL"); +MODULE_SUPPORTED_DEVICE("{{Analog Devices,AD1889}}"); + +static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; +module_param_array(index, int, NULL, 0444); +MODULE_PARM_DESC(index, "Index value for the AD1889 soundcard."); + +static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; +module_param_array(id, charp, NULL, 0444); +MODULE_PARM_DESC(id, "ID string for the AD1889 soundcard."); + +static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP; +module_param_array(enable, bool, NULL, 0444); +MODULE_PARM_DESC(enable, "Enable AD1889 soundcard."); + +static char *ac97_quirk[SNDRV_CARDS]; +module_param_array(ac97_quirk, charp, NULL, 0444); +MODULE_PARM_DESC(ac97_quirk, "AC'97 workaround for strange hardware."); + +#define DEVNAME "ad1889" +#define PFX DEVNAME ": " + +/* let's use the global sound debug interfaces */ +#define ad1889_debug(fmt, arg...) snd_printd(KERN_DEBUG fmt, ## arg) + +/* keep track of some hw registers */ +struct ad1889_register_state { + u16 reg; /* reg setup */ + u32 addr; /* dma base address */ + unsigned long size; /* DMA buffer size */ +}; + +struct snd_ad1889 { + snd_card_t *card; + struct pci_dev *pci; + + int irq; + unsigned long bar; + void __iomem *iobase; + + ac97_t *ac97; + ac97_bus_t *ac97_bus; + snd_pcm_t *pcm; + snd_info_entry_t *proc; + + snd_pcm_substream_t *psubs; + snd_pcm_substream_t *csubs; + + /* playback register state */ + struct ad1889_register_state wave; + struct ad1889_register_state ramc; + + spinlock_t lock; +}; + +static inline u16 +ad1889_readw(struct snd_ad1889 *chip, unsigned reg) +{ + return readw(chip->iobase + reg); +} + +static inline void +ad1889_writew(struct snd_ad1889 *chip, unsigned reg, u16 val) +{ + writew(val, chip->iobase + reg); +} + +static inline u32 +ad1889_readl(struct snd_ad1889 *chip, unsigned reg) +{ + return readl(chip->iobase + reg); +} + +static inline void +ad1889_writel(struct snd_ad1889 *chip, unsigned reg, u32 val) +{ + writel(val, chip->iobase + reg); +} + +static inline void +ad1889_unmute(struct snd_ad1889 *chip) +{ + u16 st; + st = ad1889_readw(chip, AD_DS_WADA) & + ~(AD_DS_WADA_RWAM | AD_DS_WADA_LWAM); + ad1889_writew(chip, AD_DS_WADA, st); + ad1889_readw(chip, AD_DS_WADA); +} + +static inline void +ad1889_mute(struct snd_ad1889 *chip) +{ + u16 st; + st = ad1889_readw(chip, AD_DS_WADA) | AD_DS_WADA_RWAM | AD_DS_WADA_LWAM; + ad1889_writew(chip, AD_DS_WADA, st); + ad1889_readw(chip, AD_DS_WADA); +} + +static inline void +ad1889_load_adc_buffer_address(struct snd_ad1889 *chip, u32 address) +{ + ad1889_writel(chip, AD_DMA_ADCBA, address); + ad1889_writel(chip, AD_DMA_ADCCA, address); +} + +static inline void +ad1889_load_adc_buffer_count(struct snd_ad1889 *chip, u32 count) +{ + ad1889_writel(chip, AD_DMA_ADCBC, count); + ad1889_writel(chip, AD_DMA_ADCCC, count); +} + +static inline void +ad1889_load_adc_interrupt_count(struct snd_ad1889 *chip, u32 count) +{ + ad1889_writel(chip, AD_DMA_ADCIB, count); + ad1889_writel(chip, AD_DMA_ADCIC, count); +} + +static inline void +ad1889_load_wave_buffer_address(struct snd_ad1889 *chip, u32 address) +{ + ad1889_writel(chip, AD_DMA_WAVBA, address); + ad1889_writel(chip, AD_DMA_WAVCA, address); +} + +static inline void +ad1889_load_wave_buffer_count(struct snd_ad1889 *chip, u32 count) +{ + ad1889_writel(chip, AD_DMA_WAVBC, count); + ad1889_writel(chip, AD_DMA_WAVCC, count); +} + +static inline void +ad1889_load_wave_interrupt_count(struct snd_ad1889 *chip, u32 count) +{ + ad1889_writel(chip, AD_DMA_WAVIB, count); + ad1889_writel(chip, AD_DMA_WAVIC, count); +} + +static void +ad1889_channel_reset(struct snd_ad1889 *chip, unsigned int channel) +{ + u16 reg; + + if (channel & AD_CHAN_WAV) { + /* Disable wave channel */ + reg = ad1889_readw(chip, AD_DS_WSMC) & ~AD_DS_WSMC_WAEN; + ad1889_writew(chip, AD_DS_WSMC, reg); + chip->wave.reg = reg; + + /* disable IRQs */ + reg = ad1889_readw(chip, AD_DMA_WAV); + reg &= AD_DMA_IM_DIS; + reg &= ~AD_DMA_LOOP; + ad1889_writew(chip, AD_DMA_WAV, reg); + + /* clear IRQ and address counters and pointers */ + ad1889_load_wave_buffer_address(chip, 0x0); + ad1889_load_wave_buffer_count(chip, 0x0); + ad1889_load_wave_interrupt_count(chip, 0x0); + + /* flush */ + ad1889_readw(chip, AD_DMA_WAV); + } + + if (channel & AD_CHAN_ADC) { + /* Disable ADC channel */ + reg = ad1889_readw(chip, AD_DS_RAMC) & ~AD_DS_RAMC_ADEN; + ad1889_writew(chip, AD_DS_RAMC, reg); + chip->ramc.reg = reg; + + reg = ad1889_readw(chip, AD_DMA_ADC); + reg &= AD_DMA_IM_DIS; + reg &= ~AD_DMA_LOOP; + ad1889_writew(chip, AD_DMA_ADC, reg); + + ad1889_load_adc_buffer_address(chip, 0x0); + ad1889_load_adc_buffer_count(chip, 0x0); + ad1889_load_adc_interrupt_count(chip, 0x0); + + /* flush */ + ad1889_readw(chip, AD_DMA_ADC); + } +} + +static inline u16 +snd_ad1889_ac97_read(ac97_t *ac97, unsigned short reg) +{ + struct snd_ad1889 *chip = ac97->private_data; + return ad1889_readw(chip, AD_AC97_BASE + reg); +} + +static inline void +snd_ad1889_ac97_write(ac97_t *ac97, unsigned short reg, unsigned short val) +{ + struct snd_ad1889 *chip = ac97->private_data; + ad1889_writew(chip, AD_AC97_BASE + reg, val); +} + +static int +snd_ad1889_ac97_ready(struct snd_ad1889 *chip) +{ + int retry = 400; /* average needs 352 msec */ + + while (!(ad1889_readw(chip, AD_AC97_ACIC) & AD_AC97_ACIC_ACRDY) + && --retry) + mdelay(1); + if (!retry) { + snd_printk(KERN_ERR PFX "[%s] Link is not ready.\n", + __FUNCTION__); + return -EIO; + } + ad1889_debug("[%s] ready after %d ms\n", __FUNCTION__, 400 - retry); + + return 0; +} + +static int +snd_ad1889_hw_params(snd_pcm_substream_t *substream, + snd_pcm_hw_params_t *hw_params) +{ + return snd_pcm_lib_malloc_pages(substream, + params_buffer_bytes(hw_params)); +} + +static int +snd_ad1889_hw_free(snd_pcm_substream_t *substream) +{ + return snd_pcm_lib_free_pages(substream); +} + +static snd_pcm_hardware_t snd_ad1889_playback_hw = { + .info = SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED | + SNDRV_PCM_INFO_MMAP_VALID | SNDRV_PCM_INFO_BLOCK_TRANSFER, + .formats = SNDRV_PCM_FMTBIT_S16_LE, + .rates = SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_8000_48000, + .rate_min = 8000, /* docs say 7000, but we're lazy */ + .rate_max = 48000, + .channels_min = 1, + .channels_max = 2, + .buffer_bytes_max = BUFFER_BYTES_MAX, + .period_bytes_min = PERIOD_BYTES_MIN, + .period_bytes_max = PERIOD_BYTES_MAX, + .periods_min = PERIODS_MIN, + .periods_max = PERIODS_MAX, + /*.fifo_size = 0,*/ +}; + +static snd_pcm_hardware_t snd_ad1889_capture_hw = { + .info = SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED | + SNDRV_PCM_INFO_MMAP_VALID | SNDRV_PCM_INFO_BLOCK_TRANSFER, + .formats = SNDRV_PCM_FMTBIT_S16_LE, + .rates = SNDRV_PCM_RATE_48000, + .rate_min = 48000, /* docs say we could to VSR, but we're lazy */ + .rate_max = 48000, + .channels_min = 1, + .channels_max = 2, + .buffer_bytes_max = BUFFER_BYTES_MAX, + .period_bytes_min = PERIOD_BYTES_MIN, + .period_bytes_max = PERIOD_BYTES_MAX, + .periods_min = PERIODS_MIN, + .periods_max = PERIODS_MAX, + /*.fifo_size = 0,*/ +}; + +static int +snd_ad1889_playback_open(snd_pcm_substream_t *ss) +{ + struct snd_ad1889 *chip = snd_pcm_substream_chip(ss); + snd_pcm_runtime_t *rt = ss->runtime; + + chip->psubs = ss; + rt->hw = snd_ad1889_playback_hw; + + return 0; +} + +static int +snd_ad1889_capture_open(snd_pcm_substream_t *ss) +{ + struct snd_ad1889 *chip = snd_pcm_substream_chip(ss); + snd_pcm_runtime_t *rt = ss->runtime; + + chip->csubs = ss; + rt->hw = snd_ad1889_capture_hw; + + return 0; +} + +static int +snd_ad1889_playback_close(snd_pcm_substream_t *ss) +{ + struct snd_ad1889 *chip = snd_pcm_substream_chip(ss); + chip->psubs = NULL; + return 0; +} + +static int +snd_ad1889_capture_close(snd_pcm_substream_t *ss) +{ + struct snd_ad1889 *chip = snd_pcm_substream_chip(ss); + chip->csubs = NULL; + return 0; +} + +static int +snd_ad1889_playback_prepare(snd_pcm_substream_t *ss) +{ + struct snd_ad1889 *chip = snd_pcm_substream_chip(ss); + snd_pcm_runtime_t *rt = ss->runtime; + unsigned int size = snd_pcm_lib_buffer_bytes(ss); + unsigned int count = snd_pcm_lib_period_bytes(ss); + u16 reg; + + ad1889_channel_reset(chip, AD_CHAN_WAV); + + reg = ad1889_readw(chip, AD_DS_WSMC); + + /* Mask out 16-bit / Stereo */ + reg &= ~(AD_DS_WSMC_WA16 | AD_DS_WSMC_WAST); + + if (snd_pcm_format_width(rt->format) == 16) + reg |= AD_DS_WSMC_WA16; + + if (rt->channels > 1) + reg |= AD_DS_WSMC_WAST; + + /* let's make sure we don't clobber ourselves */ + spin_lock_irq(&chip->lock); + + chip->wave.size = size; + chip->wave.reg = reg; + chip->wave.addr = rt->dma_addr; + + ad1889_writew(chip, AD_DS_WSMC, chip->wave.reg); + + /* Set sample rates on the codec */ + ad1889_writew(chip, AD_DS_WAS, rt->rate); + + /* Set up DMA */ + ad1889_load_wave_buffer_address(chip, chip->wave.addr); + ad1889_load_wave_buffer_count(chip, size); + ad1889_load_wave_interrupt_count(chip, count); + + /* writes flush */ + ad1889_readw(chip, AD_DS_WSMC); + + spin_unlock_irq(&chip->lock); + + ad1889_debug("prepare playback: addr = 0x%x, count = %u, " + "size = %u, reg = 0x%x, rate = %u\n", chip->wave.addr, + count, size, reg, rt->rate); + return 0; +} + +static int +snd_ad1889_capture_prepare(snd_pcm_substream_t *ss) +{ + struct snd_ad1889 *chip = snd_pcm_substream_chip(ss); + snd_pcm_runtime_t *rt = ss->runtime; + unsigned int size = snd_pcm_lib_buffer_bytes(ss); + unsigned int count = snd_pcm_lib_period_bytes(ss); + u16 reg; + + ad1889_channel_reset(chip, AD_CHAN_ADC); + + reg = ad1889_readw(chip, AD_DS_RAMC); + + /* Mask out 16-bit / Stereo */ + reg &= ~(AD_DS_RAMC_AD16 | AD_DS_RAMC_ADST); + + if (snd_pcm_format_width(rt->format) == 16) + reg |= AD_DS_RAMC_AD16; + + if (rt->channels > 1) + reg |= AD_DS_RAMC_ADST; + + /* let's make sure we don't clobber ourselves */ + spin_lock_irq(&chip->lock); + + chip->ramc.size = size; + chip->ramc.reg = reg; + chip->ramc.addr = rt->dma_addr; + + ad1889_writew(chip, AD_DS_RAMC, chip->ramc.reg); + + /* Set up DMA */ + ad1889_load_adc_buffer_address(chip, chip->ramc.addr); + ad1889_load_adc_buffer_count(chip, size); + ad1889_load_adc_interrupt_count(chip, count); + + /* writes flush */ + ad1889_readw(chip, AD_DS_RAMC); + + spin_unlock_irq(&chip->lock); + + ad1889_debug("prepare capture: addr = 0x%x, count = %u, " + "size = %u, reg = 0x%x, rate = %u\n", chip->ramc.addr, + count, size, reg, rt->rate); + return 0; +} + +/* this is called in atomic context with IRQ disabled. + Must be as fast as possible and not sleep. + DMA should be *triggered* by this call. + The WSMC "WAEN" bit triggers DMA Wave On/Off */ +static int +snd_ad1889_playback_trigger(snd_pcm_substream_t *ss, int cmd) +{ + u16 wsmc; + struct snd_ad1889 *chip = snd_pcm_substream_chip(ss); + + wsmc = ad1889_readw(chip, AD_DS_WSMC); + + switch (cmd) { + case SNDRV_PCM_TRIGGER_START: + /* enable DMA loop & interrupts */ + ad1889_writew(chip, AD_DMA_WAV, AD_DMA_LOOP | AD_DMA_IM_CNT); + wsmc |= AD_DS_WSMC_WAEN; + /* 1 to clear CHSS bit */ + ad1889_writel(chip, AD_DMA_CHSS, AD_DMA_CHSS_WAVS); + ad1889_unmute(chip); + break; + case SNDRV_PCM_TRIGGER_STOP: + ad1889_mute(chip); + wsmc &= ~AD_DS_WSMC_WAEN; + break; + default: + snd_BUG(); + return -EINVAL; + } + + chip->wave.reg = wsmc; + ad1889_writew(chip, AD_DS_WSMC, wsmc); + ad1889_readw(chip, AD_DS_WSMC); /* flush */ + + /* reset the chip when STOP - will disable IRQs */ + if (cmd == SNDRV_PCM_TRIGGER_STOP) + ad1889_channel_reset(chip, AD_CHAN_WAV); + + return 0; +} + +/* this is called in atomic context with IRQ disabled. + Must be as fast as possible and not sleep. + DMA should be *triggered* by this call. + The RAMC "ADEN" bit triggers DMA ADC On/Off */ +static int +snd_ad1889_capture_trigger(snd_pcm_substream_t *ss, int cmd) +{ + u16 ramc; + struct snd_ad1889 *chip = snd_pcm_substream_chip(ss); + + ramc = ad1889_readw(chip, AD_DS_RAMC); + + switch (cmd) { + case SNDRV_PCM_TRIGGER_START: + /* enable DMA loop & interrupts */ + ad1889_writew(chip, AD_DMA_ADC, AD_DMA_LOOP | AD_DMA_IM_CNT); + ramc |= AD_DS_RAMC_ADEN; + /* 1 to clear CHSS bit */ + ad1889_writel(chip, AD_DMA_CHSS, AD_DMA_CHSS_ADCS); + break; + case SNDRV_PCM_TRIGGER_STOP: + ramc &= ~AD_DS_RAMC_ADEN; + break; + default: + return -EINVAL; + } + + chip->ramc.reg = ramc; + ad1889_writew(chip, AD_DS_RAMC, ramc); + ad1889_readw(chip, AD_DS_RAMC); /* flush */ + + /* reset the chip when STOP - will disable IRQs */ + if (cmd == SNDRV_PCM_TRIGGER_STOP) + ad1889_channel_reset(chip, AD_CHAN_ADC); + + return 0; +} + +/* Called in atomic context with IRQ disabled */ +static snd_pcm_uframes_t +snd_ad1889_playback_pointer(snd_pcm_substream_t *ss) +{ + size_t ptr = 0; + struct snd_ad1889 *chip = snd_pcm_substream_chip(ss); + + if (unlikely(!(chip->wave.reg & AD_DS_WSMC_WAEN))) + return 0; + + ptr = ad1889_readl(chip, AD_DMA_WAVCA); + ptr -= chip->wave.addr; + + snd_assert((ptr >= 0) && (ptr < chip->wave.size), return 0); + + return bytes_to_frames(ss->runtime, ptr); +} + +/* Called in atomic context with IRQ disabled */ +static snd_pcm_uframes_t +snd_ad1889_capture_pointer(snd_pcm_substream_t *ss) +{ + size_t ptr = 0; + struct snd_ad1889 *chip = snd_pcm_substream_chip(ss); + + if (unlikely(!(chip->ramc.reg & AD_DS_RAMC_ADEN))) + return 0; + + ptr = ad1889_readl(chip, AD_DMA_ADCCA); + ptr -= chip->ramc.addr; + + snd_assert((ptr >= 0) && (ptr < chip->ramc.size), return 0); + + return bytes_to_frames(ss->runtime, ptr); +} + +static snd_pcm_ops_t snd_ad1889_playback_ops = { + .open = snd_ad1889_playback_open, + .close = snd_ad1889_playback_close, + .ioctl = snd_pcm_lib_ioctl, + .hw_params = snd_ad1889_hw_params, + .hw_free = snd_ad1889_hw_free, + .prepare = snd_ad1889_playback_prepare, + .trigger = snd_ad1889_playback_trigger, + .pointer = snd_ad1889_playback_pointer, +}; + +static snd_pcm_ops_t snd_ad1889_capture_ops = { + .open = snd_ad1889_capture_open, + .close = snd_ad1889_capture_close, + .ioctl = snd_pcm_lib_ioctl, + .hw_params = snd_ad1889_hw_params, + .hw_free = snd_ad1889_hw_free, + .prepare = snd_ad1889_capture_prepare, + .trigger = snd_ad1889_capture_trigger, + .pointer = snd_ad1889_capture_pointer, +}; + +static irqreturn_t +snd_ad1889_interrupt(int irq, + void *dev_id, + struct pt_regs *regs) +{ + unsigned long st; + struct snd_ad1889 *chip = dev_id; + + st = ad1889_readl(chip, AD_DMA_DISR); + + /* clear ISR */ + ad1889_writel(chip, AD_DMA_DISR, st); + + st &= AD_INTR_MASK; + + if (unlikely(!st)) + return IRQ_NONE; + + if (st & (AD_DMA_DISR_PMAI|AD_DMA_DISR_PTAI)) + ad1889_debug("Unexpected master or target abort interrupt!\n"); + + if ((st & AD_DMA_DISR_WAVI) && chip->psubs) + snd_pcm_period_elapsed(chip->psubs); + if ((st & AD_DMA_DISR_ADCI) && chip->csubs) + snd_pcm_period_elapsed(chip->csubs); + + return IRQ_HANDLED; +} + +static void +snd_ad1889_pcm_free(snd_pcm_t *pcm) +{ + struct snd_ad1889 *chip = pcm->private_data; + chip->pcm = NULL; + snd_pcm_lib_preallocate_free_for_all(pcm); +} + +static int __devinit +snd_ad1889_pcm_init(struct snd_ad1889 *chip, int device, snd_pcm_t **rpcm) +{ + int err; + snd_pcm_t *pcm; + + if (rpcm) + *rpcm = NULL; + + err = snd_pcm_new(chip->card, chip->card->driver, device, 1, 1, &pcm); + if (err < 0) + return err; + + snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, + &snd_ad1889_playback_ops); + snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, + &snd_ad1889_capture_ops); + + pcm->private_data = chip; + pcm->private_free = snd_ad1889_pcm_free; + pcm->info_flags = 0; + strcpy(pcm->name, chip->card->shortname); + + chip->pcm = pcm; + chip->psubs = NULL; + chip->csubs = NULL; + + err = snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, + snd_dma_pci_data(chip->pci), + BUFFER_BYTES_MAX / 2, + BUFFER_BYTES_MAX); + + if (err < 0) { + snd_printk(KERN_ERR PFX "buffer allocation error: %d\n", err); + return err; + } + + if (rpcm) + *rpcm = pcm; + + return 0; +} + +static void +snd_ad1889_proc_read(snd_info_entry_t *entry, snd_info_buffer_t *buffer) +{ + struct snd_ad1889 *chip = entry->private_data; + u16 reg; + int tmp; + + reg = ad1889_readw(chip, AD_DS_WSMC); + snd_iprintf(buffer, "Wave output: %s\n", + (reg & AD_DS_WSMC_WAEN) ? "enabled" : "disabled"); + snd_iprintf(buffer, "Wave Channels: %s\n", + (reg & AD_DS_WSMC_WAST) ? "stereo" : "mono"); + snd_iprintf(buffer, "Wave Quality: %d-bit linear\n", + (reg & AD_DS_WSMC_WA16) ? 16 : 8); + + /* WARQ is at offset 12 */ + tmp = (reg & AD_DS_WSMC_WARQ) ? + (((reg & AD_DS_WSMC_WARQ >> 12) & 0x01) ? 12 : 18) : 4; + tmp /= (reg & AD_DS_WSMC_WAST) ? 2 : 1; + + snd_iprintf(buffer, "Wave FIFO: %d %s words\n\n", tmp, + (reg & AD_DS_WSMC_WAST) ? "stereo" : "mono"); + + + snd_iprintf(buffer, "Synthesis output: %s\n", + reg & AD_DS_WSMC_SYEN ? "enabled" : "disabled"); + + /* SYRQ is at offset 4 */ + tmp = (reg & AD_DS_WSMC_SYRQ) ? + (((reg & AD_DS_WSMC_SYRQ >> 4) & 0x01) ? 12 : 18) : 4; + tmp /= (reg & AD_DS_WSMC_WAST) ? 2 : 1; + + snd_iprintf(buffer, "Synthesis FIFO: %d %s words\n\n", tmp, + (reg & AD_DS_WSMC_WAST) ? "stereo" : "mono"); + + reg = ad1889_readw(chip, AD_DS_RAMC); + snd_iprintf(buffer, "ADC input: %s\n", + (reg & AD_DS_RAMC_ADEN) ? "enabled" : "disabled"); + snd_iprintf(buffer, "ADC Channels: %s\n", + (reg & AD_DS_RAMC_ADST) ? "stereo" : "mono"); + snd_iprintf(buffer, "ADC Quality: %d-bit linear\n", + (reg & AD_DS_RAMC_AD16) ? 16 : 8); + + /* ACRQ is at offset 4 */ + tmp = (reg & AD_DS_RAMC_ACRQ) ? + (((reg & AD_DS_RAMC_ACRQ >> 4) & 0x01) ? 12 : 18) : 4; + tmp /= (reg & AD_DS_RAMC_ADST) ? 2 : 1; + + snd_iprintf(buffer, "ADC FIFO: %d %s words\n\n", tmp, + (reg & AD_DS_RAMC_ADST) ? "stereo" : "mono"); + + snd_iprintf(buffer, "Resampler input: %s\n", + reg & AD_DS_RAMC_REEN ? "enabled" : "disabled"); + + /* RERQ is at offset 12 */ + tmp = (reg & AD_DS_RAMC_RERQ) ? + (((reg & AD_DS_RAMC_RERQ >> 12) & 0x01) ? 12 : 18) : 4; + tmp /= (reg & AD_DS_RAMC_ADST) ? 2 : 1; + + snd_iprintf(buffer, "Resampler FIFO: %d %s words\n\n", tmp, + (reg & AD_DS_WSMC_WAST) ? "stereo" : "mono"); + + + /* doc says LSB represents -1.5dB, but the max value (-94.5dB) + suggests that LSB is -3dB, which is more coherent with the logarithmic + nature of the dB scale */ + reg = ad1889_readw(chip, AD_DS_WADA); + snd_iprintf(buffer, "Left: %s, -%d dB\n", + (reg & AD_DS_WADA_LWAM) ? "mute" : "unmute", + ((reg & AD_DS_WADA_LWAA) >> 8) * 3); + reg = ad1889_readw(chip, AD_DS_WADA); + snd_iprintf(buffer, "Right: %s, -%d dB\n", + (reg & AD_DS_WADA_RWAM) ? "mute" : "unmute", + ((reg & AD_DS_WADA_RWAA) >> 8) * 3); + + reg = ad1889_readw(chip, AD_DS_WAS); + snd_iprintf(buffer, "Wave samplerate: %u Hz\n", reg); + reg = ad1889_readw(chip, AD_DS_RES); + snd_iprintf(buffer, "Resampler samplerate: %u Hz\n", reg); +} + +static void __devinit +snd_ad1889_proc_init(struct snd_ad1889 *chip) +{ + snd_info_entry_t *entry; + + if (!snd_card_proc_new(chip->card, chip->card->driver, &entry)) + snd_info_set_text_ops(entry, chip, 1024, snd_ad1889_proc_read); +} + +static struct ac97_quirk ac97_quirks[] = { + { + .subvendor = 0x11d4, /* AD */ + .subdevice = 0x1889, /* AD1889 */ + .codec_id = AC97_ID_AD1819, + .name = "AD1889", + .type = AC97_TUNE_HP_ONLY + }, + { } /* terminator */ +}; + +static void __devinit +snd_ad1889_ac97_xinit(struct snd_ad1889 *chip) +{ + u16 reg; + + reg = ad1889_readw(chip, AD_AC97_ACIC); + reg |= AD_AC97_ACIC_ACRD; /* Reset Disable */ + ad1889_writew(chip, AD_AC97_ACIC, reg); + ad1889_readw(chip, AD_AC97_ACIC); /* flush posted write */ + udelay(10); + /* Interface Enable */ + reg |= AD_AC97_ACIC_ACIE; + ad1889_writew(chip, AD_AC97_ACIC, reg); + + snd_ad1889_ac97_ready(chip); + + /* Audio Stream Output | Variable Sample Rate Mode */ + reg = ad1889_readw(chip, AD_AC97_ACIC); + reg |= AD_AC97_ACIC_ASOE | AD_AC97_ACIC_VSRM; + ad1889_writew(chip, AD_AC97_ACIC, reg); + ad1889_readw(chip, AD_AC97_ACIC); /* flush posted write */ + +} + +static void +snd_ad1889_ac97_bus_free(ac97_bus_t *bus) +{ + struct snd_ad1889 *chip = bus->private_data; + chip->ac97_bus = NULL; +} + +static void +snd_ad1889_ac97_free(ac97_t *ac97) +{ + struct snd_ad1889 *chip = ac97->private_data; + chip->ac97 = NULL; +} + +static int __devinit +snd_ad1889_ac97_init(struct snd_ad1889 *chip, const char *quirk_override) +{ + int err; + ac97_template_t ac97; + static ac97_bus_ops_t ops = { + .write = snd_ad1889_ac97_write, + .read = snd_ad1889_ac97_read, + }; + + /* doing that here, it works. */ + snd_ad1889_ac97_xinit(chip); + + err = snd_ac97_bus(chip->card, 0, &ops, chip, &chip->ac97_bus); + if (err < 0) + return err; + + chip->ac97_bus->private_free = snd_ad1889_ac97_bus_free; + + memset(&ac97, 0, sizeof(ac97)); + ac97.private_data = chip; + ac97.private_free = snd_ad1889_ac97_free; + ac97.pci = chip->pci; + + err = snd_ac97_mixer(chip->ac97_bus, &ac97, &chip->ac97); + if (err < 0) + return err; + + snd_ac97_tune_hardware(chip->ac97, ac97_quirks, quirk_override); + + return 0; +} + +static int +snd_ad1889_free(struct snd_ad1889 *chip) +{ + if (chip->irq < 0) + goto skip_hw; + + spin_lock_irq(&chip->lock); + + ad1889_mute(chip); + + /* Turn off interrupt on count and zero DMA registers */ + ad1889_channel_reset(chip, AD_CHAN_WAV | AD_CHAN_ADC); + + /* clear DISR. If we don't, we'd better jump off the Eiffel Tower */ + ad1889_writel(chip, AD_DMA_DISR, AD_DMA_DISR_PTAI | AD_DMA_DISR_PMAI); + ad1889_readl(chip, AD_DMA_DISR); /* flush, dammit! */ + + spin_unlock_irq(&chip->lock); + + synchronize_irq(chip->irq); + + if (chip->irq >= 0) + free_irq(chip->irq, (void*)chip); + +skip_hw: + if (chip->iobase) + iounmap(chip->iobase); + + pci_release_regions(chip->pci); + pci_disable_device(chip->pci); + + kfree(chip); + return 0; +} + +static inline int +snd_ad1889_dev_free(snd_device_t *device) +{ + struct snd_ad1889 *chip = device->device_data; + return snd_ad1889_free(chip); +} + +static int __devinit +snd_ad1889_init(struct snd_ad1889 *chip) +{ + ad1889_writew(chip, AD_DS_CCS, AD_DS_CCS_CLKEN); /* turn on clock */ + ad1889_readw(chip, AD_DS_CCS); /* flush posted write */ + + mdelay(10); + + /* enable Master and Target abort interrupts */ + ad1889_writel(chip, AD_DMA_DISR, AD_DMA_DISR_PMAE | AD_DMA_DISR_PTAE); + + return 0; +} + +static int __devinit +snd_ad1889_create(snd_card_t *card, + struct pci_dev *pci, + struct snd_ad1889 **rchip) +{ + int err; + + struct snd_ad1889 *chip; + static snd_device_ops_t ops = { + .dev_free = snd_ad1889_dev_free, + }; + + *rchip = NULL; + + if ((err = pci_enable_device(pci)) < 0) + return err; + + /* check PCI availability (32bit DMA) */ + if (pci_set_dma_mask(pci, 0xffffffff) < 0 || + pci_set_consistent_dma_mask(pci, 0xffffffff) < 0) { + printk(KERN_ERR PFX "error setting 32-bit DMA mask.\n"); + pci_disable_device(pci); + return -ENXIO; + } + + /* allocate chip specific data with zero-filled memory */ + if ((chip = kzalloc(sizeof(*chip), GFP_KERNEL)) == NULL) { + pci_disable_device(pci); + return -ENOMEM; + } + + chip->card = card; + card->private_data = chip; + chip->pci = pci; + chip->irq = -1; + + /* (1) PCI resource allocation */ + if ((err = pci_request_regions(pci, card->driver)) < 0) + goto free_and_ret; + + chip->bar = pci_resource_start(pci, 0); + chip->iobase = ioremap_nocache(chip->bar, pci_resource_len(pci, 0)); + if (chip->iobase == NULL) { + printk(KERN_ERR PFX "unable to reserve region.\n"); + err = -EBUSY; + goto free_and_ret; + } + + pci_set_master(pci); + + spin_lock_init(&chip->lock); /* only now can we call ad1889_free */ + + if (request_irq(pci->irq, snd_ad1889_interrupt, + SA_INTERRUPT|SA_SHIRQ, card->driver, (void*)chip)) { + printk(KERN_ERR PFX "cannot obtain IRQ %d\n", pci->irq); + snd_ad1889_free(chip); + return -EBUSY; + } + + chip->irq = pci->irq; + synchronize_irq(chip->irq); + + /* (2) initialization of the chip hardware */ + if ((err = snd_ad1889_init(chip)) < 0) { + snd_ad1889_free(chip); + return err; + } + + if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops)) < 0) { + snd_ad1889_free(chip); + return err; + } + + snd_card_set_dev(card, &pci->dev); + + *rchip = chip; + + return 0; + +free_and_ret: + if (chip) + kfree(chip); + pci_disable_device(pci); + + return err; +} + +static int __devinit +snd_ad1889_probe(struct pci_dev *pci, + const struct pci_device_id *pci_id) +{ + int err; + static int devno; + snd_card_t *card; + struct snd_ad1889 *chip; + + /* (1) */ + if (devno >= SNDRV_CARDS) + return -ENODEV; + if (!enable[devno]) { + devno++; + return -ENOENT; + } + + /* (2) */ + card = snd_card_new(index[devno], id[devno], THIS_MODULE, 0); + /* XXX REVISIT: we can probably allocate chip in this call */ + if (card == NULL) + return -ENOMEM; + + strcpy(card->driver, "AD1889"); + strcpy(card->shortname, "Analog Devices AD1889"); + + /* (3) */ + err = snd_ad1889_create(card, pci, &chip); + if (err < 0) + goto free_and_ret; + + /* (4) */ + sprintf(card->longname, "%s at 0x%lx irq %i", + card->shortname, chip->bar, chip->irq); + + /* (5) */ + /* register AC97 mixer */ + err = snd_ad1889_ac97_init(chip, ac97_quirk[devno]); + if (err < 0) + goto free_and_ret; + + err = snd_ad1889_pcm_init(chip, 0, NULL); + if (err < 0) + goto free_and_ret; + + /* register proc interface */ + snd_ad1889_proc_init(chip); + + /* (6) */ + err = snd_card_register(card); + if (err < 0) + goto free_and_ret; + + /* (7) */ + pci_set_drvdata(pci, card); + + devno++; + return 0; + +free_and_ret: + snd_card_free(card); + return err; +} + +static void __devexit +snd_ad1889_remove(struct pci_dev *pci) +{ + snd_card_free(pci_get_drvdata(pci)); + pci_set_drvdata(pci, NULL); +} + +static struct pci_device_id snd_ad1889_ids[] = { + { PCI_DEVICE(PCI_VENDOR_ID_ANALOG_DEVICES, PCI_DEVICE_ID_AD1889JS) }, + { 0, }, +}; +MODULE_DEVICE_TABLE(pci, snd_ad1889_ids); + +static struct pci_driver ad1889_pci = { + .name = "AD1889 Audio", + .owner = THIS_MODULE, + .id_table = snd_ad1889_ids, + .probe = snd_ad1889_probe, + .remove = __devexit_p(snd_ad1889_remove), +}; + +static int __init +alsa_ad1889_init(void) +{ + return pci_register_driver(&ad1889_pci); +} + +static void __exit +alsa_ad1889_fini(void) +{ + pci_unregister_driver(&ad1889_pci); +} + +module_init(alsa_ad1889_init); +module_exit(alsa_ad1889_fini); diff --git a/sound/pci/ad1889.h b/sound/pci/ad1889.h new file mode 100644 index 0000000..5e6dad5 --- /dev/null +++ b/sound/pci/ad1889.h @@ -0,0 +1,189 @@ +/* Analog Devices 1889 audio driver + * Copyright (C) 2004, Kyle McMartin <kyle@parisc-linux.org> + */ + +#ifndef __AD1889_H__ +#define __AD1889_H__ + +#define AD_DS_WSMC 0x00 /* wave/synthesis channel mixer control */ +#define AD_DS_WSMC_SYEN 0x0004 /* synthesis channel enable */ +#define AD_DS_WSMC_SYRQ 0x0030 /* synth. fifo request point */ +#define AD_DS_WSMC_WA16 0x0100 /* wave channel 16bit select */ +#define AD_DS_WSMC_WAST 0x0200 /* wave channel stereo select */ +#define AD_DS_WSMC_WAEN 0x0400 /* wave channel enable */ +#define AD_DS_WSMC_WARQ 0x3000 /* wave fifo request point */ + +#define AD_DS_RAMC 0x02 /* resampler/ADC channel mixer control */ +#define AD_DS_RAMC_AD16 0x0001 /* ADC channel 16bit select */ +#define AD_DS_RAMC_ADST 0x0002 /* ADC channel stereo select */ +#define AD_DS_RAMC_ADEN 0x0004 /* ADC channel enable */ +#define AD_DS_RAMC_ACRQ 0x0030 /* ADC fifo request point */ +#define AD_DS_RAMC_REEN 0x0400 /* resampler channel enable */ +#define AD_DS_RAMC_RERQ 0x3000 /* res. fifo request point */ + +#define AD_DS_WADA 0x04 /* wave channel mix attenuation */ +#define AD_DS_WADA_RWAM 0x0080 /* right wave mute */ +#define AD_DS_WADA_RWAA 0x001f /* right wave attenuation */ +#define AD_DS_WADA_LWAM 0x8000 /* left wave mute */ +#define AD_DS_WADA_LWAA 0x3e00 /* left wave attenuation */ + +#define AD_DS_SYDA 0x06 /* synthesis channel mix attenuation */ +#define AD_DS_SYDA_RSYM 0x0080 /* right synthesis mute */ +#define AD_DS_SYDA_RSYA 0x001f /* right synthesis attenuation */ +#define AD_DS_SYDA_LSYM 0x8000 /* left synthesis mute */ +#define AD_DS_SYDA_LSYA 0x3e00 /* left synthesis attenuation */ + +#define AD_DS_WAS 0x08 /* wave channel sample rate */ +#define AD_DS_WAS_WAS 0xffff /* sample rate mask */ + +#define AD_DS_RES 0x0a /* resampler channel sample rate */ +#define AD_DS_RES_RES 0xffff /* sample rate mask */ + +#define AD_DS_CCS 0x0c /* chip control/status */ +#define AD_DS_CCS_ADO 0x0001 /* ADC channel overflow */ +#define AD_DS_CCS_REO 0x0002 /* resampler channel overflow */ +#define AD_DS_CCS_SYU 0x0004 /* synthesis channel underflow */ +#define AD_DS_CCS_WAU 0x0008 /* wave channel underflow */ +/* bits 4 -> 7, 9, 11 -> 14 reserved */ +#define AD_DS_CCS_XTD 0x0100 /* xtd delay control (4096 clock cycles) */ +#define AD_DS_CCS_PDALL 0x0400 /* power */ +#define AD_DS_CCS_CLKEN 0x8000 /* clock */ + +#define AD_DMA_RESBA 0x40 /* RES base address */ +#define AD_DMA_RESCA 0x44 /* RES current address */ +#define AD_DMA_RESBC 0x48 /* RES base count */ +#define AD_DMA_RESCC 0x4c /* RES current count */ + +#define AD_DMA_ADCBA 0x50 /* ADC base address */ +#define AD_DMA_ADCCA 0x54 /* ADC current address */ +#define AD_DMA_ADCBC 0x58 /* ADC base count */ +#define AD_DMA_ADCCC 0x5c /* ADC current count */ + +#define AD_DMA_SYNBA 0x60 /* synth base address */ +#define AD_DMA_SYNCA 0x64 /* synth current address */ +#define AD_DMA_SYNBC 0x68 /* synth base count */ +#define AD_DMA_SYNCC 0x6c /* synth current count */ + +#define AD_DMA_WAVBA 0x70 /* wave base address */ +#define AD_DMA_WAVCA 0x74 /* wave current address */ +#define AD_DMA_WAVBC 0x78 /* wave base count */ +#define AD_DMA_WAVCC 0x7c /* wave current count */ + +#define AD_DMA_RESIC 0x80 /* RES dma interrupt current byte count */ +#define AD_DMA_RESIB 0x84 /* RES dma interrupt base byte count */ + +#define AD_DMA_ADCIC 0x88 /* ADC dma interrupt current byte count */ +#define AD_DMA_ADCIB 0x8c /* ADC dma interrupt base byte count */ + +#define AD_DMA_SYNIC 0x90 /* synth dma interrupt current byte count */ +#define AD_DMA_SYNIB 0x94 /* synth dma interrupt base byte count */ + +#define AD_DMA_WAVIC 0x98 /* wave dma interrupt current byte count */ +#define AD_DMA_WAVIB 0x9c /* wave dma interrupt base byte count */ + +#define AD_DMA_ICC 0xffffff /* current byte count mask */ +#define AD_DMA_IBC 0xffffff /* base byte count mask */ +/* bits 24 -> 31 reserved */ + +/* 4 bytes pad */ +#define AD_DMA_ADC 0xa8 /* ADC dma control and status */ +#define AD_DMA_SYNTH 0xb0 /* Synth dma control and status */ +#define AD_DMA_WAV 0xb8 /* wave dma control and status */ +#define AD_DMA_RES 0xa0 /* Resample dma control and status */ + +#define AD_DMA_SGDE 0x0001 /* SGD mode enable */ +#define AD_DMA_LOOP 0x0002 /* loop enable */ +#define AD_DMA_IM 0x000c /* interrupt mode mask */ +#define AD_DMA_IM_DIS (~AD_DMA_IM) /* disable */ +#define AD_DMA_IM_CNT 0x0004 /* interrupt on count */ +#define AD_DMA_IM_SGD 0x0008 /* interrupt on SGD flag */ +#define AD_DMA_IM_EOL 0x000c /* interrupt on End of Linked List */ +#define AD_DMA_SGDS 0x0030 /* SGD status */ +#define AD_DMA_SFLG 0x0040 /* SGD flag */ +#define AD_DMA_EOL 0x0080 /* SGD end of list */ +/* bits 8 -> 15 reserved */ + +#define AD_DMA_DISR 0xc0 /* dma interrupt status */ +#define AD_DMA_DISR_RESI 0x000001 /* resampler channel interrupt */ +#define AD_DMA_DISR_ADCI 0x000002 /* ADC channel interrupt */ +#define AD_DMA_DISR_SYNI 0x000004 /* synthesis channel interrupt */ +#define AD_DMA_DISR_WAVI 0x000008 /* wave channel interrupt */ +/* bits 4, 5 reserved */ +#define AD_DMA_DISR_SEPS 0x000040 /* serial eeprom status */ +/* bits 7 -> 13 reserved */ +#define AD_DMA_DISR_PMAI 0x004000 /* pci master abort interrupt */ +#define AD_DMA_DISR_PTAI 0x008000 /* pci target abort interrupt */ +#define AD_DMA_DISR_PTAE 0x010000 /* pci target abort interrupt enable */ +#define AD_DMA_DISR_PMAE 0x020000 /* pci master abort interrupt enable */ +/* bits 19 -> 31 reserved */ + +/* interrupt mask */ +#define AD_INTR_MASK (AD_DMA_DISR_RESI|AD_DMA_DISR_ADCI| \ + AD_DMA_DISR_WAVI|AD_DMA_DISR_SYNI| \ + AD_DMA_DISR_PMAI|AD_DMA_DISR_PTAI) + +#define AD_DMA_CHSS 0xc4 /* dma channel stop status */ +#define AD_DMA_CHSS_RESS 0x000001 /* resampler channel stopped */ +#define AD_DMA_CHSS_ADCS 0x000002 /* ADC channel stopped */ +#define AD_DMA_CHSS_SYNS 0x000004 /* synthesis channel stopped */ +#define AD_DMA_CHSS_WAVS 0x000008 /* wave channel stopped */ + +#define AD_GPIO_IPC 0xc8 /* gpio port control */ +#define AD_GPIO_OP 0xca /* gpio output port status */ +#define AD_GPIO_IP 0xcc /* gpio input port status */ + +#define AD_AC97_BASE 0x100 /* ac97 base register */ + +#define AD_AC97_RESET 0x100 /* reset */ + +#define AD_AC97_PWR_CTL 0x126 /* == AC97_POWERDOWN */ +#define AD_AC97_PWR_ADC 0x0001 /* ADC ready status */ +#define AD_AC97_PWR_DAC 0x0002 /* DAC ready status */ +#define AD_AC97_PWR_PR0 0x0100 /* PR0 (ADC) powerdown */ +#define AD_AC97_PWR_PR1 0x0200 /* PR1 (DAC) powerdown */ + +#define AD_MISC_CTL 0x176 /* misc control */ +#define AD_MISC_CTL_DACZ 0x8000 /* set for zero fill, unset for repeat */ +#define AD_MISC_CTL_ARSR 0x0001 /* set for SR1, unset for SR0 */ +#define AD_MISC_CTL_ALSR 0x0100 +#define AD_MISC_CTL_DLSR 0x0400 +#define AD_MISC_CTL_DRSR 0x0004 + +#define AD_AC97_SR0 0x178 /* sample rate 0, 0xbb80 == 48K */ +#define AD_AC97_SR0_48K 0xbb80 /* 48KHz */ +#define AD_AC97_SR1 0x17a /* sample rate 1 */ + +#define AD_AC97_ACIC 0x180 /* ac97 codec interface control */ +#define AD_AC97_ACIC_ACIE 0x0001 /* analog codec interface enable */ +#define AD_AC97_ACIC_ACRD 0x0002 /* analog codec reset disable */ +#define AD_AC97_ACIC_ASOE 0x0004 /* audio stream output enable */ +#define AD_AC97_ACIC_VSRM 0x0008 /* variable sample rate mode */ +#define AD_AC97_ACIC_FSDH 0x0100 /* force SDATA_OUT high */ +#define AD_AC97_ACIC_FSYH 0x0200 /* force sync high */ +#define AD_AC97_ACIC_ACRDY 0x8000 /* analog codec ready status */ +/* bits 10 -> 14 reserved */ + + +#define AD_DS_MEMSIZE 512 +#define AD_OPL_MEMSIZE 16 +#define AD_MIDI_MEMSIZE 16 + +#define AD_WAV_STATE 0 +#define AD_ADC_STATE 1 +#define AD_MAX_STATES 2 + +#define AD_CHAN_WAV 0x0001 +#define AD_CHAN_ADC 0x0002 +#define AD_CHAN_RES 0x0004 +#define AD_CHAN_SYN 0x0008 + + +/* The chip would support 4 GB buffers and 16 MB periods, + * but let's not overdo it ... */ +#define BUFFER_BYTES_MAX (256 * 1024) +#define PERIOD_BYTES_MIN 32 +#define PERIOD_BYTES_MAX (BUFFER_BYTES_MAX / 2) +#define PERIODS_MIN 2 +#define PERIODS_MAX (BUFFER_BYTES_MAX / PERIOD_BYTES_MIN) + +#endif /* __AD1889_H__ */ diff --git a/sound/pci/ali5451/ali5451.c b/sound/pci/ali5451/ali5451.c index 4943299..d683f77 100644 --- a/sound/pci/ali5451/ali5451.c +++ b/sound/pci/ali5451/ali5451.c @@ -78,15 +78,7 @@ MODULE_PARM_DESC(spdif, "Support SPDIF I/O"); * Constants definition */ -#ifndef PCI_VENDOR_ID_ALI -#define PCI_VENDOR_ID_ALI 0x10b9 -#endif - -#ifndef PCI_DEVICE_ID_ALI_5451 -#define PCI_DEVICE_ID_ALI_5451 0x5451 -#endif - -#define DEVICE_ID_ALI5451 ((PCI_VENDOR_ID_ALI<<16)|PCI_DEVICE_ID_ALI_5451) +#define DEVICE_ID_ALI5451 ((PCI_VENDOR_ID_AL<<16)|PCI_DEVICE_ID_AL_M5451) #define ALI_CHANNELS 32 @@ -326,13 +318,12 @@ static void ali_read_regs(ali_t *codec, int channel) static void ali_read_cfg(unsigned int vendor, unsigned deviceid) { unsigned int dwVal; - struct pci_dev *pci_dev = NULL; + struct pci_dev *pci_dev; int i,j; - - pci_dev = pci_find_device(vendor, deviceid, pci_dev); - if (pci_dev == NULL) - return ; + pci_dev = pci_get_device(vendor, deviceid, NULL); + if (pci_dev == NULL) + return ; printk("\nM%x PCI CFG\n", deviceid); printk(" "); @@ -349,6 +340,7 @@ static void ali_read_cfg(unsigned int vendor, unsigned deviceid) } printk("\n"); } + pci_dev_put(pci_dev); } static void ali_read_ac97regs(ali_t *codec, int secondary) { @@ -2116,6 +2108,8 @@ static int snd_ali_free(ali_t * codec) #ifdef CONFIG_PM kfree(codec->image); #endif + pci_dev_put(codec->pci_m1533); + pci_dev_put(codec->pci_m7101); kfree(codec); return 0; } @@ -2305,7 +2299,7 @@ static int __devinit snd_ali_create(snd_card_t * card, codec->chregs.data.ainten = 0x00; /* M1533: southbridge */ - pci_dev = pci_find_device(0x10b9, 0x1533, NULL); + pci_dev = pci_get_device(0x10b9, 0x1533, NULL); codec->pci_m1533 = pci_dev; if (! codec->pci_m1533) { snd_printk(KERN_ERR "ali5451: cannot find ALi 1533 chip.\n"); @@ -2313,7 +2307,7 @@ static int __devinit snd_ali_create(snd_card_t * card, return -ENODEV; } /* M7101: power management */ - pci_dev = pci_find_device(0x10b9, 0x7101, NULL); + pci_dev = pci_get_device(0x10b9, 0x7101, NULL); codec->pci_m7101 = pci_dev; if (! codec->pci_m7101 && codec->revision == ALI_5451_V02) { snd_printk(KERN_ERR "ali5451: cannot find ALi 7101 chip.\n"); @@ -2417,6 +2411,7 @@ static void __devexit snd_ali_remove(struct pci_dev *pci) static struct pci_driver driver = { .name = "ALI 5451", + .owner = THIS_MODULE, .id_table = snd_ali_ids, .probe = snd_ali_probe, .remove = __devexit_p(snd_ali_remove), diff --git a/sound/pci/als4000.c b/sound/pci/als4000.c index ca28b22..196ec1c 100644 --- a/sound/pci/als4000.c +++ b/sound/pci/als4000.c @@ -770,6 +770,7 @@ static void __devexit snd_card_als4000_remove(struct pci_dev *pci) static struct pci_driver driver = { .name = "ALS4000", + .owner = THIS_MODULE, .id_table = snd_als4000_ids, .probe = snd_card_als4000_probe, .remove = __devexit_p(snd_card_als4000_remove), diff --git a/sound/pci/atiixp.c b/sound/pci/atiixp.c index 188df08..241eacf 100644 --- a/sound/pci/atiixp.c +++ b/sound/pci/atiixp.c @@ -1453,6 +1453,7 @@ static int snd_atiixp_resume(snd_card_t *card) atiixp_dma_t *dma = &chip->dmas[i]; if (dma->substream && dma->suspended) { dma->ops->enable_dma(chip, 1); + dma->substream->ops->prepare(dma->substream); writel((u32)dma->desc_buf.addr | ATI_REG_LINKPTR_EN, chip->remap_addr + dma->ops->llp_offset); writel(dma->saved_curptr, chip->remap_addr + dma->ops->dt_cur); @@ -1530,7 +1531,7 @@ static int __devinit snd_atiixp_create(snd_card_t *card, if ((err = pci_enable_device(pci)) < 0) return err; - chip = kcalloc(1, sizeof(*chip), GFP_KERNEL); + chip = kzalloc(sizeof(*chip), GFP_KERNEL); if (chip == NULL) { pci_disable_device(pci); return -ENOMEM; @@ -1644,6 +1645,7 @@ static void __devexit snd_atiixp_remove(struct pci_dev *pci) static struct pci_driver driver = { .name = "ATI IXP AC97 controller", + .owner = THIS_MODULE, .id_table = snd_atiixp_ids, .probe = snd_atiixp_probe, .remove = __devexit_p(snd_atiixp_remove), diff --git a/sound/pci/atiixp_modem.c b/sound/pci/atiixp_modem.c index 8d20029..c1a239a 100644 --- a/sound/pci/atiixp_modem.c +++ b/sound/pci/atiixp_modem.c @@ -405,7 +405,7 @@ static int snd_atiixp_acquire_codec(atiixp_t *chip) while (atiixp_read(chip, PHYS_OUT_ADDR) & ATI_REG_PHYS_OUT_ADDR_EN) { if (! timeout--) { - snd_printk(KERN_WARNING "atiixp: codec acquire timeout\n"); + snd_printk(KERN_WARNING "atiixp-modem: codec acquire timeout\n"); return -EBUSY; } udelay(1); @@ -436,7 +436,7 @@ static unsigned short snd_atiixp_codec_read(atiixp_t *chip, unsigned short codec } while (--timeout); /* time out may happen during reset */ if (reg < 0x7c) - snd_printk(KERN_WARNING "atiixp: codec read timeout (reg %x)\n", reg); + snd_printk(KERN_WARNING "atiixp-modem: codec read timeout (reg %x)\n", reg); return 0xffff; } @@ -498,7 +498,7 @@ static int snd_atiixp_aclink_reset(atiixp_t *chip) do_delay(); atiixp_update(chip, CMD, ATI_REG_CMD_AC_RESET, ATI_REG_CMD_AC_RESET); if (--timeout) { - snd_printk(KERN_ERR "atiixp: codec reset timeout\n"); + snd_printk(KERN_ERR "atiixp-modem: codec reset timeout\n"); break; } } @@ -552,7 +552,7 @@ static int snd_atiixp_codec_detect(atiixp_t *chip) atiixp_write(chip, IER, 0); /* disable irqs */ if ((chip->codec_not_ready_bits & ALL_CODEC_NOT_READY) == ALL_CODEC_NOT_READY) { - snd_printk(KERN_ERR "atiixp: no codec detected!\n"); + snd_printk(KERN_ERR "atiixp-modem: no codec detected!\n"); return -ENXIO; } return 0; @@ -635,7 +635,7 @@ static void snd_atiixp_xrun_dma(atiixp_t *chip, atiixp_dma_t *dma) { if (! dma->substream || ! dma->running) return; - snd_printdd("atiixp: XRUN detected (DMA %d)\n", dma->ops->type); + snd_printdd("atiixp-modem: XRUN detected (DMA %d)\n", dma->ops->type); snd_pcm_stop(dma->substream, SNDRV_PCM_STATE_XRUN); } @@ -1081,14 +1081,14 @@ static int __devinit snd_atiixp_mixer_new(atiixp_t *chip, int clock) ac97.scaps = AC97_SCAP_SKIP_AUDIO; if ((err = snd_ac97_mixer(pbus, &ac97, &chip->ac97[i])) < 0) { chip->ac97[i] = NULL; /* to be sure */ - snd_printdd("atiixp: codec %d not available for modem\n", i); + snd_printdd("atiixp-modem: codec %d not available for modem\n", i); continue; } codec_count++; } if (! codec_count) { - snd_printk(KERN_ERR "atiixp: no codec available\n"); + snd_printk(KERN_ERR "atiixp-modem: no codec available\n"); return -ENODEV; } @@ -1159,7 +1159,7 @@ static void __devinit snd_atiixp_proc_init(atiixp_t *chip) { snd_info_entry_t *entry; - if (! snd_card_proc_new(chip->card, "atiixp", &entry)) + if (! snd_card_proc_new(chip->card, "atiixp-modem", &entry)) snd_info_set_text_ops(entry, chip, 1024, snd_atiixp_proc_read); } @@ -1208,7 +1208,7 @@ static int __devinit snd_atiixp_create(snd_card_t *card, if ((err = pci_enable_device(pci)) < 0) return err; - chip = kcalloc(1, sizeof(*chip), GFP_KERNEL); + chip = kzalloc(sizeof(*chip), GFP_KERNEL); if (chip == NULL) { pci_disable_device(pci); return -ENOMEM; @@ -1318,6 +1318,7 @@ static void __devexit snd_atiixp_remove(struct pci_dev *pci) static struct pci_driver driver = { .name = "ATI IXP MC97 controller", + .owner = THIS_MODULE, .id_table = snd_atiixp_ids, .probe = snd_atiixp_probe, .remove = __devexit_p(snd_atiixp_remove), diff --git a/sound/pci/au88x0/au88x0.c b/sound/pci/au88x0/au88x0.c index f6236c6..04b695d 100644 --- a/sound/pci/au88x0/au88x0.c +++ b/sound/pci/au88x0/au88x0.c @@ -79,19 +79,21 @@ static void vortex_fix_agp_bridge(struct pci_dev *via) static void __devinit snd_vortex_workaround(struct pci_dev *vortex, int fix) { - struct pci_dev *via; + struct pci_dev *via = NULL; /* autodetect if workarounds are required */ if (fix == 255) { /* VIA KT133 */ - via = pci_find_device(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8365_1, NULL); + via = pci_get_device(PCI_VENDOR_ID_VIA, + PCI_DEVICE_ID_VIA_8365_1, NULL); /* VIA Apollo */ if (via == NULL) { - via = pci_find_device(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C598_1, NULL); - } - /* AMD Irongate */ - if (via == NULL) { - via = pci_find_device(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_FE_GATE_7007, NULL); + via = pci_get_device(PCI_VENDOR_ID_VIA, + PCI_DEVICE_ID_VIA_82C598_1, NULL); + /* AMD Irongate */ + if (via == NULL) + via = pci_get_device(PCI_VENDOR_ID_AMD, + PCI_DEVICE_ID_AMD_FE_GATE_7007, NULL); } if (via) { printk(KERN_INFO CARD_NAME ": Activating latency workaround...\n"); @@ -101,13 +103,17 @@ static void __devinit snd_vortex_workaround(struct pci_dev *vortex, int fix) } else { if (fix & 0x1) vortex_fix_latency(vortex); - if ((fix & 0x2) && (via = pci_find_device(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8365_1, NULL))) + if ((fix & 0x2) && (via = pci_get_device(PCI_VENDOR_ID_VIA, + PCI_DEVICE_ID_VIA_8365_1, NULL))) vortex_fix_agp_bridge(via); - if ((fix & 0x4) && (via = pci_find_device(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C598_1, NULL))) + if ((fix & 0x4) && (via = pci_get_device(PCI_VENDOR_ID_VIA, + PCI_DEVICE_ID_VIA_82C598_1, NULL))) vortex_fix_agp_bridge(via); - if ((fix & 0x8) && (via = pci_find_device(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_FE_GATE_7007, NULL))) + if ((fix & 0x8) && (via = pci_get_device(PCI_VENDOR_ID_AMD, + PCI_DEVICE_ID_AMD_FE_GATE_7007, NULL))) vortex_fix_agp_bridge(via); } + pci_dev_put(via); } // component-destructor @@ -150,7 +156,7 @@ snd_vortex_create(snd_card_t * card, struct pci_dev *pci, vortex_t ** rchip) } pci_set_dma_mask(pci, VORTEX_DMA_MASK); - chip = kcalloc(1, sizeof(*chip), GFP_KERNEL); + chip = kzalloc(sizeof(*chip), GFP_KERNEL); if (chip == NULL) return -ENOMEM; @@ -367,6 +373,7 @@ static void __devexit snd_vortex_remove(struct pci_dev *pci) // pci_driver definition static struct pci_driver driver = { .name = CARD_NAME_SHORT, + .owner = THIS_MODULE, .id_table = snd_vortex_ids, .probe = snd_vortex_probe, .remove = __devexit_p(snd_vortex_remove), diff --git a/sound/pci/azt3328.c b/sound/pci/azt3328.c index 72bba7b..d5261bd 100644 --- a/sound/pci/azt3328.c +++ b/sound/pci/azt3328.c @@ -1345,7 +1345,7 @@ static int __devinit snd_azf3328_create(snd_card_t * card, if ((err = pci_enable_device(pci)) < 0) return err; - chip = kcalloc(1, sizeof(*chip), GFP_KERNEL); + chip = kzalloc(sizeof(*chip), GFP_KERNEL); if (chip == NULL) { pci_disable_device(pci); return -ENOMEM; @@ -1511,6 +1511,7 @@ static void __devexit snd_azf3328_remove(struct pci_dev *pci) static struct pci_driver driver = { .name = "AZF3328", + .owner = THIS_MODULE, .id_table = snd_azf3328_ids, .probe = snd_azf3328_probe, .remove = __devexit_p(snd_azf3328_remove), diff --git a/sound/pci/bt87x.c b/sound/pci/bt87x.c index c5557ea..2236c95 100644 --- a/sound/pci/bt87x.c +++ b/sound/pci/bt87x.c @@ -59,16 +59,6 @@ module_param(load_all, bool, 0444); MODULE_PARM_DESC(load_all, "Allow to load the non-whitelisted cards"); -#ifndef PCI_VENDOR_ID_BROOKTREE -#define PCI_VENDOR_ID_BROOKTREE 0x109e -#endif -#ifndef PCI_DEVICE_ID_BROOKTREE_878 -#define PCI_DEVICE_ID_BROOKTREE_878 0x0878 -#endif -#ifndef PCI_DEVICE_ID_BROOKTREE_879 -#define PCI_DEVICE_ID_BROOKTREE_879 0x0879 -#endif - /* register offsets */ #define REG_INT_STAT 0x100 /* interrupt status */ #define REG_INT_MASK 0x104 /* interrupt mask */ @@ -720,7 +710,7 @@ static int __devinit snd_bt87x_create(snd_card_t *card, if (err < 0) return err; - chip = kcalloc(1, sizeof(*chip), GFP_KERNEL); + chip = kzalloc(sizeof(*chip), GFP_KERNEL); if (!chip) { pci_disable_device(pci); return -ENOMEM; @@ -911,6 +901,7 @@ static struct pci_device_id snd_bt87x_default_ids[] = { static struct pci_driver driver = { .name = "Bt87x", + .owner = THIS_MODULE, .id_table = snd_bt87x_ids, .probe = snd_bt87x_probe, .remove = __devexit_p(snd_bt87x_remove), diff --git a/sound/pci/ca0106/ca0106_main.c b/sound/pci/ca0106/ca0106_main.c index 7e27bfc..ba07960 100644 --- a/sound/pci/ca0106/ca0106_main.c +++ b/sound/pci/ca0106/ca0106_main.c @@ -352,7 +352,7 @@ static int snd_ca0106_pcm_open_playback_channel(snd_pcm_substream_t *substream, snd_pcm_runtime_t *runtime = substream->runtime; int err; - epcm = kcalloc(1, sizeof(*epcm), GFP_KERNEL); + epcm = kzalloc(sizeof(*epcm), GFP_KERNEL); if (epcm == NULL) return -ENOMEM; @@ -419,7 +419,7 @@ static int snd_ca0106_pcm_open_capture_channel(snd_pcm_substream_t *substream, i snd_pcm_runtime_t *runtime = substream->runtime; int err; - epcm = kcalloc(1, sizeof(*epcm), GFP_KERNEL); + epcm = kzalloc(sizeof(*epcm), GFP_KERNEL); if (epcm == NULL) { snd_printk("open_capture_channel: failed epcm alloc\n"); return -ENOMEM; @@ -1144,7 +1144,7 @@ static int __devinit snd_ca0106_create(snd_card_t *card, return -ENXIO; } - chip = kcalloc(1, sizeof(*chip), GFP_KERNEL); + chip = kzalloc(sizeof(*chip), GFP_KERNEL); if (chip == NULL) { pci_disable_device(pci); return -ENOMEM; @@ -1390,6 +1390,7 @@ MODULE_DEVICE_TABLE(pci, snd_ca0106_ids); // pci_driver definition static struct pci_driver driver = { .name = "CA0106", + .owner = THIS_MODULE, .id_table = snd_ca0106_ids, .probe = snd_ca0106_probe, .remove = __devexit_p(snd_ca0106_remove), diff --git a/sound/pci/ca0106/ca0106_mixer.c b/sound/pci/ca0106/ca0106_mixer.c index b6b8882..c10e4a5 100644 --- a/sound/pci/ca0106/ca0106_mixer.c +++ b/sound/pci/ca0106/ca0106_mixer.c @@ -482,7 +482,7 @@ static int snd_ca0106_volume_put_feedback(snd_kcontrol_t * kcontrol, static snd_kcontrol_new_t snd_ca0106_volume_control_analog_front = { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Analog Front Volume", + .name = "Analog Front Playback Volume", .info = snd_ca0106_volume_info, .get = snd_ca0106_volume_get_analog_front, .put = snd_ca0106_volume_put_analog_front @@ -490,7 +490,7 @@ static snd_kcontrol_new_t snd_ca0106_volume_control_analog_front = static snd_kcontrol_new_t snd_ca0106_volume_control_analog_center_lfe = { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Analog Center/LFE Volume", + .name = "Analog Center/LFE Playback Volume", .info = snd_ca0106_volume_info, .get = snd_ca0106_volume_get_analog_center_lfe, .put = snd_ca0106_volume_put_analog_center_lfe @@ -498,7 +498,7 @@ static snd_kcontrol_new_t snd_ca0106_volume_control_analog_center_lfe = static snd_kcontrol_new_t snd_ca0106_volume_control_analog_unknown = { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Analog Side Volume", + .name = "Analog Side Playback Volume", .info = snd_ca0106_volume_info, .get = snd_ca0106_volume_get_analog_unknown, .put = snd_ca0106_volume_put_analog_unknown @@ -506,7 +506,7 @@ static snd_kcontrol_new_t snd_ca0106_volume_control_analog_unknown = static snd_kcontrol_new_t snd_ca0106_volume_control_analog_rear = { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Analog Rear Volume", + .name = "Analog Rear Playback Volume", .info = snd_ca0106_volume_info, .get = snd_ca0106_volume_get_analog_rear, .put = snd_ca0106_volume_put_analog_rear @@ -514,7 +514,7 @@ static snd_kcontrol_new_t snd_ca0106_volume_control_analog_rear = static snd_kcontrol_new_t snd_ca0106_volume_control_spdif_front = { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "SPDIF Front Volume", + .name = "SPDIF Front Playback Volume", .info = snd_ca0106_volume_info, .get = snd_ca0106_volume_get_spdif_front, .put = snd_ca0106_volume_put_spdif_front @@ -522,7 +522,7 @@ static snd_kcontrol_new_t snd_ca0106_volume_control_spdif_front = static snd_kcontrol_new_t snd_ca0106_volume_control_spdif_center_lfe = { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "SPDIF Center/LFE Volume", + .name = "SPDIF Center/LFE Playback Volume", .info = snd_ca0106_volume_info, .get = snd_ca0106_volume_get_spdif_center_lfe, .put = snd_ca0106_volume_put_spdif_center_lfe @@ -530,7 +530,7 @@ static snd_kcontrol_new_t snd_ca0106_volume_control_spdif_center_lfe = static snd_kcontrol_new_t snd_ca0106_volume_control_spdif_unknown = { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "SPDIF Unknown Volume", + .name = "SPDIF Unknown Playback Volume", .info = snd_ca0106_volume_info, .get = snd_ca0106_volume_get_spdif_unknown, .put = snd_ca0106_volume_put_spdif_unknown @@ -538,7 +538,7 @@ static snd_kcontrol_new_t snd_ca0106_volume_control_spdif_unknown = static snd_kcontrol_new_t snd_ca0106_volume_control_spdif_rear = { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "SPDIF Rear Volume", + .name = "SPDIF Rear Playback Volume", .info = snd_ca0106_volume_info, .get = snd_ca0106_volume_get_spdif_rear, .put = snd_ca0106_volume_put_spdif_rear @@ -547,7 +547,7 @@ static snd_kcontrol_new_t snd_ca0106_volume_control_spdif_rear = static snd_kcontrol_new_t snd_ca0106_volume_control_feedback = { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "CAPTURE feedback into PLAYBACK", + .name = "CAPTURE feedback Playback Volume", .info = snd_ca0106_volume_info, .get = snd_ca0106_volume_get_feedback, .put = snd_ca0106_volume_put_feedback diff --git a/sound/pci/cmipci.c b/sound/pci/cmipci.c index b098b51..1eb3315 100644 --- a/sound/pci/cmipci.c +++ b/sound/pci/cmipci.c @@ -79,13 +79,6 @@ module_param_array(joystick_port, int, NULL, 0444); MODULE_PARM_DESC(joystick_port, "Joystick port address."); #endif -#ifndef PCI_DEVICE_ID_CMEDIA_CM8738 -#define PCI_DEVICE_ID_CMEDIA_CM8738 0x0111 -#endif -#ifndef PCI_DEVICE_ID_CMEDIA_CM8738B -#define PCI_DEVICE_ID_CMEDIA_CM8738B 0x0112 -#endif - /* * CM8x38 registers definition */ @@ -348,25 +341,6 @@ MODULE_PARM_DESC(joystick_port, "Joystick port address."); /* - * pci ids - */ -#ifndef PCI_VENDOR_ID_CMEDIA -#define PCI_VENDOR_ID_CMEDIA 0x13F6 -#endif -#ifndef PCI_DEVICE_ID_CMEDIA_CM8338A -#define PCI_DEVICE_ID_CMEDIA_CM8338A 0x0100 -#endif -#ifndef PCI_DEVICE_ID_CMEDIA_CM8338B -#define PCI_DEVICE_ID_CMEDIA_CM8338B 0x0101 -#endif -#ifndef PCI_DEVICE_ID_CMEDIA_CM8738 -#define PCI_DEVICE_ID_CMEDIA_CM8738 0x0111 -#endif -#ifndef PCI_DEVICE_ID_CMEDIA_CM8738B -#define PCI_DEVICE_ID_CMEDIA_CM8738B 0x0112 -#endif - -/* * channels for playback / capture */ #define CM_CH_PLAY 0 @@ -2801,7 +2775,7 @@ static int __devinit snd_cmipci_create(snd_card_t *card, struct pci_dev *pci, if ((err = pci_enable_device(pci)) < 0) return err; - cm = kcalloc(1, sizeof(*cm), GFP_KERNEL); + cm = kzalloc(sizeof(*cm), GFP_KERNEL); if (cm == NULL) { pci_disable_device(pci); return -ENOMEM; @@ -3063,6 +3037,7 @@ static void __devexit snd_cmipci_remove(struct pci_dev *pci) static struct pci_driver driver = { .name = "C-Media PCI", + .owner = THIS_MODULE, .id_table = snd_cmipci_ids, .probe = snd_cmipci_probe, .remove = __devexit_p(snd_cmipci_remove), diff --git a/sound/pci/cs4281.c b/sound/pci/cs4281.c index c7a370d..dc87e01 100644 --- a/sound/pci/cs4281.c +++ b/sound/pci/cs4281.c @@ -57,17 +57,6 @@ module_param_array(dual_codec, bool, NULL, 0444); MODULE_PARM_DESC(dual_codec, "Secondary Codec ID (0 = disabled)."); /* - * - */ - -#ifndef PCI_VENDOR_ID_CIRRUS -#define PCI_VENDOR_ID_CIRRUS 0x1013 -#endif -#ifndef PCI_DEVICE_ID_CIRRUS_4281 -#define PCI_DEVICE_ID_CIRRUS_4281 0x6005 -#endif - -/* * Direct registers */ @@ -1394,7 +1383,7 @@ static int __devinit snd_cs4281_create(snd_card_t * card, *rchip = NULL; if ((err = pci_enable_device(pci)) < 0) return err; - chip = kcalloc(1, sizeof(*chip), GFP_KERNEL); + chip = kzalloc(sizeof(*chip), GFP_KERNEL); if (chip == NULL) { pci_disable_device(pci); return -ENOMEM; @@ -2119,6 +2108,7 @@ static int cs4281_resume(snd_card_t *card) static struct pci_driver driver = { .name = "CS4281", + .owner = THIS_MODULE, .id_table = snd_cs4281_ids, .probe = snd_cs4281_probe, .remove = __devexit_p(snd_cs4281_remove), diff --git a/sound/pci/cs46xx/cs46xx.c b/sound/pci/cs46xx/cs46xx.c index b9fff4e..32b4f84 100644 --- a/sound/pci/cs46xx/cs46xx.c +++ b/sound/pci/cs46xx/cs46xx.c @@ -163,6 +163,7 @@ static void __devexit snd_card_cs46xx_remove(struct pci_dev *pci) static struct pci_driver driver = { .name = "Sound Fusion CS46xx", + .owner = THIS_MODULE, .id_table = snd_cs46xx_ids, .probe = snd_card_cs46xx_probe, .remove = __devexit_p(snd_card_cs46xx_remove), diff --git a/sound/pci/cs46xx/cs46xx_lib.c b/sound/pci/cs46xx/cs46xx_lib.c index 4b05215..6e3855b 100644 --- a/sound/pci/cs46xx/cs46xx_lib.c +++ b/sound/pci/cs46xx/cs46xx_lib.c @@ -1304,7 +1304,7 @@ static int _cs46xx_playback_open_channel (snd_pcm_substream_t * substream,int pc cs46xx_pcm_t * cpcm; snd_pcm_runtime_t *runtime = substream->runtime; - cpcm = kcalloc(1, sizeof(*cpcm), GFP_KERNEL); + cpcm = kzalloc(sizeof(*cpcm), GFP_KERNEL); if (cpcm == NULL) return -ENOMEM; if (snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(chip->pci), @@ -3525,17 +3525,6 @@ static void amp_voyetra_4294(cs46xx_t *chip, int change) /* - * piix4 pci ids - */ -#ifndef PCI_VENDOR_ID_INTEL -#define PCI_VENDOR_ID_INTEL 0x8086 -#endif /* PCI_VENDOR_ID_INTEL */ - -#ifndef PCI_DEVICE_ID_INTEL_82371AB_3 -#define PCI_DEVICE_ID_INTEL_82371AB_3 0x7113 -#endif /* PCI_DEVICE_ID_INTEL_82371AB_3 */ - -/* * Handle the CLKRUN on a thinkpad. We must disable CLKRUN support * whenever we need to beat on the chip. * @@ -3548,7 +3537,7 @@ static void clkrun_hack(cs46xx_t *chip, int change) { u16 control, nval; - if (chip->acpi_dev == NULL) + if (!chip->acpi_port) return; chip->amplifier += change; @@ -3571,15 +3560,20 @@ static void clkrun_hack(cs46xx_t *chip, int change) */ static void clkrun_init(cs46xx_t *chip) { + struct pci_dev *pdev; u8 pp; - chip->acpi_dev = pci_find_device(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371AB_3, NULL); - if (chip->acpi_dev == NULL) + chip->acpi_port = 0; + + pdev = pci_get_device(PCI_VENDOR_ID_INTEL, + PCI_DEVICE_ID_INTEL_82371AB_3, NULL); + if (pdev == NULL) return; /* Not a thinkpad thats for sure */ /* Find the control port */ - pci_read_config_byte(chip->acpi_dev, 0x41, &pp); + pci_read_config_byte(pdev, 0x41, &pp); chip->acpi_port = pp << 8; + pci_dev_put(pdev); } @@ -3780,7 +3774,7 @@ int __devinit snd_cs46xx_create(snd_card_t * card, if ((err = pci_enable_device(pci)) < 0) return err; - chip = kcalloc(1, sizeof(*chip), GFP_KERNEL); + chip = kzalloc(sizeof(*chip), GFP_KERNEL); if (chip == NULL) { pci_disable_device(pci); return -ENOMEM; diff --git a/sound/pci/emu10k1/emu10k1.c b/sound/pci/emu10k1/emu10k1.c index fc377c4..b0e00f0 100644 --- a/sound/pci/emu10k1/emu10k1.c +++ b/sound/pci/emu10k1/emu10k1.c @@ -223,6 +223,7 @@ static void __devexit snd_card_emu10k1_remove(struct pci_dev *pci) static struct pci_driver driver = { .name = "EMU10K1_Audigy", + .owner = THIS_MODULE, .id_table = snd_emu10k1_ids, .probe = snd_card_emu10k1_probe, .remove = __devexit_p(snd_card_emu10k1_remove), diff --git a/sound/pci/emu10k1/emu10k1_main.c b/sound/pci/emu10k1/emu10k1_main.c index e69d5b7..e87e842 100644 --- a/sound/pci/emu10k1/emu10k1_main.c +++ b/sound/pci/emu10k1/emu10k1_main.c @@ -754,12 +754,11 @@ static emu_chip_details_t emu_chip_details[] = { .emu10k1_chip = 1, .ac97_chip = 1, .sblive51 = 1} , - /* Tested by alsa bugtrack user "hus" 12th Sept 2005 */ + /* Tested by alsa bugtrack user "hus" bug #1297 12th Aug 2005 */ {.vendor = 0x1102, .device = 0x0002, .subsystem = 0x80611102, - .driver = "EMU10K1", .name = "SBLive! Player 5.1 [SB0060]", + .driver = "EMU10K1", .name = "SBLive! Platinum 5.1 [SB0060]", .id = "Live", .emu10k1_chip = 1, - .ac97_chip = 1, .sblive51 = 1} , {.vendor = 0x1102, .device = 0x0002, .subsystem = 0x80511102, .driver = "EMU10K1", .name = "SBLive! Value [CT4850]", @@ -865,7 +864,7 @@ int __devinit snd_emu10k1_create(snd_card_t * card, if ((err = pci_enable_device(pci)) < 0) return err; - emu = kcalloc(1, sizeof(*emu), GFP_KERNEL); + emu = kzalloc(sizeof(*emu), GFP_KERNEL); if (emu == NULL) { pci_disable_device(pci); return -ENOMEM; diff --git a/sound/pci/emu10k1/emu10k1x.c b/sound/pci/emu10k1/emu10k1x.c index 52c7826..ad15755 100644 --- a/sound/pci/emu10k1/emu10k1x.c +++ b/sound/pci/emu10k1/emu10k1x.c @@ -395,7 +395,7 @@ static int snd_emu10k1x_playback_open(snd_pcm_substream_t *substream) if ((err = snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_BYTES, 64)) < 0) return err; - epcm = kcalloc(1, sizeof(*epcm), GFP_KERNEL); + epcm = kzalloc(sizeof(*epcm), GFP_KERNEL); if (epcm == NULL) return -ENOMEM; epcm->emu = chip; @@ -571,7 +571,7 @@ static int snd_emu10k1x_pcm_open_capture(snd_pcm_substream_t *substream) if ((err = snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_BYTES, 64)) < 0) return err; - epcm = kcalloc(1, sizeof(*epcm), GFP_KERNEL); + epcm = kzalloc(sizeof(*epcm), GFP_KERNEL); if (epcm == NULL) return -ENOMEM; @@ -920,7 +920,7 @@ static int __devinit snd_emu10k1x_create(snd_card_t *card, return -ENXIO; } - chip = kcalloc(1, sizeof(*chip), GFP_KERNEL); + chip = kzalloc(sizeof(*chip), GFP_KERNEL); if (chip == NULL) { pci_disable_device(pci); return -ENOMEM; @@ -1615,6 +1615,7 @@ MODULE_DEVICE_TABLE(pci, snd_emu10k1x_ids); // pci_driver definition static struct pci_driver driver = { .name = "EMU10K1X", + .owner = THIS_MODULE, .id_table = snd_emu10k1x_ids, .probe = snd_emu10k1x_probe, .remove = __devexit_p(snd_emu10k1x_remove), diff --git a/sound/pci/emu10k1/emufx.c b/sound/pci/emu10k1/emufx.c index 637c555..646b5d9 100644 --- a/sound/pci/emu10k1/emufx.c +++ b/sound/pci/emu10k1/emufx.c @@ -470,7 +470,7 @@ static void snd_emu10k1_write_op(emu10k1_fx8010_code_t *icode, unsigned int *ptr { u_int32_t *code; snd_assert(*ptr < 512, return); - code = (u_int32_t *)icode->code + (*ptr) * 2; + code = (u_int32_t __force *)icode->code + (*ptr) * 2; set_bit(*ptr, icode->code_valid); code[0] = ((x & 0x3ff) << 10) | (y & 0x3ff); code[1] = ((op & 0x0f) << 20) | ((r & 0x3ff) << 10) | (a & 0x3ff); @@ -485,7 +485,7 @@ static void snd_emu10k1_audigy_write_op(emu10k1_fx8010_code_t *icode, unsigned i { u_int32_t *code; snd_assert(*ptr < 1024, return); - code = (u_int32_t *)icode->code + (*ptr) * 2; + code = (u_int32_t __force *)icode->code + (*ptr) * 2; set_bit(*ptr, icode->code_valid); code[0] = ((x & 0x7ff) << 12) | (y & 0x7ff); code[1] = ((op & 0x0f) << 24) | ((r & 0x7ff) << 12) | (a & 0x7ff); @@ -1036,13 +1036,13 @@ static int __devinit _snd_emu10k1_audigy_init_efx(emu10k1_t *emu) spin_lock_init(&emu->fx8010.irq_lock); INIT_LIST_HEAD(&emu->fx8010.gpr_ctl); - if ((icode = kcalloc(1, sizeof(*icode), GFP_KERNEL)) == NULL || + if ((icode = kzalloc(sizeof(*icode), GFP_KERNEL)) == NULL || (icode->gpr_map = (u_int32_t __user *)kcalloc(512 + 256 + 256 + 2 * 1024, sizeof(u_int32_t), GFP_KERNEL)) == NULL || (controls = kcalloc(SND_EMU10K1_GPR_CONTROLS, sizeof(*controls), GFP_KERNEL)) == NULL) { err = -ENOMEM; goto __err; } - gpr_map = (u32 *)icode->gpr_map; + gpr_map = (u32 __force *)icode->gpr_map; icode->tram_data_map = icode->gpr_map + 512; icode->tram_addr_map = icode->tram_data_map + 256; @@ -1431,7 +1431,7 @@ A_OP(icode, &ptr, iMAC0, A_GPR(var), A_GPR(var), A_GPR(vol), A_EXTIN(input)) __err: kfree(controls); if (icode != NULL) { - kfree((void *)icode->gpr_map); + kfree((void __force *)icode->gpr_map); kfree(icode); } return err; @@ -1503,15 +1503,15 @@ static int __devinit _snd_emu10k1_init_efx(emu10k1_t *emu) spin_lock_init(&emu->fx8010.irq_lock); INIT_LIST_HEAD(&emu->fx8010.gpr_ctl); - if ((icode = kcalloc(1, sizeof(*icode), GFP_KERNEL)) == NULL) + if ((icode = kzalloc(sizeof(*icode), GFP_KERNEL)) == NULL) return -ENOMEM; if ((icode->gpr_map = (u_int32_t __user *)kcalloc(256 + 160 + 160 + 2 * 512, sizeof(u_int32_t), GFP_KERNEL)) == NULL || (controls = kcalloc(SND_EMU10K1_GPR_CONTROLS, sizeof(emu10k1_fx8010_control_gpr_t), GFP_KERNEL)) == NULL || - (ipcm = kcalloc(1, sizeof(*ipcm), GFP_KERNEL)) == NULL) { + (ipcm = kzalloc(sizeof(*ipcm), GFP_KERNEL)) == NULL) { err = -ENOMEM; goto __err; } - gpr_map = (u32 *)icode->gpr_map; + gpr_map = (u32 __force *)icode->gpr_map; icode->tram_data_map = icode->gpr_map + 256; icode->tram_addr_map = icode->tram_data_map + 160; @@ -2032,7 +2032,7 @@ static int __devinit _snd_emu10k1_init_efx(emu10k1_t *emu) kfree(ipcm); kfree(controls); if (icode != NULL) { - kfree((void *)icode->gpr_map); + kfree((void __force *)icode->gpr_map); kfree(icode); } return err; @@ -2217,7 +2217,7 @@ static int snd_emu10k1_fx8010_ioctl(snd_hwdep_t * hw, struct file *file, unsigne kfree(ipcm); return res; case SNDRV_EMU10K1_IOCTL_PCM_PEEK: - ipcm = kcalloc(1, sizeof(*ipcm), GFP_KERNEL); + ipcm = kzalloc(sizeof(*ipcm), GFP_KERNEL); if (ipcm == NULL) return -ENOMEM; if (copy_from_user(ipcm, argp, sizeof(*ipcm))) { diff --git a/sound/pci/emu10k1/emupcm.c b/sound/pci/emu10k1/emupcm.c index 9c35f6d..66ba27a 100644 --- a/sound/pci/emu10k1/emupcm.c +++ b/sound/pci/emu10k1/emupcm.c @@ -1016,7 +1016,7 @@ static int snd_emu10k1_efx_playback_open(snd_pcm_substream_t * substream) snd_pcm_runtime_t *runtime = substream->runtime; int i; - epcm = kcalloc(1, sizeof(*epcm), GFP_KERNEL); + epcm = kzalloc(sizeof(*epcm), GFP_KERNEL); if (epcm == NULL) return -ENOMEM; epcm->emu = emu; @@ -1049,7 +1049,7 @@ static int snd_emu10k1_playback_open(snd_pcm_substream_t * substream) snd_pcm_runtime_t *runtime = substream->runtime; int i, err; - epcm = kcalloc(1, sizeof(*epcm), GFP_KERNEL); + epcm = kzalloc(sizeof(*epcm), GFP_KERNEL); if (epcm == NULL) return -ENOMEM; epcm->emu = emu; @@ -1094,7 +1094,7 @@ static int snd_emu10k1_capture_open(snd_pcm_substream_t * substream) snd_pcm_runtime_t *runtime = substream->runtime; emu10k1_pcm_t *epcm; - epcm = kcalloc(1, sizeof(*epcm), GFP_KERNEL); + epcm = kzalloc(sizeof(*epcm), GFP_KERNEL); if (epcm == NULL) return -ENOMEM; epcm->emu = emu; @@ -1130,7 +1130,7 @@ static int snd_emu10k1_capture_mic_open(snd_pcm_substream_t * substream) emu10k1_pcm_t *epcm; snd_pcm_runtime_t *runtime = substream->runtime; - epcm = kcalloc(1, sizeof(*epcm), GFP_KERNEL); + epcm = kzalloc(sizeof(*epcm), GFP_KERNEL); if (epcm == NULL) return -ENOMEM; epcm->emu = emu; @@ -1170,7 +1170,7 @@ static int snd_emu10k1_capture_efx_open(snd_pcm_substream_t * substream) int nefx = emu->audigy ? 64 : 32; int idx; - epcm = kcalloc(1, sizeof(*epcm), GFP_KERNEL); + epcm = kzalloc(sizeof(*epcm), GFP_KERNEL); if (epcm == NULL) return -ENOMEM; epcm->emu = emu; diff --git a/sound/pci/emu10k1/p16v.c b/sound/pci/emu10k1/p16v.c index a169133..d59c7f3 100644 --- a/sound/pci/emu10k1/p16v.c +++ b/sound/pci/emu10k1/p16v.c @@ -178,7 +178,7 @@ static int snd_p16v_pcm_open_playback_channel(snd_pcm_substream_t *substream, in snd_pcm_runtime_t *runtime = substream->runtime; int err; - epcm = kcalloc(1, sizeof(*epcm), GFP_KERNEL); + epcm = kzalloc(sizeof(*epcm), GFP_KERNEL); //snd_printk("epcm kcalloc: %p\n", epcm); if (epcm == NULL) @@ -214,7 +214,7 @@ static int snd_p16v_pcm_open_capture_channel(snd_pcm_substream_t *substream, int snd_pcm_runtime_t *runtime = substream->runtime; int err; - epcm = kcalloc(1, sizeof(*epcm), GFP_KERNEL); + epcm = kzalloc(sizeof(*epcm), GFP_KERNEL); //snd_printk("epcm kcalloc: %p\n", epcm); if (epcm == NULL) diff --git a/sound/pci/ens1370.c b/sound/pci/ens1370.c index f06b95f..bef9a59 100644 --- a/sound/pci/ens1370.c +++ b/sound/pci/ens1370.c @@ -100,13 +100,6 @@ MODULE_PARM_DESC(joystick, "Enable joystick."); #endif #endif /* SUPPORT_JOYSTICK */ -#ifndef PCI_DEVICE_ID_ENSONIQ_CT5880 -#define PCI_DEVICE_ID_ENSONIQ_CT5880 0x5880 -#endif -#ifndef PCI_DEVICE_ID_ENSONIQ_ES1371 -#define PCI_DEVICE_ID_ENSONIQ_ES1371 0x1371 -#endif - /* ES1371 chip ID */ /* This is a little confusing because all ES1371 compatible chips have the same DEVICE_ID, the only thing differentiating them is the REV_ID field. @@ -1950,7 +1943,7 @@ static int __devinit snd_ensoniq_create(snd_card_t * card, *rensoniq = NULL; if ((err = pci_enable_device(pci)) < 0) return err; - ensoniq = kcalloc(1, sizeof(*ensoniq), GFP_KERNEL); + ensoniq = kzalloc(sizeof(*ensoniq), GFP_KERNEL); if (ensoniq == NULL) { pci_disable_device(pci); return -ENOMEM; @@ -2394,6 +2387,7 @@ static void __devexit snd_audiopci_remove(struct pci_dev *pci) static struct pci_driver driver = { .name = DRIVER_NAME, + .owner = THIS_MODULE, .id_table = snd_audiopci_ids, .probe = snd_audiopci_probe, .remove = __devexit_p(snd_audiopci_remove), diff --git a/sound/pci/es1938.c b/sound/pci/es1938.c index b492777..17fa80c 100644 --- a/sound/pci/es1938.c +++ b/sound/pci/es1938.c @@ -76,13 +76,6 @@ MODULE_SUPPORTED_DEVICE("{{ESS,ES1938}," #define SUPPORT_JOYSTICK 1 #endif -#ifndef PCI_VENDOR_ID_ESS -#define PCI_VENDOR_ID_ESS 0x125d -#endif -#ifndef PCI_DEVICE_ID_ESS_ES1938 -#define PCI_DEVICE_ID_ESS_ES1938 0x1969 -#endif - static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-MAX */ static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* ID for this card */ static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP; /* Enable this card */ @@ -1501,7 +1494,7 @@ static int __devinit snd_es1938_create(snd_card_t * card, return -ENXIO; } - chip = kcalloc(1, sizeof(*chip), GFP_KERNEL); + chip = kzalloc(sizeof(*chip), GFP_KERNEL); if (chip == NULL) { pci_disable_device(pci); return -ENOMEM; @@ -1753,6 +1746,7 @@ static void __devexit snd_es1938_remove(struct pci_dev *pci) static struct pci_driver driver = { .name = "ESS ES1938 (Solo-1)", + .owner = THIS_MODULE, .id_table = snd_es1938_ids, .probe = snd_es1938_probe, .remove = __devexit_p(snd_es1938_remove), diff --git a/sound/pci/es1968.c b/sound/pci/es1968.c index 9d7a287..ecdcada 100644 --- a/sound/pci/es1968.c +++ b/sound/pci/es1968.c @@ -160,25 +160,6 @@ MODULE_PARM_DESC(joystick, "Enable joystick."); #endif -/* PCI Dev ID's */ - -#ifndef PCI_VENDOR_ID_ESS -#define PCI_VENDOR_ID_ESS 0x125D -#endif - -#define PCI_VENDOR_ID_ESS_OLD 0x1285 /* Platform Tech, the people the ESS - was bought form */ - -#ifndef PCI_DEVICE_ID_ESS_M2E -#define PCI_DEVICE_ID_ESS_M2E 0x1978 -#endif -#ifndef PCI_DEVICE_ID_ESS_M2 -#define PCI_DEVICE_ID_ESS_M2 0x1968 -#endif -#ifndef PCI_DEVICE_ID_ESS_M1 -#define PCI_DEVICE_ID_ESS_M1 0x0100 -#endif - #define NR_APUS 64 #define NR_APU_REGS 16 @@ -1596,7 +1577,7 @@ static int snd_es1968_playback_open(snd_pcm_substream_t *substream) if (apu1 < 0) return apu1; - es = kcalloc(1, sizeof(*es), GFP_KERNEL); + es = kzalloc(sizeof(*es), GFP_KERNEL); if (!es) { snd_es1968_free_apu_pair(chip, apu1); return -ENOMEM; @@ -1641,7 +1622,7 @@ static int snd_es1968_capture_open(snd_pcm_substream_t *substream) return apu2; } - es = kcalloc(1, sizeof(*es), GFP_KERNEL); + es = kzalloc(sizeof(*es), GFP_KERNEL); if (!es) { snd_es1968_free_apu_pair(chip, apu1); snd_es1968_free_apu_pair(chip, apu2); @@ -2588,7 +2569,7 @@ static int __devinit snd_es1968_create(snd_card_t * card, return -ENXIO; } - chip = kcalloc(1, sizeof(*chip), GFP_KERNEL); + chip = kzalloc(sizeof(*chip), GFP_KERNEL); if (! chip) { pci_disable_device(pci); return -ENOMEM; @@ -2782,6 +2763,7 @@ static void __devexit snd_es1968_remove(struct pci_dev *pci) static struct pci_driver driver = { .name = "ES1968 (ESS Maestro)", + .owner = THIS_MODULE, .id_table = snd_es1968_ids, .probe = snd_es1968_probe, .remove = __devexit_p(snd_es1968_remove), diff --git a/sound/pci/fm801.c b/sound/pci/fm801.c index 36b2f62..e5cfa2a 100644 --- a/sound/pci/fm801.c +++ b/sound/pci/fm801.c @@ -1263,7 +1263,7 @@ static int __devinit snd_fm801_create(snd_card_t * card, *rchip = NULL; if ((err = pci_enable_device(pci)) < 0) return err; - chip = kcalloc(1, sizeof(*chip), GFP_KERNEL); + chip = kzalloc(sizeof(*chip), GFP_KERNEL); if (chip == NULL) { pci_disable_device(pci); return -ENOMEM; @@ -1462,6 +1462,7 @@ static void __devexit snd_card_fm801_remove(struct pci_dev *pci) static struct pci_driver driver = { .name = "FM801", + .owner = THIS_MODULE, .id_table = snd_fm801_ids, .probe = snd_card_fm801_probe, .remove = __devexit_p(snd_card_fm801_remove), diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index 20f7762..3815403 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c @@ -288,7 +288,7 @@ static int init_unsol_queue(struct hda_bus *bus) { struct hda_bus_unsolicited *unsol; - unsol = kcalloc(1, sizeof(*unsol), GFP_KERNEL); + unsol = kzalloc(sizeof(*unsol), GFP_KERNEL); if (! unsol) { snd_printk(KERN_ERR "hda_codec: can't allocate unsolicited queue\n"); return -ENOMEM; @@ -358,7 +358,7 @@ int snd_hda_bus_new(snd_card_t *card, const struct hda_bus_template *temp, if (busp) *busp = NULL; - bus = kcalloc(1, sizeof(*bus), GFP_KERNEL); + bus = kzalloc(sizeof(*bus), GFP_KERNEL); if (bus == NULL) { snd_printk(KERN_ERR "can't allocate struct hda_bus\n"); return -ENOMEM; @@ -493,7 +493,7 @@ int snd_hda_codec_new(struct hda_bus *bus, unsigned int codec_addr, return -EBUSY; } - codec = kcalloc(1, sizeof(*codec), GFP_KERNEL); + codec = kzalloc(sizeof(*codec), GFP_KERNEL); if (codec == NULL) { snd_printk(KERN_ERR "can't allocate struct hda_codec\n"); return -ENOMEM; diff --git a/sound/pci/hda/hda_codec.h b/sound/pci/hda/hda_codec.h index 63a29a8..bb53bcf 100644 --- a/sound/pci/hda/hda_codec.h +++ b/sound/pci/hda/hda_codec.h @@ -505,6 +505,7 @@ struct hda_pcm_stream { struct hda_pcm { char *name; struct hda_pcm_stream stream[2]; + unsigned int is_modem; /* modem codec? */ }; /* codec information */ diff --git a/sound/pci/hda/hda_generic.c b/sound/pci/hda/hda_generic.c index 1229227..5b829a1 100644 --- a/sound/pci/hda/hda_generic.c +++ b/sound/pci/hda/hda_generic.c @@ -98,7 +98,7 @@ static int add_new_node(struct hda_codec *codec, struct hda_gspec *spec, hda_nid struct hda_gnode *node; int nconns; - node = kcalloc(1, sizeof(*node), GFP_KERNEL); + node = kzalloc(sizeof(*node), GFP_KERNEL); if (node == NULL) return -ENOMEM; node->nid = nid; @@ -886,7 +886,7 @@ int snd_hda_parse_generic_codec(struct hda_codec *codec) return -ENODEV; } - spec = kcalloc(1, sizeof(*spec), GFP_KERNEL); + spec = kzalloc(sizeof(*spec), GFP_KERNEL); if (spec == NULL) { printk(KERN_ERR "hda_generic: can't allocate spec\n"); return -ENOMEM; diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index 15107df..9590ece 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c @@ -62,7 +62,7 @@ MODULE_PARM_DESC(enable, "Enable Intel HD audio interface."); module_param_array(model, charp, NULL, 0444); MODULE_PARM_DESC(model, "Use the given board model."); module_param_array(position_fix, int, NULL, 0444); -MODULE_PARM_DESC(position_fix, "Fix DMA pointer (0 = FIFO size, 1 = none, 2 = POSBUF)."); +MODULE_PARM_DESC(position_fix, "Fix DMA pointer (0 = auto, 1 = none, 2 = POSBUF, 3 = FIFO size)."); MODULE_LICENSE("GPL"); MODULE_SUPPORTED_DEVICE("{{Intel, ICH6}," @@ -164,7 +164,9 @@ enum { SDI0, SDI1, SDI2, SDI3, SDO0, SDO1, SDO2, SDO3 }; /* max buffer size - no h/w limit, you can increase as you like */ #define AZX_MAX_BUF_SIZE (1024*1024*1024) /* max number of PCM devics per card */ -#define AZX_MAX_PCMS 8 +#define AZX_MAX_AUDIO_PCMS 6 +#define AZX_MAX_MODEM_PCMS 2 +#define AZX_MAX_PCMS (AZX_MAX_AUDIO_PCMS + AZX_MAX_MODEM_PCMS) /* RIRB int mask: overrun[2], response[0] */ #define RIRB_INT_RESPONSE 0x01 @@ -211,9 +213,10 @@ enum { SDI0, SDI1, SDI2, SDI3, SDO0, SDO1, SDO2, SDO3 }; /* position fix mode */ enum { - POS_FIX_FIFO, + POS_FIX_AUTO, POS_FIX_NONE, - POS_FIX_POSBUF + POS_FIX_POSBUF, + POS_FIX_FIFO, }; /* Defines for ATI HD Audio support in SB450 south bridge */ @@ -243,6 +246,7 @@ struct snd_azx_dev { unsigned int fragsize; /* size of each period in bytes */ unsigned int frags; /* number for period in the play buffer */ unsigned int fifo_size; /* FIFO size */ + unsigned int last_pos; /* last updated period position */ void __iomem *sd_addr; /* stream descriptor pointer */ @@ -256,6 +260,7 @@ struct snd_azx_dev { unsigned int opened: 1; unsigned int running: 1; + unsigned int period_updating: 1; }; /* CORB/RIRB */ @@ -724,11 +729,9 @@ static void azx_init_chip(azx_t *chip) /* initialize the codec command I/O */ azx_init_cmd_io(chip); - if (chip->position_fix == POS_FIX_POSBUF) { - /* program the position buffer */ - azx_writel(chip, DPLBASE, (u32)chip->posbuf.addr); - azx_writel(chip, DPUBASE, upper_32bit(chip->posbuf.addr)); - } + /* program the position buffer */ + azx_writel(chip, DPLBASE, (u32)chip->posbuf.addr); + azx_writel(chip, DPUBASE, upper_32bit(chip->posbuf.addr)); /* For ATI SB450 azalia HD audio, we need to enable snoop */ if (chip->driver_type == AZX_DRIVER_ATI) { @@ -763,9 +766,11 @@ static irqreturn_t azx_interrupt(int irq, void* dev_id, struct pt_regs *regs) if (status & azx_dev->sd_int_sta_mask) { azx_sd_writeb(azx_dev, SD_STS, SD_INT_MASK); if (azx_dev->substream && azx_dev->running) { + azx_dev->period_updating = 1; spin_unlock(&chip->reg_lock); snd_pcm_period_elapsed(azx_dev->substream); spin_lock(&chip->reg_lock); + azx_dev->period_updating = 0; } } } @@ -866,11 +871,9 @@ static int azx_setup_controller(azx_t *chip, azx_dev_t *azx_dev) /* upper BDL address */ azx_sd_writel(azx_dev, SD_BDLPU, upper_32bit(azx_dev->bdl_addr)); - if (chip->position_fix == POS_FIX_POSBUF) { - /* enable the position buffer */ - if (! (azx_readl(chip, DPLBASE) & ICH6_DPLBASE_ENABLE)) - azx_writel(chip, DPLBASE, (u32)chip->posbuf.addr | ICH6_DPLBASE_ENABLE); - } + /* enable the position buffer */ + if (! (azx_readl(chip, DPLBASE) & ICH6_DPLBASE_ENABLE)) + azx_writel(chip, DPLBASE, (u32)chip->posbuf.addr | ICH6_DPLBASE_ENABLE); /* set the interrupt enable bits in the descriptor control register */ azx_sd_writel(azx_dev, SD_CTL, azx_sd_readl(azx_dev, SD_CTL) | SD_INT_MASK); @@ -1078,6 +1081,7 @@ static int azx_pcm_prepare(snd_pcm_substream_t *substream) azx_dev->fifo_size = azx_sd_readw(azx_dev, SD_FIFOSIZE) + 1; else azx_dev->fifo_size = 0; + azx_dev->last_pos = 0; return hinfo->ops.prepare(hinfo, apcm->codec, azx_dev->stream_tag, azx_dev->format_val, substream); @@ -1133,6 +1137,26 @@ static snd_pcm_uframes_t azx_pcm_pointer(snd_pcm_substream_t *substream) pos = azx_sd_readl(azx_dev, SD_LPIB); if (chip->position_fix == POS_FIX_FIFO) pos += azx_dev->fifo_size; + else if (chip->position_fix == POS_FIX_AUTO && azx_dev->period_updating) { + /* check the validity of DMA position */ + unsigned int diff = 0; + azx_dev->last_pos += azx_dev->fragsize; + if (azx_dev->last_pos > pos) + diff = azx_dev->last_pos - pos; + if (azx_dev->last_pos >= azx_dev->bufsize) { + if (pos < azx_dev->fragsize) + diff = 0; + azx_dev->last_pos = 0; + } + if (diff > 0 && diff <= azx_dev->fifo_size) + pos += azx_dev->fifo_size; + else { + snd_printdd(KERN_INFO "hda_intel: DMA position fix %d, switching to posbuf\n", diff); + chip->position_fix = POS_FIX_POSBUF; + pos = *azx_dev->posbuf; + } + azx_dev->period_updating = 0; + } } if (pos >= azx_dev->bufsize) pos = 0; @@ -1203,12 +1227,33 @@ static int __devinit azx_pcm_create(azx_t *chip) if ((err = snd_hda_build_pcms(chip->bus)) < 0) return err; + /* create audio PCMs */ pcm_dev = 0; list_for_each(p, &chip->bus->codec_list) { codec = list_entry(p, struct hda_codec, list); for (c = 0; c < codec->num_pcms; c++) { + if (codec->pcm_info[c].is_modem) + continue; /* create later */ + if (pcm_dev >= AZX_MAX_AUDIO_PCMS) { + snd_printk(KERN_ERR SFX "Too many audio PCMs\n"); + return -EINVAL; + } + err = create_codec_pcm(chip, codec, &codec->pcm_info[c], pcm_dev); + if (err < 0) + return err; + pcm_dev++; + } + } + + /* create modem PCMs */ + pcm_dev = AZX_MAX_AUDIO_PCMS; + list_for_each(p, &chip->bus->codec_list) { + codec = list_entry(p, struct hda_codec, list); + for (c = 0; c < codec->num_pcms; c++) { + if (! codec->pcm_info[c].is_modem) + continue; /* already created */ if (pcm_dev >= AZX_MAX_PCMS) { - snd_printk(KERN_ERR SFX "Too many PCMs\n"); + snd_printk(KERN_ERR SFX "Too many modem PCMs\n"); return -EINVAL; } err = create_codec_pcm(chip, codec, &codec->pcm_info[c], pcm_dev); @@ -1244,8 +1289,7 @@ static int __devinit azx_init_stream(azx_t *chip) azx_dev_t *azx_dev = &chip->azx_dev[i]; azx_dev->bdl = (u32 *)(chip->bdl.area + off); azx_dev->bdl_addr = chip->bdl.addr + off; - if (chip->position_fix == POS_FIX_POSBUF) - azx_dev->posbuf = (volatile u32 *)(chip->posbuf.area + i * 8); + azx_dev->posbuf = (volatile u32 *)(chip->posbuf.area + i * 8); /* offset: SDI0=0x80, SDI1=0xa0, ... SDO3=0x160 */ azx_dev->sd_addr = chip->remap_addr + (0x20 * i + 0x80); /* int mask: SDI0=0x01, SDI1=0x02, ... SDO3=0x80 */ @@ -1358,7 +1402,7 @@ static int __devinit azx_create(snd_card_t *card, struct pci_dev *pci, if ((err = pci_enable_device(pci)) < 0) return err; - chip = kcalloc(1, sizeof(*chip), GFP_KERNEL); + chip = kzalloc(sizeof(*chip), GFP_KERNEL); if (NULL == chip) { snd_printk(KERN_ERR SFX "cannot allocate chip\n"); @@ -1437,13 +1481,11 @@ static int __devinit azx_create(snd_card_t *card, struct pci_dev *pci, snd_printk(KERN_ERR SFX "cannot allocate BDL\n"); goto errout; } - if (chip->position_fix == POS_FIX_POSBUF) { - /* allocate memory for the position buffer */ - if ((err = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(chip->pci), - chip->num_streams * 8, &chip->posbuf)) < 0) { - snd_printk(KERN_ERR SFX "cannot allocate posbuf\n"); - goto errout; - } + /* allocate memory for the position buffer */ + if ((err = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(chip->pci), + chip->num_streams * 8, &chip->posbuf)) < 0) { + snd_printk(KERN_ERR SFX "cannot allocate posbuf\n"); + goto errout; } /* allocate CORB/RIRB */ if ((err = azx_alloc_cmd_io(chip)) < 0) @@ -1561,6 +1603,7 @@ MODULE_DEVICE_TABLE(pci, azx_ids); /* pci_driver definition */ static struct pci_driver driver = { .name = "HDA Intel", + .owner = THIS_MODULE, .id_table = azx_ids, .probe = azx_probe, .remove = __devexit_p(azx_remove), diff --git a/sound/pci/hda/hda_proc.c b/sound/pci/hda/hda_proc.c index de1217b..08f6a6e 100644 --- a/sound/pci/hda/hda_proc.c +++ b/sound/pci/hda/hda_proc.c @@ -207,6 +207,8 @@ static void print_codec_info(snd_info_entry_t *entry, snd_info_buffer_t *buffer) snd_iprintf(buffer, "Vendor Id: 0x%x\n", codec->vendor_id); snd_iprintf(buffer, "Subsystem Id: 0x%x\n", codec->subsystem_id); snd_iprintf(buffer, "Revision Id: 0x%x\n", codec->revision_id); + if (! codec->afg) + return; snd_iprintf(buffer, "Default PCM: "); print_pcm_caps(buffer, codec, codec->afg); snd_iprintf(buffer, "Default Amp-In caps: "); diff --git a/sound/pci/hda/patch_analog.c b/sound/pci/hda/patch_analog.c index bceb83a..da6874d 100644 --- a/sound/pci/hda/patch_analog.c +++ b/sound/pci/hda/patch_analog.c @@ -465,7 +465,7 @@ static int patch_ad1986a(struct hda_codec *codec) { struct ad198x_spec *spec; - spec = kcalloc(1, sizeof(*spec), GFP_KERNEL); + spec = kzalloc(sizeof(*spec), GFP_KERNEL); if (spec == NULL) return -ENOMEM; @@ -623,7 +623,7 @@ static int patch_ad1983(struct hda_codec *codec) { struct ad198x_spec *spec; - spec = kcalloc(1, sizeof(*spec), GFP_KERNEL); + spec = kzalloc(sizeof(*spec), GFP_KERNEL); if (spec == NULL) return -ENOMEM; @@ -764,7 +764,7 @@ static int patch_ad1981(struct hda_codec *codec) { struct ad198x_spec *spec; - spec = kcalloc(1, sizeof(*spec), GFP_KERNEL); + spec = kzalloc(sizeof(*spec), GFP_KERNEL); if (spec == NULL) return -ENOMEM; diff --git a/sound/pci/hda/patch_cmedia.c b/sound/pci/hda/patch_cmedia.c index 07fb4f5..523c362 100644 --- a/sound/pci/hda/patch_cmedia.c +++ b/sound/pci/hda/patch_cmedia.c @@ -667,7 +667,7 @@ static int patch_cmi9880(struct hda_codec *codec) { struct cmi_spec *spec; - spec = kcalloc(1, sizeof(*spec), GFP_KERNEL); + spec = kzalloc(sizeof(*spec), GFP_KERNEL); if (spec == NULL) return -ENOMEM; diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index eeb900a..849b5b5 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -1526,6 +1526,7 @@ static struct hda_board_config alc880_cfg_tbl[] = { /* Back 3 jack, front 2 jack (Internal add Aux-In) */ { .pci_subvendor = 0x1025, .pci_subdevice = 0xe310, .config = ALC880_3ST }, { .pci_subvendor = 0x104d, .pci_subdevice = 0x81d6, .config = ALC880_3ST }, + { .pci_subvendor = 0x104d, .pci_subdevice = 0x81a0, .config = ALC880_3ST }, /* Back 3 jack plus 1 SPDIF out jack, front 2 jack */ { .modelname = "3stack-digout", .config = ALC880_3ST_DIG }, @@ -1581,6 +1582,7 @@ static struct hda_board_config alc880_cfg_tbl[] = { { .pci_subvendor = 0x1043, .pci_subdevice = 0x1973, .config = ALC880_ASUS_DIG }, { .pci_subvendor = 0x1043, .pci_subdevice = 0x19b3, .config = ALC880_ASUS_DIG }, { .pci_subvendor = 0x1043, .pci_subdevice = 0x1113, .config = ALC880_ASUS_DIG }, + { .pci_subvendor = 0x1043, .pci_subdevice = 0x1173, .config = ALC880_ASUS_DIG }, { .pci_subvendor = 0x1043, .pci_subdevice = 0x1993, .config = ALC880_ASUS }, { .pci_subvendor = 0x1043, .pci_subdevice = 0x10c3, .config = ALC880_ASUS_DIG }, { .pci_subvendor = 0x1043, .pci_subdevice = 0x1133, .config = ALC880_ASUS }, @@ -2093,7 +2095,7 @@ static int patch_alc880(struct hda_codec *codec) int board_config; int i, err; - spec = kcalloc(1, sizeof(*spec), GFP_KERNEL); + spec = kzalloc(sizeof(*spec), GFP_KERNEL); if (spec == NULL) return -ENOMEM; @@ -2365,7 +2367,7 @@ static int patch_alc260(struct hda_codec *codec) struct alc_spec *spec; int board_config; - spec = kcalloc(1, sizeof(*spec), GFP_KERNEL); + spec = kzalloc(sizeof(*spec), GFP_KERNEL); if (spec == NULL) return -ENOMEM; @@ -2615,7 +2617,7 @@ static int patch_alc882(struct hda_codec *codec) { struct alc_spec *spec; - spec = kcalloc(1, sizeof(*spec), GFP_KERNEL); + spec = kzalloc(sizeof(*spec), GFP_KERNEL); if (spec == NULL) return -ENOMEM; diff --git a/sound/pci/hda/patch_si3054.c b/sound/pci/hda/patch_si3054.c index b0270d1..d014b7b 100644 --- a/sound/pci/hda/patch_si3054.c +++ b/sound/pci/hda/patch_si3054.c @@ -214,6 +214,7 @@ static int si3054_build_pcms(struct hda_codec *codec) info->name = "Si3054 Modem"; info->stream[SNDRV_PCM_STREAM_PLAYBACK] = si3054_pcm; info->stream[SNDRV_PCM_STREAM_CAPTURE] = si3054_pcm; + info->is_modem = 1; return 0; } @@ -282,7 +283,7 @@ static struct hda_codec_ops si3054_patch_ops = { static int patch_si3054(struct hda_codec *codec) { - struct si3054_spec *spec = kcalloc(1, sizeof(*spec), GFP_KERNEL); + struct si3054_spec *spec = kzalloc(sizeof(*spec), GFP_KERNEL); if (spec == NULL) return -ENOMEM; codec->spec = spec; diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c index 9d503da..33a8ada 100644 --- a/sound/pci/hda/patch_sigmatel.c +++ b/sound/pci/hda/patch_sigmatel.c @@ -919,7 +919,7 @@ static int patch_stac9200(struct hda_codec *codec) struct sigmatel_spec *spec; int err; - spec = kcalloc(1, sizeof(*spec), GFP_KERNEL); + spec = kzalloc(sizeof(*spec), GFP_KERNEL); if (spec == NULL) return -ENOMEM; @@ -957,7 +957,7 @@ static int patch_stac922x(struct hda_codec *codec) struct sigmatel_spec *spec; int err; - spec = kcalloc(1, sizeof(*spec), GFP_KERNEL); + spec = kzalloc(sizeof(*spec), GFP_KERNEL); if (spec == NULL) return -ENOMEM; diff --git a/sound/pci/ice1712/aureon.c b/sound/pci/ice1712/aureon.c index 4405d96..2e0a316 100644 --- a/sound/pci/ice1712/aureon.c +++ b/sound/pci/ice1712/aureon.c @@ -1796,7 +1796,7 @@ static int __devinit aureon_init(ice1712_t *ice) } /* to remeber the register values of CS8415 */ - ice->akm = kcalloc(1, sizeof(akm4xxx_t), GFP_KERNEL); + ice->akm = kzalloc(sizeof(akm4xxx_t), GFP_KERNEL); if (! ice->akm) return -ENOMEM; ice->akm_codecs = 1; diff --git a/sound/pci/ice1712/ice1712.c b/sound/pci/ice1712/ice1712.c index b97f50d..a6d9801 100644 --- a/sound/pci/ice1712/ice1712.c +++ b/sound/pci/ice1712/ice1712.c @@ -100,12 +100,6 @@ MODULE_PARM_DESC(cs8427_timeout, "Define reset timeout for cs8427 chip in msec r module_param_array(model, charp, NULL, 0444); MODULE_PARM_DESC(model, "Use the given board model."); -#ifndef PCI_VENDOR_ID_ICE -#define PCI_VENDOR_ID_ICE 0x1412 -#endif -#ifndef PCI_DEVICE_ID_ICE_1712 -#define PCI_DEVICE_ID_ICE_1712 0x1712 -#endif static struct pci_device_id snd_ice1712_ids[] = { { PCI_VENDOR_ID_ICE, PCI_DEVICE_ID_ICE_1712, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, /* ICE1712 */ @@ -2535,7 +2529,7 @@ static int __devinit snd_ice1712_create(snd_card_t * card, return -ENXIO; } - ice = kcalloc(1, sizeof(*ice), GFP_KERNEL); + ice = kzalloc(sizeof(*ice), GFP_KERNEL); if (ice == NULL) { pci_disable_device(pci); return -ENOMEM; @@ -2741,6 +2735,7 @@ static void __devexit snd_ice1712_remove(struct pci_dev *pci) static struct pci_driver driver = { .name = "ICE1712", + .owner = THIS_MODULE, .id_table = snd_ice1712_ids, .probe = snd_ice1712_probe, .remove = __devexit_p(snd_ice1712_remove), diff --git a/sound/pci/ice1712/ice1724.c b/sound/pci/ice1712/ice1724.c index c7af5e5..c3ce8f9 100644 --- a/sound/pci/ice1712/ice1724.c +++ b/sound/pci/ice1712/ice1724.c @@ -83,12 +83,6 @@ MODULE_PARM_DESC(enable, "Enable ICE1724 soundcard."); module_param_array(model, charp, NULL, 0444); MODULE_PARM_DESC(model, "Use the given board model."); -#ifndef PCI_VENDOR_ID_ICE -#define PCI_VENDOR_ID_ICE 0x1412 -#endif -#ifndef PCI_DEVICE_ID_VT1724 -#define PCI_DEVICE_ID_VT1724 0x1724 -#endif /* Both VT1720 and VT1724 have the same PCI IDs */ static struct pci_device_id snd_vt1724_ids[] = { @@ -2130,7 +2124,7 @@ static int __devinit snd_vt1724_create(snd_card_t * card, if ((err = pci_enable_device(pci)) < 0) return err; - ice = kcalloc(1, sizeof(*ice), GFP_KERNEL); + ice = kzalloc(sizeof(*ice), GFP_KERNEL); if (ice == NULL) { pci_disable_device(pci); return -ENOMEM; @@ -2321,6 +2315,7 @@ static void __devexit snd_vt1724_remove(struct pci_dev *pci) static struct pci_driver driver = { .name = "ICE1724", + .owner = THIS_MODULE, .id_table = snd_vt1724_ids, .probe = snd_vt1724_probe, .remove = __devexit_p(snd_vt1724_remove), diff --git a/sound/pci/ice1712/juli.c b/sound/pci/ice1712/juli.c index 3fb297b..2437876 100644 --- a/sound/pci/ice1712/juli.c +++ b/sound/pci/ice1712/juli.c @@ -182,7 +182,7 @@ static int __devinit juli_init(ice1712_t *ice) ice->num_total_dacs = 2; ice->num_total_adcs = 2; - ak = ice->akm = kcalloc(1, sizeof(akm4xxx_t), GFP_KERNEL); + ak = ice->akm = kzalloc(sizeof(akm4xxx_t), GFP_KERNEL); if (! ak) return -ENOMEM; ice->akm_codecs = 1; diff --git a/sound/pci/ice1712/phase.c b/sound/pci/ice1712/phase.c index 5bf734b..dcf1e8c 100644 --- a/sound/pci/ice1712/phase.c +++ b/sound/pci/ice1712/phase.c @@ -122,7 +122,7 @@ static int __devinit phase22_init(ice1712_t *ice) } // Initialize analog chips - ak = ice->akm = kcalloc(1, sizeof(akm4xxx_t), GFP_KERNEL); + ak = ice->akm = kzalloc(sizeof(akm4xxx_t), GFP_KERNEL); if (! ak) return -ENOMEM; ice->akm_codecs = 1; @@ -386,7 +386,7 @@ static int __devinit phase28_init(ice1712_t *ice) ice->num_total_adcs = 2; // Initialize analog chips - ak = ice->akm = kcalloc(1, sizeof(akm4xxx_t), GFP_KERNEL); + ak = ice->akm = kzalloc(sizeof(akm4xxx_t), GFP_KERNEL); if (!ak) return -ENOMEM; ice->akm_codecs = 1; diff --git a/sound/pci/ice1712/pontis.c b/sound/pci/ice1712/pontis.c index 25f827d..a5f852b 100644 --- a/sound/pci/ice1712/pontis.c +++ b/sound/pci/ice1712/pontis.c @@ -781,7 +781,7 @@ static int __devinit pontis_init(ice1712_t *ice) ice->num_total_adcs = 2; /* to remeber the register values */ - ice->akm = kcalloc(1, sizeof(akm4xxx_t), GFP_KERNEL); + ice->akm = kzalloc(sizeof(akm4xxx_t), GFP_KERNEL); if (! ice->akm) return -ENOMEM; ice->akm_codecs = 1; diff --git a/sound/pci/intel8x0.c b/sound/pci/intel8x0.c index 7b54841..1a96198 100644 --- a/sound/pci/intel8x0.c +++ b/sound/pci/intel8x0.c @@ -69,6 +69,7 @@ static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* ID for this card */ static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP; /* Enable this card */ static int ac97_clock[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 0}; static char *ac97_quirk[SNDRV_CARDS]; +static int buggy_semaphore[SNDRV_CARDS]; static int buggy_irq[SNDRV_CARDS]; static int xbox[SNDRV_CARDS]; @@ -86,6 +87,8 @@ module_param_array(ac97_clock, int, NULL, 0444); MODULE_PARM_DESC(ac97_clock, "AC'97 codec clock (0 = auto-detect)."); module_param_array(ac97_quirk, charp, NULL, 0444); MODULE_PARM_DESC(ac97_quirk, "AC'97 workaround for strange hardware."); +module_param_array(buggy_semaphore, bool, NULL, 0444); +MODULE_PARM_DESC(buggy_semaphore, "Enable workaround for hardwares with problematic codec semaphores."); module_param_array(buggy_irq, bool, NULL, 0444); MODULE_PARM_DESC(buggy_irq, "Enable workaround for buggy interrupts on some motherboards."); module_param_array(xbox, bool, NULL, 0444); @@ -94,62 +97,6 @@ MODULE_PARM_DESC(xbox, "Set to 1 for Xbox, if you have problems with the AC'97 c /* * Direct registers */ - -#ifndef PCI_DEVICE_ID_INTEL_82801 -#define PCI_DEVICE_ID_INTEL_82801 0x2415 -#endif -#ifndef PCI_DEVICE_ID_INTEL_82901 -#define PCI_DEVICE_ID_INTEL_82901 0x2425 -#endif -#ifndef PCI_DEVICE_ID_INTEL_82801BA -#define PCI_DEVICE_ID_INTEL_82801BA 0x2445 -#endif -#ifndef PCI_DEVICE_ID_INTEL_440MX -#define PCI_DEVICE_ID_INTEL_440MX 0x7195 -#endif -#ifndef PCI_DEVICE_ID_INTEL_ICH3 -#define PCI_DEVICE_ID_INTEL_ICH3 0x2485 -#endif -#ifndef PCI_DEVICE_ID_INTEL_ICH4 -#define PCI_DEVICE_ID_INTEL_ICH4 0x24c5 -#endif -#ifndef PCI_DEVICE_ID_INTEL_ICH5 -#define PCI_DEVICE_ID_INTEL_ICH5 0x24d5 -#endif -#ifndef PCI_DEVICE_ID_INTEL_ESB_5 -#define PCI_DEVICE_ID_INTEL_ESB_5 0x25a6 -#endif -#ifndef PCI_DEVICE_ID_INTEL_ICH6_18 -#define PCI_DEVICE_ID_INTEL_ICH6_18 0x266e -#endif -#ifndef PCI_DEVICE_ID_INTEL_ICH7_20 -#define PCI_DEVICE_ID_INTEL_ICH7_20 0x27de -#endif -#ifndef PCI_DEVICE_ID_INTEL_ESB2_14 -#define PCI_DEVICE_ID_INTEL_ESB2_14 0x2698 -#endif -#ifndef PCI_DEVICE_ID_SI_7012 -#define PCI_DEVICE_ID_SI_7012 0x7012 -#endif -#ifndef PCI_DEVICE_ID_NVIDIA_MCP_AUDIO -#define PCI_DEVICE_ID_NVIDIA_MCP_AUDIO 0x01b1 -#endif -#ifndef PCI_DEVICE_ID_NVIDIA_CK804_AUDIO -#define PCI_DEVICE_ID_NVIDIA_CK804_AUDIO 0x0059 -#endif -#ifndef PCI_DEVICE_ID_NVIDIA_MCP2_AUDIO -#define PCI_DEVICE_ID_NVIDIA_MCP2_AUDIO 0x006a -#endif -#ifndef PCI_DEVICE_ID_NVIDIA_CK8_AUDIO -#define PCI_DEVICE_ID_NVIDIA_CK8_AUDIO 0x008a -#endif -#ifndef PCI_DEVICE_ID_NVIDIA_MCP3_AUDIO -#define PCI_DEVICE_ID_NVIDIA_MCP3_AUDIO 0x00da -#endif -#ifndef PCI_DEVICE_ID_NVIDIA_CK8S_AUDIO -#define PCI_DEVICE_ID_NVIDIA_CK8S_AUDIO 0x00ea -#endif - enum { DEVICE_INTEL, DEVICE_INTEL_ICH4, DEVICE_SIS, DEVICE_ALI, DEVICE_NFORCE }; #define ICHREG(x) ICH_REG_##x @@ -423,6 +370,7 @@ struct _snd_intel8x0 { unsigned fix_nocache: 1; /* workaround for 440MX */ unsigned buggy_irq: 1; /* workaround for buggy mobos */ unsigned xbox: 1; /* workaround for Xbox AC'97 detection */ + unsigned buggy_semaphore: 1; /* workaround for buggy codec semaphore */ int spdif_idx; /* SPDIF BAR index; *_SPBAR or -1 if use PCMOUT */ unsigned int sdm_saved; /* SDM reg value */ @@ -577,6 +525,9 @@ static int snd_intel8x0_codec_semaphore(intel8x0_t *chip, unsigned int codec) if ((igetdword(chip, ICHREG(GLOB_STA)) & codec) == 0) return -EIO; + if (chip->buggy_semaphore) + return 0; /* just ignore ... */ + /* Anyone holding a semaphore for 1 msec should be shot... */ time = 100; do { @@ -1759,6 +1710,12 @@ static struct ac97_quirk ac97_quirks[] __devinitdata = { .type = AC97_TUNE_ALC_JACK }, { + .subvendor = 0x1014, + .subdevice = 0x0267, + .name = "IBM NetVista A30p", /* AD1981B */ + .type = AC97_TUNE_HP_ONLY + }, + { .subvendor = 0x1028, .subdevice = 0x00d8, .name = "Dell Precision 530", /* AD1885 */ @@ -2599,6 +2556,7 @@ struct ich_reg_info { static int __devinit snd_intel8x0_create(snd_card_t * card, struct pci_dev *pci, unsigned long device_type, + int buggy_sem, intel8x0_t ** r_intel8x0) { intel8x0_t *chip; @@ -2646,7 +2604,7 @@ static int __devinit snd_intel8x0_create(snd_card_t * card, if ((err = pci_enable_device(pci)) < 0) return err; - chip = kcalloc(1, sizeof(*chip), GFP_KERNEL); + chip = kzalloc(sizeof(*chip), GFP_KERNEL); if (chip == NULL) { pci_disable_device(pci); return -ENOMEM; @@ -2656,6 +2614,7 @@ static int __devinit snd_intel8x0_create(snd_card_t * card, chip->card = card; chip->pci = pci; chip->irq = -1; + chip->buggy_semaphore = buggy_sem; if (pci->vendor == PCI_VENDOR_ID_INTEL && pci->device == PCI_DEVICE_ID_INTEL_440MX) @@ -2795,19 +2754,19 @@ static struct shortname_table { unsigned int id; const char *s; } shortnames[] __devinitdata = { - { PCI_DEVICE_ID_INTEL_82801, "Intel 82801AA-ICH" }, - { PCI_DEVICE_ID_INTEL_82901, "Intel 82901AB-ICH0" }, - { PCI_DEVICE_ID_INTEL_82801BA, "Intel 82801BA-ICH2" }, + { PCI_DEVICE_ID_INTEL_82801AA_5, "Intel 82801AA-ICH" }, + { PCI_DEVICE_ID_INTEL_82801AB_5, "Intel 82901AB-ICH0" }, + { PCI_DEVICE_ID_INTEL_82801BA_4, "Intel 82801BA-ICH2" }, { PCI_DEVICE_ID_INTEL_440MX, "Intel 440MX" }, - { PCI_DEVICE_ID_INTEL_ICH3, "Intel 82801CA-ICH3" }, - { PCI_DEVICE_ID_INTEL_ICH4, "Intel 82801DB-ICH4" }, - { PCI_DEVICE_ID_INTEL_ICH5, "Intel ICH5" }, + { PCI_DEVICE_ID_INTEL_82801CA_5, "Intel 82801CA-ICH3" }, + { PCI_DEVICE_ID_INTEL_82801DB_5, "Intel 82801DB-ICH4" }, + { PCI_DEVICE_ID_INTEL_82801EB_5, "Intel ICH5" }, { PCI_DEVICE_ID_INTEL_ESB_5, "Intel 6300ESB" }, { PCI_DEVICE_ID_INTEL_ICH6_18, "Intel ICH6" }, { PCI_DEVICE_ID_INTEL_ICH7_20, "Intel ICH7" }, { PCI_DEVICE_ID_INTEL_ESB2_14, "Intel ESB2" }, { PCI_DEVICE_ID_SI_7012, "SiS SI7012" }, - { PCI_DEVICE_ID_NVIDIA_MCP_AUDIO, "NVidia nForce" }, + { PCI_DEVICE_ID_NVIDIA_MCP1_AUDIO, "NVidia nForce" }, { PCI_DEVICE_ID_NVIDIA_MCP2_AUDIO, "NVidia nForce2" }, { PCI_DEVICE_ID_NVIDIA_MCP3_AUDIO, "NVidia nForce3" }, { PCI_DEVICE_ID_NVIDIA_CK8S_AUDIO, "NVidia CK8S" }, @@ -2860,7 +2819,8 @@ static int __devinit snd_intel8x0_probe(struct pci_dev *pci, } } - if ((err = snd_intel8x0_create(card, pci, pci_id->driver_data, &chip)) < 0) { + if ((err = snd_intel8x0_create(card, pci, pci_id->driver_data, + buggy_semaphore[dev], &chip)) < 0) { snd_card_free(card); return err; } @@ -2904,6 +2864,7 @@ static void __devexit snd_intel8x0_remove(struct pci_dev *pci) static struct pci_driver driver = { .name = "Intel ICH", + .owner = THIS_MODULE, .id_table = snd_intel8x0_ids, .probe = snd_intel8x0_probe, .remove = __devexit_p(snd_intel8x0_remove), diff --git a/sound/pci/intel8x0m.c b/sound/pci/intel8x0m.c index bb758c7..9e2060d 100644 --- a/sound/pci/intel8x0m.c +++ b/sound/pci/intel8x0m.c @@ -73,51 +73,6 @@ MODULE_PARM_DESC(ac97_clock, "AC'97 codec clock (0 = auto-detect)."); /* * Direct registers */ - -#ifndef PCI_DEVICE_ID_INTEL_82801_6 -#define PCI_DEVICE_ID_INTEL_82801_6 0x2416 -#endif -#ifndef PCI_DEVICE_ID_INTEL_82901_6 -#define PCI_DEVICE_ID_INTEL_82901_6 0x2426 -#endif -#ifndef PCI_DEVICE_ID_INTEL_82801BA_6 -#define PCI_DEVICE_ID_INTEL_82801BA_6 0x2446 -#endif -#ifndef PCI_DEVICE_ID_INTEL_440MX_6 -#define PCI_DEVICE_ID_INTEL_440MX_6 0x7196 -#endif -#ifndef PCI_DEVICE_ID_INTEL_ICH3_6 -#define PCI_DEVICE_ID_INTEL_ICH3_6 0x2486 -#endif -#ifndef PCI_DEVICE_ID_INTEL_ICH4_6 -#define PCI_DEVICE_ID_INTEL_ICH4_6 0x24c6 -#endif -#ifndef PCI_DEVICE_ID_INTEL_ICH5_6 -#define PCI_DEVICE_ID_INTEL_ICH5_6 0x24d6 -#endif -#ifndef PCI_DEVICE_ID_INTEL_ICH6_6 -#define PCI_DEVICE_ID_INTEL_ICH6_6 0x266d -#endif -#ifndef PCI_DEVICE_ID_INTEL_ICH7_6 -#define PCI_DEVICE_ID_INTEL_ICH7_6 0x27dd -#endif -#ifndef PCI_DEVICE_ID_SI_7013 -#define PCI_DEVICE_ID_SI_7013 0x7013 -#endif -#ifndef PCI_DEVICE_ID_NVIDIA_MCP_MODEM -#define PCI_DEVICE_ID_NVIDIA_MCP_MODEM 0x01c1 -#endif -#ifndef PCI_DEVICE_ID_NVIDIA_MCP2_MODEM -#define PCI_DEVICE_ID_NVIDIA_MCP2_MODEM 0x0069 -#endif -#ifndef PCI_DEVICE_ID_NVIDIA_MCP2S_MODEM -#define PCI_DEVICE_ID_NVIDIA_MCP2S_MODEM 0x0089 -#endif -#ifndef PCI_DEVICE_ID_NVIDIA_MCP3_MODEM -#define PCI_DEVICE_ID_NVIDIA_MCP3_MODEM 0x00d9 -#endif - - enum { DEVICE_INTEL, DEVICE_SIS, DEVICE_ALI, DEVICE_NFORCE }; #define ICHREG(x) ICH_REG_##x @@ -1158,7 +1113,7 @@ static int __devinit snd_intel8x0m_create(snd_card_t * card, if ((err = pci_enable_device(pci)) < 0) return err; - chip = kcalloc(1, sizeof(*chip), GFP_KERNEL); + chip = kzalloc(sizeof(*chip), GFP_KERNEL); if (chip == NULL) { pci_disable_device(pci); return -ENOMEM; @@ -1283,18 +1238,18 @@ static struct shortname_table { unsigned int id; const char *s; } shortnames[] __devinitdata = { - { PCI_DEVICE_ID_INTEL_82801_6, "Intel 82801AA-ICH" }, - { PCI_DEVICE_ID_INTEL_82901_6, "Intel 82901AB-ICH0" }, + { PCI_DEVICE_ID_INTEL_82801AA_6, "Intel 82801AA-ICH" }, + { PCI_DEVICE_ID_INTEL_82801AB_6, "Intel 82901AB-ICH0" }, { PCI_DEVICE_ID_INTEL_82801BA_6, "Intel 82801BA-ICH2" }, { PCI_DEVICE_ID_INTEL_440MX_6, "Intel 440MX" }, - { PCI_DEVICE_ID_INTEL_ICH3_6, "Intel 82801CA-ICH3" }, - { PCI_DEVICE_ID_INTEL_ICH4_6, "Intel 82801DB-ICH4" }, - { PCI_DEVICE_ID_INTEL_ICH5_6, "Intel ICH5" }, - { PCI_DEVICE_ID_INTEL_ICH6_6, "Intel ICH6" }, - { PCI_DEVICE_ID_INTEL_ICH7_6, "Intel ICH7" }, + { PCI_DEVICE_ID_INTEL_82801CA_6, "Intel 82801CA-ICH3" }, + { PCI_DEVICE_ID_INTEL_82801DB_6, "Intel 82801DB-ICH4" }, + { PCI_DEVICE_ID_INTEL_82801EB_6, "Intel ICH5" }, + { PCI_DEVICE_ID_INTEL_ICH6_17, "Intel ICH6" }, + { PCI_DEVICE_ID_INTEL_ICH7_19, "Intel ICH7" }, { 0x7446, "AMD AMD768" }, { PCI_DEVICE_ID_SI_7013, "SiS SI7013" }, - { PCI_DEVICE_ID_NVIDIA_MCP_MODEM, "NVidia nForce" }, + { PCI_DEVICE_ID_NVIDIA_MCP1_MODEM, "NVidia nForce" }, { PCI_DEVICE_ID_NVIDIA_MCP2_MODEM, "NVidia nForce2" }, { PCI_DEVICE_ID_NVIDIA_MCP2S_MODEM, "NVidia nForce2s" }, { PCI_DEVICE_ID_NVIDIA_MCP3_MODEM, "NVidia nForce3" }, @@ -1371,6 +1326,7 @@ static void __devexit snd_intel8x0m_remove(struct pci_dev *pci) static struct pci_driver driver = { .name = "Intel ICH Modem", + .owner = THIS_MODULE, .id_table = snd_intel8x0m_ids, .probe = snd_intel8x0m_probe, .remove = __devexit_p(snd_intel8x0m_remove), diff --git a/sound/pci/korg1212/korg1212.c b/sound/pci/korg1212/korg1212.c index d2aa9c8..09f9cbe 100644 --- a/sound/pci/korg1212/korg1212.c +++ b/sound/pci/korg1212/korg1212.c @@ -2220,7 +2220,7 @@ static int __devinit snd_korg1212_create(snd_card_t * card, struct pci_dev *pci, if ((err = pci_enable_device(pci)) < 0) return err; - korg1212 = kcalloc(1, sizeof(*korg1212), GFP_KERNEL); + korg1212 = kzalloc(sizeof(*korg1212), GFP_KERNEL); if (korg1212 == NULL) { pci_disable_device(pci); return -ENOMEM; @@ -2534,6 +2534,7 @@ static void __devexit snd_korg1212_remove(struct pci_dev *pci) static struct pci_driver driver = { .name = "korg1212", + .owner = THIS_MODULE, .id_table = snd_korg1212_ids, .probe = snd_korg1212_probe, .remove = __devexit_p(snd_korg1212_remove), diff --git a/sound/pci/maestro3.c b/sound/pci/maestro3.c index 39b5e7d..2693b6f 100644 --- a/sound/pci/maestro3.c +++ b/sound/pci/maestro3.c @@ -872,35 +872,6 @@ struct snd_m3 { /* * pci ids */ - -#ifndef PCI_VENDOR_ID_ESS -#define PCI_VENDOR_ID_ESS 0x125D -#endif -#ifndef PCI_DEVICE_ID_ESS_ALLEGRO_1 -#define PCI_DEVICE_ID_ESS_ALLEGRO_1 0x1988 -#endif -#ifndef PCI_DEVICE_ID_ESS_ALLEGRO -#define PCI_DEVICE_ID_ESS_ALLEGRO 0x1989 -#endif -#ifndef PCI_DEVICE_ID_ESS_CANYON3D_2LE -#define PCI_DEVICE_ID_ESS_CANYON3D_2LE 0x1990 -#endif -#ifndef PCI_DEVICE_ID_ESS_CANYON3D_2 -#define PCI_DEVICE_ID_ESS_CANYON3D_2 0x1992 -#endif -#ifndef PCI_DEVICE_ID_ESS_MAESTRO3 -#define PCI_DEVICE_ID_ESS_MAESTRO3 0x1998 -#endif -#ifndef PCI_DEVICE_ID_ESS_MAESTRO3_1 -#define PCI_DEVICE_ID_ESS_MAESTRO3_1 0x1999 -#endif -#ifndef PCI_DEVICE_ID_ESS_MAESTRO3_HW -#define PCI_DEVICE_ID_ESS_MAESTRO3_HW 0x199a -#endif -#ifndef PCI_DEVICE_ID_ESS_MAESTRO3_2 -#define PCI_DEVICE_ID_ESS_MAESTRO3_2 0x199b -#endif - static struct pci_device_id snd_m3_ids[] = { {PCI_VENDOR_ID_ESS, PCI_DEVICE_ID_ESS_ALLEGRO_1, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_MULTIMEDIA_AUDIO << 8, 0xffff00, 0}, @@ -2689,7 +2660,7 @@ snd_m3_create(snd_card_t *card, struct pci_dev *pci, return -ENXIO; } - chip = kcalloc(1, sizeof(*chip), GFP_KERNEL); + chip = kzalloc(sizeof(*chip), GFP_KERNEL); if (chip == NULL) { pci_disable_device(pci); return -ENOMEM; @@ -2890,6 +2861,7 @@ static void __devexit snd_m3_remove(struct pci_dev *pci) static struct pci_driver driver = { .name = "Maestro3", + .owner = THIS_MODULE, .id_table = snd_m3_ids, .probe = snd_m3_probe, .remove = __devexit_p(snd_m3_remove), diff --git a/sound/pci/mixart/mixart.c b/sound/pci/mixart/mixart.c index 6c868d9..1a62c7f 100644 --- a/sound/pci/mixart/mixart.c +++ b/sound/pci/mixart/mixart.c @@ -1004,7 +1004,7 @@ static int __devinit snd_mixart_create(mixart_mgr_t *mgr, snd_card_t *card, int .dev_free = snd_mixart_chip_dev_free, }; - mgr->chip[idx] = chip = kcalloc(1, sizeof(*chip), GFP_KERNEL); + mgr->chip[idx] = chip = kzalloc(sizeof(*chip), GFP_KERNEL); if (! chip) { snd_printk(KERN_ERR "cannot allocate chip\n"); return -ENOMEM; @@ -1292,7 +1292,7 @@ static int __devinit snd_mixart_probe(struct pci_dev *pci, /* */ - mgr = kcalloc(1, sizeof(*mgr), GFP_KERNEL); + mgr = kzalloc(sizeof(*mgr), GFP_KERNEL); if (! mgr) { pci_disable_device(pci); return -ENOMEM; @@ -1424,6 +1424,7 @@ static void __devexit snd_mixart_remove(struct pci_dev *pci) static struct pci_driver driver = { .name = "Digigram miXart", + .owner = THIS_MODULE, .id_table = snd_mixart_ids, .probe = snd_mixart_probe, .remove = __devexit_p(snd_mixart_remove), diff --git a/sound/pci/nm256/nm256.c b/sound/pci/nm256/nm256.c index 2bbeb10..5c55a3b 100644 --- a/sound/pci/nm256/nm256.c +++ b/sound/pci/nm256/nm256.c @@ -259,21 +259,6 @@ struct snd_nm256 { /* * PCI ids */ - -#ifndef PCI_VENDOR_ID_NEOMAGIC -#define PCI_VENDOR_ID_NEOMEGIC 0x10c8 -#endif -#ifndef PCI_DEVICE_ID_NEOMAGIC_NM256AV_AUDIO -#define PCI_DEVICE_ID_NEOMAGIC_NM256AV_AUDIO 0x8005 -#endif -#ifndef PCI_DEVICE_ID_NEOMAGIC_NM256ZX_AUDIO -#define PCI_DEVICE_ID_NEOMAGIC_NM256ZX_AUDIO 0x8006 -#endif -#ifndef PCI_DEVICE_ID_NEOMAGIC_NM256XL_PLUS_AUDIO -#define PCI_DEVICE_ID_NEOMAGIC_NM256XL_PLUS_AUDIO 0x8016 -#endif - - static struct pci_device_id snd_nm256_ids[] = { {PCI_VENDOR_ID_NEOMAGIC, PCI_DEVICE_ID_NEOMAGIC_NM256AV_AUDIO, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, {PCI_VENDOR_ID_NEOMAGIC, PCI_DEVICE_ID_NEOMAGIC_NM256ZX_AUDIO, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, @@ -840,7 +825,7 @@ static void snd_nm256_setup_stream(nm256_t *chip, nm256_stream_t *s, runtime->hw = *hw_ptr; runtime->hw.buffer_bytes_max = s->bufsize; runtime->hw.period_bytes_max = s->bufsize / 2; - runtime->dma_area = (void*) s->bufptr; + runtime->dma_area = (void __force *) s->bufptr; runtime->dma_addr = s->bufptr_addr; runtime->dma_bytes = s->bufsize; runtime->private_data = s; @@ -1404,7 +1389,7 @@ snd_nm256_create(snd_card_t *card, struct pci_dev *pci, if ((err = pci_enable_device(pci)) < 0) return err; - chip = kcalloc(1, sizeof(*chip), GFP_KERNEL); + chip = kzalloc(sizeof(*chip), GFP_KERNEL); if (chip == NULL) { pci_disable_device(pci); return -ENOMEM; @@ -1683,6 +1668,7 @@ static void __devexit snd_nm256_remove(struct pci_dev *pci) static struct pci_driver driver = { .name = "NeoMagic 256", + .owner = THIS_MODULE, .id_table = snd_nm256_ids, .probe = snd_nm256_probe, .remove = __devexit_p(snd_nm256_remove), diff --git a/sound/pci/rme32.c b/sound/pci/rme32.c index 456be39..cd313af 100644 --- a/sound/pci/rme32.c +++ b/sound/pci/rme32.c @@ -192,20 +192,6 @@ MODULE_SUPPORTED_DEVICE("{{RME,Digi32}," "{RME,Digi32/8}," "{RME,Digi32 PRO}}"); #define RME32_PRO_REVISION_WITH_8414 150 -/* PCI vendor/device ID's */ -#ifndef PCI_VENDOR_ID_XILINX_RME -# define PCI_VENDOR_ID_XILINX_RME 0xea60 -#endif -#ifndef PCI_DEVICE_ID_DIGI32 -# define PCI_DEVICE_ID_DIGI32 0x9896 -#endif -#ifndef PCI_DEVICE_ID_DIGI32_PRO -# define PCI_DEVICE_ID_DIGI32_PRO 0x9897 -#endif -#ifndef PCI_DEVICE_ID_DIGI32_8 -# define PCI_DEVICE_ID_DIGI32_8 0x9898 -#endif - typedef struct snd_rme32 { spinlock_t lock; int irq; @@ -242,11 +228,11 @@ typedef struct snd_rme32 { } rme32_t; static struct pci_device_id snd_rme32_ids[] = { - {PCI_VENDOR_ID_XILINX_RME, PCI_DEVICE_ID_DIGI32, + {PCI_VENDOR_ID_XILINX_RME, PCI_DEVICE_ID_RME_DIGI32, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0,}, - {PCI_VENDOR_ID_XILINX_RME, PCI_DEVICE_ID_DIGI32_8, + {PCI_VENDOR_ID_XILINX_RME, PCI_DEVICE_ID_RME_DIGI32_8, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0,}, - {PCI_VENDOR_ID_XILINX_RME, PCI_DEVICE_ID_DIGI32_PRO, + {PCI_VENDOR_ID_XILINX_RME, PCI_DEVICE_ID_RME_DIGI32_PRO, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0,}, {0,} }; @@ -254,7 +240,7 @@ static struct pci_device_id snd_rme32_ids[] = { MODULE_DEVICE_TABLE(pci, snd_rme32_ids); #define RME32_ISWORKING(rme32) ((rme32)->wcreg & RME32_WCR_START) -#define RME32_PRO_WITH_8414(rme32) ((rme32)->pci->device == PCI_DEVICE_ID_DIGI32_PRO && (rme32)->rev == RME32_PRO_REVISION_WITH_8414) +#define RME32_PRO_WITH_8414(rme32) ((rme32)->pci->device == PCI_DEVICE_ID_RME_DIGI32_PRO && (rme32)->rev == RME32_PRO_REVISION_WITH_8414) static int snd_rme32_playback_prepare(snd_pcm_substream_t * substream); @@ -541,21 +527,21 @@ static int snd_rme32_playback_setrate(rme32_t * rme32, int rate) RME32_WCR_FREQ_1; break; case 64000: - if (rme32->pci->device != PCI_DEVICE_ID_DIGI32_PRO) + if (rme32->pci->device != PCI_DEVICE_ID_RME_DIGI32_PRO) return -EINVAL; rme32->wcreg |= RME32_WCR_DS_BM; rme32->wcreg = (rme32->wcreg | RME32_WCR_FREQ_0) & ~RME32_WCR_FREQ_1; break; case 88200: - if (rme32->pci->device != PCI_DEVICE_ID_DIGI32_PRO) + if (rme32->pci->device != PCI_DEVICE_ID_RME_DIGI32_PRO) return -EINVAL; rme32->wcreg |= RME32_WCR_DS_BM; rme32->wcreg = (rme32->wcreg | RME32_WCR_FREQ_1) & ~RME32_WCR_FREQ_0; break; case 96000: - if (rme32->pci->device != PCI_DEVICE_ID_DIGI32_PRO) + if (rme32->pci->device != PCI_DEVICE_ID_RME_DIGI32_PRO) return -EINVAL; rme32->wcreg |= RME32_WCR_DS_BM; rme32->wcreg = (rme32->wcreg | RME32_WCR_FREQ_0) | @@ -692,7 +678,8 @@ snd_rme32_playback_hw_params(snd_pcm_substream_t * substream, if (err < 0) return err; } else { - runtime->dma_area = (void *)(rme32->iobase + RME32_IO_DATA_BUFFER); + runtime->dma_area = (void __force *)(rme32->iobase + + RME32_IO_DATA_BUFFER); runtime->dma_addr = rme32->port + RME32_IO_DATA_BUFFER; runtime->dma_bytes = RME32_BUFFER_SIZE; } @@ -746,7 +733,8 @@ snd_rme32_capture_hw_params(snd_pcm_substream_t * substream, if (err < 0) return err; } else { - runtime->dma_area = (void *)rme32->iobase + RME32_IO_DATA_BUFFER; + runtime->dma_area = (void __force *)rme32->iobase + + RME32_IO_DATA_BUFFER; runtime->dma_addr = rme32->port + RME32_IO_DATA_BUFFER; runtime->dma_bytes = RME32_BUFFER_SIZE; } @@ -893,7 +881,7 @@ static int snd_rme32_playback_spdif_open(snd_pcm_substream_t * substream) runtime->hw = snd_rme32_spdif_fd_info; else runtime->hw = snd_rme32_spdif_info; - if (rme32->pci->device == PCI_DEVICE_ID_DIGI32_PRO) { + if (rme32->pci->device == PCI_DEVICE_ID_RME_DIGI32_PRO) { runtime->hw.rates |= SNDRV_PCM_RATE_64000 | SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000; runtime->hw.rate_max = 96000; } @@ -1420,8 +1408,8 @@ static int __devinit snd_rme32_create(rme32_t * rme32) } /* set up ALSA pcm device for ADAT */ - if ((pci->device == PCI_DEVICE_ID_DIGI32) || - (pci->device == PCI_DEVICE_ID_DIGI32_PRO)) { + if ((pci->device == PCI_DEVICE_ID_RME_DIGI32) || + (pci->device == PCI_DEVICE_ID_RME_DIGI32_PRO)) { /* ADAT is not available on DIGI32 and DIGI32 Pro */ rme32->adat_pcm = NULL; } @@ -1651,11 +1639,11 @@ snd_rme32_info_inputtype_control(snd_kcontrol_t * kcontrol, uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; uinfo->count = 1; switch (rme32->pci->device) { - case PCI_DEVICE_ID_DIGI32: - case PCI_DEVICE_ID_DIGI32_8: + case PCI_DEVICE_ID_RME_DIGI32: + case PCI_DEVICE_ID_RME_DIGI32_8: uinfo->value.enumerated.items = 3; break; - case PCI_DEVICE_ID_DIGI32_PRO: + case PCI_DEVICE_ID_RME_DIGI32_PRO: uinfo->value.enumerated.items = 4; break; default: @@ -1682,11 +1670,11 @@ snd_rme32_get_inputtype_control(snd_kcontrol_t * kcontrol, ucontrol->value.enumerated.item[0] = snd_rme32_getinputtype(rme32); switch (rme32->pci->device) { - case PCI_DEVICE_ID_DIGI32: - case PCI_DEVICE_ID_DIGI32_8: + case PCI_DEVICE_ID_RME_DIGI32: + case PCI_DEVICE_ID_RME_DIGI32_8: items = 3; break; - case PCI_DEVICE_ID_DIGI32_PRO: + case PCI_DEVICE_ID_RME_DIGI32_PRO: items = 4; break; default: @@ -1709,11 +1697,11 @@ snd_rme32_put_inputtype_control(snd_kcontrol_t * kcontrol, int change, items = 3; switch (rme32->pci->device) { - case PCI_DEVICE_ID_DIGI32: - case PCI_DEVICE_ID_DIGI32_8: + case PCI_DEVICE_ID_RME_DIGI32: + case PCI_DEVICE_ID_RME_DIGI32_8: items = 3; break; - case PCI_DEVICE_ID_DIGI32_PRO: + case PCI_DEVICE_ID_RME_DIGI32_PRO: items = 4; break; default: @@ -1994,13 +1982,13 @@ snd_rme32_probe(struct pci_dev *pci, const struct pci_device_id *pci_id) strcpy(card->driver, "Digi32"); switch (rme32->pci->device) { - case PCI_DEVICE_ID_DIGI32: + case PCI_DEVICE_ID_RME_DIGI32: strcpy(card->shortname, "RME Digi32"); break; - case PCI_DEVICE_ID_DIGI32_8: + case PCI_DEVICE_ID_RME_DIGI32_8: strcpy(card->shortname, "RME Digi32/8"); break; - case PCI_DEVICE_ID_DIGI32_PRO: + case PCI_DEVICE_ID_RME_DIGI32_PRO: strcpy(card->shortname, "RME Digi32 PRO"); break; } @@ -2024,6 +2012,7 @@ static void __devexit snd_rme32_remove(struct pci_dev *pci) static struct pci_driver driver = { .name = "RME Digi32", + .owner = THIS_MODULE, .id_table = snd_rme32_ids, .probe = snd_rme32_probe, .remove = __devexit_p(snd_rme32_remove), diff --git a/sound/pci/rme96.c b/sound/pci/rme96.c index 9645e90..c495cae 100644 --- a/sound/pci/rme96.c +++ b/sound/pci/rme96.c @@ -200,25 +200,6 @@ MODULE_PARM_DESC(enable, "Enable RME Digi96 soundcard."); #define RME96_AD1852_VOL_BITS 14 #define RME96_AD1855_VOL_BITS 10 -/* - * PCI vendor/device ids, could in the future be defined in <linux/pci.h>, - * therefore #ifndef is used. - */ -#ifndef PCI_VENDOR_ID_XILINX -#define PCI_VENDOR_ID_XILINX 0x10ee -#endif -#ifndef PCI_DEVICE_ID_DIGI96 -#define PCI_DEVICE_ID_DIGI96 0x3fc0 -#endif -#ifndef PCI_DEVICE_ID_DIGI96_8 -#define PCI_DEVICE_ID_DIGI96_8 0x3fc1 -#endif -#ifndef PCI_DEVICE_ID_DIGI96_8_PRO -#define PCI_DEVICE_ID_DIGI96_8_PRO 0x3fc2 -#endif -#ifndef PCI_DEVICE_ID_DIGI96_8_PAD_OR_PST -#define PCI_DEVICE_ID_DIGI96_8_PAD_OR_PST 0x3fc3 -#endif typedef struct snd_rme96 { spinlock_t lock; @@ -252,13 +233,13 @@ typedef struct snd_rme96 { } rme96_t; static struct pci_device_id snd_rme96_ids[] = { - { PCI_VENDOR_ID_XILINX, PCI_DEVICE_ID_DIGI96, + { PCI_VENDOR_ID_XILINX, PCI_DEVICE_ID_RME_DIGI96, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, - { PCI_VENDOR_ID_XILINX, PCI_DEVICE_ID_DIGI96_8, + { PCI_VENDOR_ID_XILINX, PCI_DEVICE_ID_RME_DIGI96_8, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, - { PCI_VENDOR_ID_XILINX, PCI_DEVICE_ID_DIGI96_8_PRO, + { PCI_VENDOR_ID_XILINX, PCI_DEVICE_ID_RME_DIGI96_8_PRO, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, - { PCI_VENDOR_ID_XILINX, PCI_DEVICE_ID_DIGI96_8_PAD_OR_PST, + { PCI_VENDOR_ID_XILINX, PCI_DEVICE_ID_RME_DIGI96_8_PAD_OR_PST, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, { 0, } }; @@ -267,12 +248,12 @@ MODULE_DEVICE_TABLE(pci, snd_rme96_ids); #define RME96_ISPLAYING(rme96) ((rme96)->wcreg & RME96_WCR_START) #define RME96_ISRECORDING(rme96) ((rme96)->wcreg & RME96_WCR_START_2) -#define RME96_HAS_ANALOG_IN(rme96) ((rme96)->pci->device == PCI_DEVICE_ID_DIGI96_8_PAD_OR_PST) -#define RME96_HAS_ANALOG_OUT(rme96) ((rme96)->pci->device == PCI_DEVICE_ID_DIGI96_8_PRO || \ - (rme96)->pci->device == PCI_DEVICE_ID_DIGI96_8_PAD_OR_PST) +#define RME96_HAS_ANALOG_IN(rme96) ((rme96)->pci->device == PCI_DEVICE_ID_RME_DIGI96_8_PAD_OR_PST) +#define RME96_HAS_ANALOG_OUT(rme96) ((rme96)->pci->device == PCI_DEVICE_ID_RME_DIGI96_8_PRO || \ + (rme96)->pci->device == PCI_DEVICE_ID_RME_DIGI96_8_PAD_OR_PST) #define RME96_DAC_IS_1852(rme96) (RME96_HAS_ANALOG_OUT(rme96) && (rme96)->rev >= 4) -#define RME96_DAC_IS_1855(rme96) (((rme96)->pci->device == PCI_DEVICE_ID_DIGI96_8_PAD_OR_PST && (rme96)->rev < 4) || \ - ((rme96)->pci->device == PCI_DEVICE_ID_DIGI96_8_PRO && (rme96)->rev == 2)) +#define RME96_DAC_IS_1855(rme96) (((rme96)->pci->device == PCI_DEVICE_ID_RME_DIGI96_8_PAD_OR_PST && (rme96)->rev < 4) || \ + ((rme96)->pci->device == PCI_DEVICE_ID_RME_DIGI96_8_PRO && (rme96)->rev == 2)) #define RME96_185X_MAX_OUT(rme96) ((1 << (RME96_DAC_IS_1852(rme96) ? RME96_AD1852_VOL_BITS : RME96_AD1855_VOL_BITS)) - 1) static int @@ -849,9 +830,9 @@ snd_rme96_setinputtype(rme96_t *rme96, RME96_WCR_INP_1; break; case RME96_INPUT_XLR: - if ((rme96->pci->device != PCI_DEVICE_ID_DIGI96_8_PAD_OR_PST && - rme96->pci->device != PCI_DEVICE_ID_DIGI96_8_PRO) || - (rme96->pci->device == PCI_DEVICE_ID_DIGI96_8_PAD_OR_PST && + if ((rme96->pci->device != PCI_DEVICE_ID_RME_DIGI96_8_PAD_OR_PST && + rme96->pci->device != PCI_DEVICE_ID_RME_DIGI96_8_PRO) || + (rme96->pci->device == PCI_DEVICE_ID_RME_DIGI96_8_PAD_OR_PST && rme96->rev > 4)) { /* Only Digi96/8 PRO and Digi96/8 PAD supports XLR */ @@ -985,7 +966,8 @@ snd_rme96_playback_hw_params(snd_pcm_substream_t *substream, snd_pcm_runtime_t *runtime = substream->runtime; int err, rate, dummy; - runtime->dma_area = (void *)(rme96->iobase + RME96_IO_PLAY_BUFFER); + runtime->dma_area = (void __force *)(rme96->iobase + + RME96_IO_PLAY_BUFFER); runtime->dma_addr = rme96->port + RME96_IO_PLAY_BUFFER; runtime->dma_bytes = RME96_BUFFER_SIZE; @@ -1037,7 +1019,8 @@ snd_rme96_capture_hw_params(snd_pcm_substream_t *substream, snd_pcm_runtime_t *runtime = substream->runtime; int err, isadat, rate; - runtime->dma_area = (void *)(rme96->iobase + RME96_IO_REC_BUFFER); + runtime->dma_area = (void __force *)(rme96->iobase + + RME96_IO_REC_BUFFER); runtime->dma_addr = rme96->port + RME96_IO_REC_BUFFER; runtime->dma_bytes = RME96_BUFFER_SIZE; @@ -1615,7 +1598,7 @@ snd_rme96_create(rme96_t *rme96) rme96->spdif_pcm->info_flags = 0; /* set up ALSA pcm device for ADAT */ - if (pci->device == PCI_DEVICE_ID_DIGI96) { + if (pci->device == PCI_DEVICE_ID_RME_DIGI96) { /* ADAT is not available on the base model */ rme96->adat_pcm = NULL; } else { @@ -1875,14 +1858,14 @@ snd_rme96_info_inputtype_control(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; uinfo->count = 1; switch (rme96->pci->device) { - case PCI_DEVICE_ID_DIGI96: - case PCI_DEVICE_ID_DIGI96_8: + case PCI_DEVICE_ID_RME_DIGI96: + case PCI_DEVICE_ID_RME_DIGI96_8: uinfo->value.enumerated.items = 3; break; - case PCI_DEVICE_ID_DIGI96_8_PRO: + case PCI_DEVICE_ID_RME_DIGI96_8_PRO: uinfo->value.enumerated.items = 4; break; - case PCI_DEVICE_ID_DIGI96_8_PAD_OR_PST: + case PCI_DEVICE_ID_RME_DIGI96_8_PAD_OR_PST: if (rme96->rev > 4) { /* PST */ uinfo->value.enumerated.items = 4; @@ -1912,14 +1895,14 @@ snd_rme96_get_inputtype_control(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t ucontrol->value.enumerated.item[0] = snd_rme96_getinputtype(rme96); switch (rme96->pci->device) { - case PCI_DEVICE_ID_DIGI96: - case PCI_DEVICE_ID_DIGI96_8: + case PCI_DEVICE_ID_RME_DIGI96: + case PCI_DEVICE_ID_RME_DIGI96_8: items = 3; break; - case PCI_DEVICE_ID_DIGI96_8_PRO: + case PCI_DEVICE_ID_RME_DIGI96_8_PRO: items = 4; break; - case PCI_DEVICE_ID_DIGI96_8_PAD_OR_PST: + case PCI_DEVICE_ID_RME_DIGI96_8_PAD_OR_PST: if (rme96->rev > 4) { /* for handling PST case, (INPUT_ANALOG is moved to INPUT_XLR */ if (ucontrol->value.enumerated.item[0] == RME96_INPUT_ANALOG) { @@ -1949,14 +1932,14 @@ snd_rme96_put_inputtype_control(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t int change, items = 3; switch (rme96->pci->device) { - case PCI_DEVICE_ID_DIGI96: - case PCI_DEVICE_ID_DIGI96_8: + case PCI_DEVICE_ID_RME_DIGI96: + case PCI_DEVICE_ID_RME_DIGI96_8: items = 3; break; - case PCI_DEVICE_ID_DIGI96_8_PRO: + case PCI_DEVICE_ID_RME_DIGI96_8_PRO: items = 4; break; - case PCI_DEVICE_ID_DIGI96_8_PAD_OR_PST: + case PCI_DEVICE_ID_RME_DIGI96_8_PAD_OR_PST: if (rme96->rev > 4) { items = 4; } else { @@ -1970,7 +1953,7 @@ snd_rme96_put_inputtype_control(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t val = ucontrol->value.enumerated.item[0] % items; /* special case for PST */ - if (rme96->pci->device == PCI_DEVICE_ID_DIGI96_8_PAD_OR_PST && rme96->rev > 4) { + if (rme96->pci->device == PCI_DEVICE_ID_RME_DIGI96_8_PAD_OR_PST && rme96->rev > 4) { if (val == RME96_INPUT_XLR) { val = RME96_INPUT_ANALOG; } @@ -2392,16 +2375,16 @@ snd_rme96_probe(struct pci_dev *pci, strcpy(card->driver, "Digi96"); switch (rme96->pci->device) { - case PCI_DEVICE_ID_DIGI96: + case PCI_DEVICE_ID_RME_DIGI96: strcpy(card->shortname, "RME Digi96"); break; - case PCI_DEVICE_ID_DIGI96_8: + case PCI_DEVICE_ID_RME_DIGI96_8: strcpy(card->shortname, "RME Digi96/8"); break; - case PCI_DEVICE_ID_DIGI96_8_PRO: + case PCI_DEVICE_ID_RME_DIGI96_8_PRO: strcpy(card->shortname, "RME Digi96/8 PRO"); break; - case PCI_DEVICE_ID_DIGI96_8_PAD_OR_PST: + case PCI_DEVICE_ID_RME_DIGI96_8_PAD_OR_PST: pci_read_config_byte(rme96->pci, 8, &val); if (val < 5) { strcpy(card->shortname, "RME Digi96/8 PAD"); @@ -2430,6 +2413,7 @@ static void __devexit snd_rme96_remove(struct pci_dev *pci) static struct pci_driver driver = { .name = "RME Digi96", + .owner = THIS_MODULE, .id_table = snd_rme96_ids, .probe = snd_rme96_probe, .remove = __devexit_p(snd_rme96_remove), diff --git a/sound/pci/rme9652/hdsp.c b/sound/pci/rme9652/hdsp.c index 6694866..52525eb 100644 --- a/sound/pci/rme9652/hdsp.c +++ b/sound/pci/rme9652/hdsp.c @@ -370,13 +370,6 @@ MODULE_SUPPORTED_DEVICE("{{RME Hammerfall-DSP}," #define UNITY_GAIN 32768 #define MINUS_INFINITY_GAIN 0 -#ifndef PCI_VENDOR_ID_XILINX -#define PCI_VENDOR_ID_XILINX 0x10ee -#endif -#ifndef PCI_DEVICE_ID_XILINX_HAMMERFALL_DSP -#define PCI_DEVICE_ID_XILINX_HAMMERFALL_DSP 0x3fc5 -#endif - /* the size of a substream (1 mono data stream) */ #define HDSP_CHANNEL_BUFFER_SAMPLES (16*1024) @@ -4899,6 +4892,7 @@ static int snd_hdsp_create_alsa_devices(snd_card_t *card, hdsp_t *hdsp) } if (!(hdsp->state & HDSP_InitializationComplete)) { + strcpy(card->shortname, "Hammerfall DSP"); sprintf(card->longname, "%s at 0x%lx, irq %d", hdsp->card_name, hdsp->port, hdsp->irq); @@ -5222,6 +5216,7 @@ static void __devexit snd_hdsp_remove(struct pci_dev *pci) static struct pci_driver driver = { .name = "RME Hammerfall DSP", + .owner = THIS_MODULE, .id_table = snd_hdsp_ids, .probe = snd_hdsp_probe, .remove = __devexit_p(snd_hdsp_remove), diff --git a/sound/pci/rme9652/hdspm.c b/sound/pci/rme9652/hdspm.c index 5d786d1..fc3f328 100644 --- a/sound/pci/rme9652/hdspm.c +++ b/sound/pci/rme9652/hdspm.c @@ -301,18 +301,6 @@ MODULE_SUPPORTED_DEVICE("{{RME HDSPM-MADI}}"); #define UNITY_GAIN 32768 /* = 65536/2 */ #define MINUS_INFINITY_GAIN 0 -/* PCI info */ -#ifndef PCI_VENDOR_ID_XILINX -#define PCI_VENDOR_ID_XILINX 0x10ee -#endif -#ifndef PCI_DEVICE_ID_XILINX_HAMMERFALL_DSP -#define PCI_DEVICE_ID_XILINX_HAMMERFALL_DSP 0x3fc5 -#endif -#ifndef PCI_DEVICE_ID_XILINX_HAMMERFALL_DSP_MADI -#define PCI_DEVICE_ID_XILINX_HAMMERFALL_DSP_MADI 0x3fc6 -#endif - - /* Number of channels for different Speed Modes */ #define MADI_SS_CHANNELS 64 #define MADI_DS_CHANNELS 32 @@ -3652,6 +3640,7 @@ static void __devexit snd_hdspm_remove(struct pci_dev *pci) static struct pci_driver driver = { .name = "RME Hammerfall DSP MADI", + .owner = THIS_MODULE, .id_table = snd_hdspm_ids, .probe = snd_hdspm_probe, .remove = __devexit_p(snd_hdspm_remove), diff --git a/sound/pci/rme9652/rme9652.c b/sound/pci/rme9652/rme9652.c index 8ee4d6f..b600f45 100644 --- a/sound/pci/rme9652/rme9652.c +++ b/sound/pci/rme9652/rme9652.c @@ -120,13 +120,6 @@ MODULE_SUPPORTED_DEVICE("{{RME,Hammerfall}," #define RME9652_REV15_buf_pos(x) ((((x)&0xE0000000)>>26)|((x)&RME9652_buf_pos)) -#ifndef PCI_VENDOR_ID_XILINX -#define PCI_VENDOR_ID_XILINX 0x10ee -#endif -#ifndef PCI_DEVICE_ID_XILINX_HAMMERFALL -#define PCI_DEVICE_ID_XILINX_HAMMERFALL 0x3fc4 -#endif - /* amount of io space we remap for register access. i'm not sure we even need this much, but 1K is nice round number :) */ @@ -2661,6 +2654,7 @@ static void __devexit snd_rme9652_remove(struct pci_dev *pci) static struct pci_driver driver = { .name = "RME Digi9652 (Hammerfall)", + .owner = THIS_MODULE, .id_table = snd_rme9652_ids, .probe = snd_rme9652_probe, .remove = __devexit_p(snd_rme9652_remove), diff --git a/sound/pci/sonicvibes.c b/sound/pci/sonicvibes.c index 60ecb2b..1f6c2bf 100644 --- a/sound/pci/sonicvibes.c +++ b/sound/pci/sonicvibes.c @@ -50,13 +50,6 @@ MODULE_SUPPORTED_DEVICE("{{S3,SonicVibes PCI}}"); #define SUPPORT_JOYSTICK 1 #endif -#ifndef PCI_VENDOR_ID_S3 -#define PCI_VENDOR_ID_S3 0x5333 -#endif -#ifndef PCI_DEVICE_ID_S3_SONICVIBES -#define PCI_DEVICE_ID_S3_SONICVIBES 0xca00 -#endif - static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-MAX */ static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* ID for this card */ static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP; /* Enable this card */ @@ -1257,7 +1250,7 @@ static int __devinit snd_sonicvibes_create(snd_card_t * card, return -ENXIO; } - sonic = kcalloc(1, sizeof(*sonic), GFP_KERNEL); + sonic = kzalloc(sizeof(*sonic), GFP_KERNEL); if (sonic == NULL) { pci_disable_device(pci); return -ENOMEM; @@ -1515,6 +1508,7 @@ static void __devexit snd_sonic_remove(struct pci_dev *pci) static struct pci_driver driver = { .name = "S3 SonicVibes", + .owner = THIS_MODULE, .id_table = snd_sonic_ids, .probe = snd_sonic_probe, .remove = __devexit_p(snd_sonic_remove), diff --git a/sound/pci/trident/trident.c b/sound/pci/trident/trident.c index 940d531..a8ca8e1 100644 --- a/sound/pci/trident/trident.c +++ b/sound/pci/trident/trident.c @@ -177,6 +177,7 @@ static void __devexit snd_trident_remove(struct pci_dev *pci) static struct pci_driver driver = { .name = "Trident4DWaveAudio", + .owner = THIS_MODULE, .id_table = snd_trident_ids, .probe = snd_trident_probe, .remove = __devexit_p(snd_trident_remove), diff --git a/sound/pci/trident/trident_main.c b/sound/pci/trident/trident_main.c index f30d9d9..777da9a 100644 --- a/sound/pci/trident/trident_main.c +++ b/sound/pci/trident/trident_main.c @@ -2960,7 +2960,7 @@ static int __devinit snd_trident_mixer(trident_t * trident, int pcm_spdif_device .read = snd_trident_codec_read, }; - uctl = kcalloc(1, sizeof(*uctl), GFP_KERNEL); + uctl = kzalloc(sizeof(*uctl), GFP_KERNEL); if (!uctl) return -ENOMEM; @@ -3546,7 +3546,7 @@ int __devinit snd_trident_create(snd_card_t * card, return -ENXIO; } - trident = kcalloc(1, sizeof(*trident), GFP_KERNEL); + trident = kzalloc(sizeof(*trident), GFP_KERNEL); if (trident == NULL) { pci_disable_device(pci); return -ENOMEM; diff --git a/sound/pci/via82xx.c b/sound/pci/via82xx.c index 56c6e52..6db7de6 100644 --- a/sound/pci/via82xx.c +++ b/sound/pci/via82xx.c @@ -104,14 +104,6 @@ module_param_array(dxs_support, int, NULL, 0444); MODULE_PARM_DESC(dxs_support, "Support for DXS channels (0 = auto, 1 = enable, 2 = disable, 3 = 48k only, 4 = no VRA, 5 = enable any sample rate)"); -/* pci ids */ -#ifndef PCI_DEVICE_ID_VIA_82C686_5 -#define PCI_DEVICE_ID_VIA_82C686_5 0x3058 -#endif -#ifndef PCI_DEVICE_ID_VIA_8233_5 -#define PCI_DEVICE_ID_VIA_8233_5 0x3059 -#endif - /* revision numbers for via686 */ #define VIA_REV_686_A 0x10 #define VIA_REV_686_B 0x11 @@ -1935,11 +1927,12 @@ static int snd_via82xx_chip_init(via82xx_t *chip) * DXS channels don't work properly with VRA if MC97 is disabled. */ struct pci_dev *pci; - pci = pci_find_device(0x1106, 0x3068, NULL); /* MC97 */ + pci = pci_get_device(0x1106, 0x3068, NULL); /* MC97 */ if (pci) { unsigned char data; pci_read_config_byte(pci, 0x44, &data); pci_write_config_byte(pci, 0x44, data | 0x40); + pci_dev_put(pci); } } @@ -2065,7 +2058,7 @@ static int __devinit snd_via82xx_create(snd_card_t * card, if ((err = pci_enable_device(pci)) < 0) return err; - if ((chip = kcalloc(1, sizeof(*chip), GFP_KERNEL)) == NULL) { + if ((chip = kzalloc(sizeof(*chip), GFP_KERNEL)) == NULL) { pci_disable_device(pci); return -ENOMEM; } @@ -2350,6 +2343,7 @@ static void __devexit snd_via82xx_remove(struct pci_dev *pci) static struct pci_driver driver = { .name = "VIA 82xx Audio", + .owner = THIS_MODULE, .id_table = snd_via82xx_ids, .probe = snd_via82xx_probe, .remove = __devexit_p(snd_via82xx_remove), diff --git a/sound/pci/via82xx_modem.c b/sound/pci/via82xx_modem.c index 5872d43..7eac6f6 100644 --- a/sound/pci/via82xx_modem.c +++ b/sound/pci/via82xx_modem.c @@ -1083,7 +1083,7 @@ static int __devinit snd_via82xx_create(snd_card_t * card, if ((err = pci_enable_device(pci)) < 0) return err; - if ((chip = kcalloc(1, sizeof(*chip), GFP_KERNEL)) == NULL) { + if ((chip = kzalloc(sizeof(*chip), GFP_KERNEL)) == NULL) { pci_disable_device(pci); return -ENOMEM; } @@ -1207,6 +1207,7 @@ static void __devexit snd_via82xx_remove(struct pci_dev *pci) static struct pci_driver driver = { .name = "VIA 82xx Modem", + .owner = THIS_MODULE, .id_table = snd_via82xx_modem_ids, .probe = snd_via82xx_probe, .remove = __devexit_p(snd_via82xx_remove), diff --git a/sound/pci/vx222/vx222.c b/sound/pci/vx222/vx222.c index dca6bd2..2a7ad9d 100644 --- a/sound/pci/vx222/vx222.c +++ b/sound/pci/vx222/vx222.c @@ -252,6 +252,7 @@ static void __devexit snd_vx222_remove(struct pci_dev *pci) static struct pci_driver driver = { .name = "Digigram VX222", + .owner = THIS_MODULE, .id_table = snd_vx222_ids, .probe = snd_vx222_probe, .remove = __devexit_p(snd_vx222_remove), diff --git a/sound/pci/ymfpci/ymfpci.c b/sound/pci/ymfpci/ymfpci.c index 5b5b624..2e69abe 100644 --- a/sound/pci/ymfpci/ymfpci.c +++ b/sound/pci/ymfpci/ymfpci.c @@ -352,6 +352,7 @@ static void __devexit snd_card_ymfpci_remove(struct pci_dev *pci) static struct pci_driver driver = { .name = "Yamaha DS-XG PCI", + .owner = THIS_MODULE, .id_table = snd_ymfpci_ids, .probe = snd_card_ymfpci_probe, .remove = __devexit_p(snd_card_ymfpci_remove), diff --git a/sound/pci/ymfpci/ymfpci_main.c b/sound/pci/ymfpci/ymfpci_main.c index 0548364..27fa523 100644 --- a/sound/pci/ymfpci/ymfpci_main.c +++ b/sound/pci/ymfpci/ymfpci_main.c @@ -839,7 +839,7 @@ static int snd_ymfpci_playback_open_1(snd_pcm_substream_t * substream) snd_pcm_runtime_t *runtime = substream->runtime; ymfpci_pcm_t *ypcm; - ypcm = kcalloc(1, sizeof(*ypcm), GFP_KERNEL); + ypcm = kzalloc(sizeof(*ypcm), GFP_KERNEL); if (ypcm == NULL) return -ENOMEM; ypcm->chip = chip; @@ -957,7 +957,7 @@ static int snd_ymfpci_capture_open(snd_pcm_substream_t * substream, snd_pcm_runtime_t *runtime = substream->runtime; ymfpci_pcm_t *ypcm; - ypcm = kcalloc(1, sizeof(*ypcm), GFP_KERNEL); + ypcm = kzalloc(sizeof(*ypcm), GFP_KERNEL); if (ypcm == NULL) return -ENOMEM; ypcm->chip = chip; @@ -2270,7 +2270,7 @@ int __devinit snd_ymfpci_create(snd_card_t * card, if ((err = pci_enable_device(pci)) < 0) return err; - chip = kcalloc(1, sizeof(*chip), GFP_KERNEL); + chip = kzalloc(sizeof(*chip), GFP_KERNEL); if (chip == NULL) { pci_disable_device(pci); return -ENOMEM; diff --git a/sound/pcmcia/pdaudiocf/pdaudiocf_core.c b/sound/pcmcia/pdaudiocf/pdaudiocf_core.c index a2132e3..0208c54 100644 --- a/sound/pcmcia/pdaudiocf/pdaudiocf_core.c +++ b/sound/pcmcia/pdaudiocf/pdaudiocf_core.c @@ -151,7 +151,7 @@ pdacf_t *snd_pdacf_create(snd_card_t *card) { pdacf_t *chip; - chip = kcalloc(1, sizeof(*chip), GFP_KERNEL); + chip = kzalloc(sizeof(*chip), GFP_KERNEL); if (chip == NULL) return NULL; chip->card = card; diff --git a/sound/ppc/Kconfig b/sound/ppc/Kconfig index 75213bf..206b933 100644 --- a/sound/ppc/Kconfig +++ b/sound/ppc/Kconfig @@ -13,11 +13,24 @@ config SND_POWERMAC tristate "PowerMac (AWACS, DACA, Burgundy, Tumbler, Keywest)" depends on SND && I2C && INPUT && PPC_PMAC select SND_PCM + select SND_GENERIC_DRIVER help Say Y here to include support for the integrated sound device. To compile this driver as a module, choose M here: the module will be called snd-powermac. -endmenu +config SND_POWERMAC_AUTO_DRC + bool "Toggle DRC automatically at headphone/line plug-in" + depends on SND_POWERMAC + default y + help + Say Y here to enable the automatic toggle of DRC (dynamic + range compression) on Tumbler/Snapper. + If this feature is enabled, DRC is turned off when the + headphone/line jack is plugged, and turned on when unplugged. + Note that you can turn on/off DRC manually even without this + option. + +endmenu diff --git a/sound/ppc/pmac.c b/sound/ppc/pmac.c index c89e82e..e35b48d 100644 --- a/sound/ppc/pmac.c +++ b/sound/ppc/pmac.c @@ -988,6 +988,7 @@ static int __init snd_pmac_detect(pmac_t *chip) case 0x33: case 0x29: case 0x24: + case 0x5c: chip->num_freqs = ARRAY_SIZE(tumbler_freqs); chip->model = PMAC_SNAPPER; chip->can_byte_swap = 0; /* FIXME: check this */ @@ -1159,7 +1160,7 @@ int __init snd_pmac_new(snd_card_t *card, pmac_t **chip_return) snd_runtime_check(chip_return, return -EINVAL); *chip_return = NULL; - chip = kcalloc(1, sizeof(*chip), GFP_KERNEL); + chip = kzalloc(sizeof(*chip), GFP_KERNEL); if (chip == NULL) return -ENOMEM; chip->card = card; diff --git a/sound/ppc/powermac.c b/sound/ppc/powermac.c index 231f643..a6d8cbf 100644 --- a/sound/ppc/powermac.c +++ b/sound/ppc/powermac.c @@ -131,6 +131,9 @@ static int __init snd_pmac_probe(void) if (enable_beep) snd_pmac_attach_beep(chip); + if ((err = snd_card_set_generic_dev(card)) < 0) + goto __error; + if ((err = snd_card_register(card)) < 0) goto __error; diff --git a/sound/ppc/tumbler.c b/sound/ppc/tumbler.c index b94437c..65384af 100644 --- a/sound/ppc/tumbler.c +++ b/sound/ppc/tumbler.c @@ -948,7 +948,6 @@ static void device_change_handler(void *self) msleep(10); check_mute(chip, &mix->amp_mute, 1, mix->auto_mute_notify, chip->speaker_sw_ctl); - mix->drc_enable = 0; } else { /* unmute speaker, mute others */ check_mute(chip, &mix->amp_mute, 0, mix->auto_mute_notify, @@ -960,20 +959,21 @@ static void device_change_handler(void *self) if (mix->line_mute.addr != 0) check_mute(chip, &mix->line_mute, 1, mix->auto_mute_notify, chip->lineout_sw_ctl); - mix->drc_enable = 1; } - if (mix->auto_mute_notify) { + if (mix->auto_mute_notify) snd_ctl_notify(chip->card, SNDRV_CTL_EVENT_MASK_VALUE, &chip->hp_detect_ctl->id); + +#ifdef CONFIG_SND_POWERMAC_AUTO_DRC + mix->drc_enable = ! (headphone || lineout); + if (mix->auto_mute_notify) snd_ctl_notify(chip->card, SNDRV_CTL_EVENT_MASK_VALUE, &chip->drc_sw_ctl->id); - } - - /* first set the DRC so the speaker do not explode -ReneR */ if (chip->model == PMAC_TUMBLER) tumbler_set_drc(mix); else snapper_set_drc(mix); +#endif /* reset the master volume so the correct amplification is applied */ tumbler_set_master_volume(mix); @@ -1370,6 +1370,17 @@ int __init snd_pmac_tumbler_init(pmac_t *chip) if ((err = snd_ctl_add(chip->card, chip->drc_sw_ctl)) < 0) return err; + /* set initial DRC range to 60% */ + if (chip->model == PMAC_TUMBLER) + mix->drc_range = (TAS3001_DRC_MAX * 6) / 10; + else + mix->drc_range = (TAS3004_DRC_MAX * 6) / 10; + mix->drc_enable = 1; /* will be changed later if AUTO_DRC is set */ + if (chip->model == PMAC_TUMBLER) + tumbler_set_drc(mix); + else + snapper_set_drc(mix); + #ifdef CONFIG_PM chip->suspend = tumbler_suspend; chip->resume = tumbler_resume; diff --git a/sound/sparc/Kconfig b/sound/sparc/Kconfig index 25a8a55..09ab138 100644 --- a/sound/sparc/Kconfig +++ b/sound/sparc/Kconfig @@ -7,6 +7,7 @@ config SND_SUN_AMD7930 tristate "Sun AMD7930" depends on SBUS && SND select SND_PCM + select SND_GENERIC_DRIVER help Say Y here to include support for AMD7930 sound device on Sun. @@ -17,6 +18,7 @@ config SND_SUN_CS4231 tristate "Sun CS4231" depends on SND select SND_PCM + select SND_GENERIC_DRIVER help Say Y here to include support for CS4231 sound device on Sun. @@ -27,6 +29,7 @@ config SND_SUN_DBRI tristate "Sun DBRI" depends on SND && SBUS select SND_PCM + select SND_GENERIC_DRIVER help Say Y here to include support for DBRI sound device on Sun. diff --git a/sound/sparc/amd7930.c b/sound/sparc/amd7930.c index bd8a850..46d504b 100644 --- a/sound/sparc/amd7930.c +++ b/sound/sparc/amd7930.c @@ -967,7 +967,7 @@ static int __init snd_amd7930_create(snd_card_t *card, int err; *ramd = NULL; - amd = kcalloc(1, sizeof(*amd), GFP_KERNEL); + amd = kzalloc(sizeof(*amd), GFP_KERNEL); if (amd == NULL) return -ENOMEM; @@ -1088,6 +1088,9 @@ static int __init amd7930_attach(int prom_node, struct sbus_dev *sdev) if ((err = snd_amd7930_mixer(amd)) < 0) goto out_err; + if ((err = snd_card_set_generic_dev(card)) < 0) + goto out_err; + if ((err = snd_card_register(card)) < 0) goto out_err; diff --git a/sound/sparc/cs4231.c b/sound/sparc/cs4231.c index 36f9fe4..f4361c5 100644 --- a/sound/sparc/cs4231.c +++ b/sound/sparc/cs4231.c @@ -173,7 +173,7 @@ static cs4231_t *cs4231_list; #define CS4231_GLOBALIRQ 0x01 /* IRQ is active */ -/* definitions for codec irq status */ +/* definitions for codec irq status - CS4231_IRQ_STATUS */ #define CS4231_PLAYBACK_IRQ 0x10 #define CS4231_RECORD_IRQ 0x20 @@ -402,7 +402,7 @@ static void snd_cs4231_outm(cs4231_t *chip, unsigned char reg, udelay(100); #ifdef CONFIG_SND_DEBUG if (__cs4231_readb(chip, CS4231P(chip, REGSEL)) & CS4231_INIT) - snd_printk("outm: auto calibration time out - reg = 0x%x, value = 0x%x\n", reg, value); + snd_printdd("outm: auto calibration time out - reg = 0x%x, value = 0x%x\n", reg, value); #endif if (chip->calibrate_mute) { chip->image[reg] &= mask; @@ -425,6 +425,10 @@ static void snd_cs4231_dout(cs4231_t *chip, unsigned char reg, unsigned char val timeout > 0 && (__cs4231_readb(chip, CS4231P(chip, REGSEL)) & CS4231_INIT); timeout--) udelay(100); +#ifdef CONFIG_SND_DEBUG + if (__cs4231_readb(chip, CS4231P(chip, REGSEL)) & CS4231_INIT) + snd_printdd("out: auto calibration time out - reg = 0x%x, value = 0x%x\n", reg, value); +#endif __cs4231_writeb(chip, chip->mce_bit | reg, CS4231P(chip, REGSEL)); __cs4231_writeb(chip, value, CS4231P(chip, REG)); mb(); @@ -440,15 +444,12 @@ static void snd_cs4231_out(cs4231_t *chip, unsigned char reg, unsigned char valu udelay(100); #ifdef CONFIG_SND_DEBUG if (__cs4231_readb(chip, CS4231P(chip, REGSEL)) & CS4231_INIT) - snd_printk("out: auto calibration time out - reg = 0x%x, value = 0x%x\n", reg, value); + snd_printdd("out: auto calibration time out - reg = 0x%x, value = 0x%x\n", reg, value); #endif __cs4231_writeb(chip, chip->mce_bit | reg, CS4231P(chip, REGSEL)); __cs4231_writeb(chip, value, CS4231P(chip, REG)); chip->image[reg] = value; mb(); -#if 0 - printk("codec out - reg 0x%x = 0x%x\n", chip->mce_bit | reg, value); -#endif } static unsigned char snd_cs4231_in(cs4231_t *chip, unsigned char reg) @@ -462,61 +463,14 @@ static unsigned char snd_cs4231_in(cs4231_t *chip, unsigned char reg) udelay(100); #ifdef CONFIG_SND_DEBUG if (__cs4231_readb(chip, CS4231P(chip, REGSEL)) & CS4231_INIT) - snd_printk("in: auto calibration time out - reg = 0x%x\n", reg); + snd_printdd("in: auto calibration time out - reg = 0x%x\n", reg); #endif __cs4231_writeb(chip, chip->mce_bit | reg, CS4231P(chip, REGSEL)); mb(); ret = __cs4231_readb(chip, CS4231P(chip, REG)); -#if 0 - printk("codec in - reg 0x%x = 0x%x\n", chip->mce_bit | reg, ret); -#endif return ret; } -#if 0 - -static void snd_cs4231_debug(cs4231_t *chip) -{ - printk("CS4231 REGS: INDEX = 0x%02x ", - __cs4231_readb(chip, CS4231P(chip, REGSEL))); - printk(" STATUS = 0x%02x\n", - __cs4231_readb(chip, CS4231P(chip, STATUS))); - printk(" 0x00: left input = 0x%02x ", snd_cs4231_in(chip, 0x00)); - printk(" 0x10: alt 1 (CFIG 2) = 0x%02x\n", snd_cs4231_in(chip, 0x10)); - printk(" 0x01: right input = 0x%02x ", snd_cs4231_in(chip, 0x01)); - printk(" 0x11: alt 2 (CFIG 3) = 0x%02x\n", snd_cs4231_in(chip, 0x11)); - printk(" 0x02: GF1 left input = 0x%02x ", snd_cs4231_in(chip, 0x02)); - printk(" 0x12: left line in = 0x%02x\n", snd_cs4231_in(chip, 0x12)); - printk(" 0x03: GF1 right input = 0x%02x ", snd_cs4231_in(chip, 0x03)); - printk(" 0x13: right line in = 0x%02x\n", snd_cs4231_in(chip, 0x13)); - printk(" 0x04: CD left input = 0x%02x ", snd_cs4231_in(chip, 0x04)); - printk(" 0x14: timer low = 0x%02x\n", snd_cs4231_in(chip, 0x14)); - printk(" 0x05: CD right input = 0x%02x ", snd_cs4231_in(chip, 0x05)); - printk(" 0x15: timer high = 0x%02x\n", snd_cs4231_in(chip, 0x15)); - printk(" 0x06: left output = 0x%02x ", snd_cs4231_in(chip, 0x06)); - printk(" 0x16: left MIC (PnP) = 0x%02x\n", snd_cs4231_in(chip, 0x16)); - printk(" 0x07: right output = 0x%02x ", snd_cs4231_in(chip, 0x07)); - printk(" 0x17: right MIC (PnP) = 0x%02x\n", snd_cs4231_in(chip, 0x17)); - printk(" 0x08: playback format = 0x%02x ", snd_cs4231_in(chip, 0x08)); - printk(" 0x18: IRQ status = 0x%02x\n", snd_cs4231_in(chip, 0x18)); - printk(" 0x09: iface (CFIG 1) = 0x%02x ", snd_cs4231_in(chip, 0x09)); - printk(" 0x19: left line out = 0x%02x\n", snd_cs4231_in(chip, 0x19)); - printk(" 0x0a: pin control = 0x%02x ", snd_cs4231_in(chip, 0x0a)); - printk(" 0x1a: mono control = 0x%02x\n", snd_cs4231_in(chip, 0x1a)); - printk(" 0x0b: init & status = 0x%02x ", snd_cs4231_in(chip, 0x0b)); - printk(" 0x1b: right line out = 0x%02x\n", snd_cs4231_in(chip, 0x1b)); - printk(" 0x0c: revision & mode = 0x%02x ", snd_cs4231_in(chip, 0x0c)); - printk(" 0x1c: record format = 0x%02x\n", snd_cs4231_in(chip, 0x1c)); - printk(" 0x0d: loopback = 0x%02x ", snd_cs4231_in(chip, 0x0d)); - printk(" 0x1d: var freq (PnP) = 0x%02x\n", snd_cs4231_in(chip, 0x1d)); - printk(" 0x0e: ply upr count = 0x%02x ", snd_cs4231_in(chip, 0x0e)); - printk(" 0x1e: rec upr count = 0x%02x\n", snd_cs4231_in(chip, 0x1e)); - printk(" 0x0f: ply lwr count = 0x%02x ", snd_cs4231_in(chip, 0x0f)); - printk(" 0x1f: rec lwr count = 0x%02x\n", snd_cs4231_in(chip, 0x1f)); -} - -#endif - /* * CS4231 detection / MCE routines */ @@ -528,11 +482,12 @@ static void snd_cs4231_busy_wait(cs4231_t *chip) /* huh.. looks like this sequence is proper for CS4231A chip (GUS MAX) */ for (timeout = 5; timeout > 0; timeout--) __cs4231_readb(chip, CS4231P(chip, REGSEL)); + /* end of cleanup sequence */ - for (timeout = 250; + for (timeout = 500; timeout > 0 && (__cs4231_readb(chip, CS4231P(chip, REGSEL)) & CS4231_INIT); timeout--) - udelay(100); + udelay(1000); } static void snd_cs4231_mce_up(cs4231_t *chip) @@ -545,12 +500,12 @@ static void snd_cs4231_mce_up(cs4231_t *chip) udelay(100); #ifdef CONFIG_SND_DEBUG if (__cs4231_readb(chip, CS4231P(chip, REGSEL)) & CS4231_INIT) - snd_printk("mce_up - auto calibration time out (0)\n"); + snd_printdd("mce_up - auto calibration time out (0)\n"); #endif chip->mce_bit |= CS4231_MCE; timeout = __cs4231_readb(chip, CS4231P(chip, REGSEL)); if (timeout == 0x80) - snd_printk("mce_up [%p]: serious init problem - codec still busy\n", chip->port); + snd_printdd("mce_up [%p]: serious init problem - codec still busy\n", chip->port); if (!(timeout & CS4231_MCE)) __cs4231_writeb(chip, chip->mce_bit | (timeout & 0x1f), CS4231P(chip, REGSEL)); spin_unlock_irqrestore(&chip->lock, flags); @@ -563,18 +518,15 @@ static void snd_cs4231_mce_down(cs4231_t *chip) spin_lock_irqsave(&chip->lock, flags); snd_cs4231_busy_wait(chip); -#if 0 - printk("(1) timeout = %i\n", timeout); -#endif #ifdef CONFIG_SND_DEBUG if (__cs4231_readb(chip, CS4231P(chip, REGSEL)) & CS4231_INIT) - snd_printk("mce_down [%p] - auto calibration time out (0)\n", CS4231P(chip, REGSEL)); + snd_printdd("mce_down [%p] - auto calibration time out (0)\n", CS4231P(chip, REGSEL)); #endif chip->mce_bit &= ~CS4231_MCE; timeout = __cs4231_readb(chip, CS4231P(chip, REGSEL)); __cs4231_writeb(chip, chip->mce_bit | (timeout & 0x1f), CS4231P(chip, REGSEL)); if (timeout == 0x80) - snd_printk("mce_down [%p]: serious init problem - codec still busy\n", chip->port); + snd_printdd("mce_down [%p]: serious init problem - codec still busy\n", chip->port); if ((timeout & CS4231_MCE) == 0) { spin_unlock_irqrestore(&chip->lock, flags); return; @@ -590,9 +542,7 @@ static void snd_cs4231_mce_down(cs4231_t *chip) spin_unlock_irqrestore(&chip->lock, flags); return; } -#if 0 - printk("(2) timeout = %i, jiffies = %li\n", timeout, jiffies); -#endif + /* in 10ms increments, check condition, up to 250ms */ timeout = 25; while (snd_cs4231_in(chip, CS4231_TEST_INIT) & CS4231_CALIB_IN_PROGRESS) { @@ -604,9 +554,7 @@ static void snd_cs4231_mce_down(cs4231_t *chip) msleep(10); spin_lock_irqsave(&chip->lock, flags); } -#if 0 - printk("(3) jiffies = %li\n", jiffies); -#endif + /* in 10ms increments, check condition, up to 100ms */ timeout = 10; while (__cs4231_readb(chip, CS4231P(chip, REGSEL)) & CS4231_INIT) { @@ -619,28 +567,7 @@ static void snd_cs4231_mce_down(cs4231_t *chip) spin_lock_irqsave(&chip->lock, flags); } spin_unlock_irqrestore(&chip->lock, flags); -#if 0 - printk("(4) jiffies = %li\n", jiffies); - snd_printk("mce_down - exit = 0x%x\n", __cs4231_readb(chip, CS4231P(chip, REGSEL))); -#endif -} - -#if 0 /* Unused for now... */ -static unsigned int snd_cs4231_get_count(unsigned char format, unsigned int size) -{ - switch (format & 0xe0) { - case CS4231_LINEAR_16: - case CS4231_LINEAR_16_BIG: - size >>= 1; - break; - case CS4231_ADPCM_16: - return size >> 2; - } - if (format & CS4231_STEREO) - size >>= 1; - return size; } -#endif #ifdef EBUS_SUPPORT static void snd_cs4231_ebus_advance_dma(struct ebus_dma_info *p, snd_pcm_substream_t *substream, unsigned int *periods_sent) @@ -648,25 +575,50 @@ static void snd_cs4231_ebus_advance_dma(struct ebus_dma_info *p, snd_pcm_substre snd_pcm_runtime_t *runtime = substream->runtime; while (1) { - unsigned int dma_size = snd_pcm_lib_period_bytes(substream); - unsigned int offset = dma_size * (*periods_sent); + unsigned int period_size = snd_pcm_lib_period_bytes(substream); + unsigned int offset = period_size * (*periods_sent); - if (dma_size >= (1 << 24)) + if (period_size >= (1 << 24)) BUG(); - if (ebus_dma_request(p, runtime->dma_addr + offset, dma_size)) + if (ebus_dma_request(p, runtime->dma_addr + offset, period_size)) return; -#if 0 - printk("ebus_advance: Sent period %u (size[%x] offset[%x])\n", - (*periods_sent), dma_size, offset); -#endif (*periods_sent) = ((*periods_sent) + 1) % runtime->periods; } } #endif -static void cs4231_dma_trigger(cs4231_t *chip, unsigned int what, int on) +#ifdef SBUS_SUPPORT +static void snd_cs4231_sbus_advance_dma(snd_pcm_substream_t *substream, unsigned int *periods_sent) { + cs4231_t *chip = snd_pcm_substream_chip(substream); + snd_pcm_runtime_t *runtime = substream->runtime; + + unsigned int period_size = snd_pcm_lib_period_bytes(substream); + unsigned int offset = period_size * (*periods_sent % runtime->periods); + + if (runtime->period_size > 0xffff + 1) + BUG(); + + switch (substream->stream) { + case SNDRV_PCM_STREAM_PLAYBACK: + sbus_writel(runtime->dma_addr + offset, chip->port + APCPNVA); + sbus_writel(period_size, chip->port + APCPNC); + break; + case SNDRV_PCM_STREAM_CAPTURE: + sbus_writel(runtime->dma_addr + offset, chip->port + APCCNVA); + sbus_writel(period_size, chip->port + APCCNC); + break; + } + + (*periods_sent) = (*periods_sent + 1) % runtime->periods; +} +#endif + +static void cs4231_dma_trigger(snd_pcm_substream_t *substream, unsigned int what, int on) +{ + cs4231_t *chip = snd_pcm_substream_chip(substream); + #ifdef EBUS_SUPPORT if (chip->flags & CS4231_FLAG_EBUS) { if (what & CS4231_PLAYBACK_ENABLE) { @@ -694,6 +646,60 @@ static void cs4231_dma_trigger(cs4231_t *chip, unsigned int what, int on) } else { #endif #ifdef SBUS_SUPPORT + u32 csr = sbus_readl(chip->port + APCCSR); + /* I don't know why, but on sbus the period counter must + * only start counting after the first period is sent. + * Therefore this dummy thing. + */ + unsigned int dummy = 0; + + switch (what) { + case CS4231_PLAYBACK_ENABLE: + if (on) { + csr &= ~APC_XINT_PLAY; + sbus_writel(csr, chip->port + APCCSR); + + csr &= ~APC_PPAUSE; + sbus_writel(csr, chip->port + APCCSR); + + snd_cs4231_sbus_advance_dma(substream, &dummy); + + csr |= APC_GENL_INT | APC_PLAY_INT | APC_XINT_ENA | + APC_XINT_PLAY | APC_XINT_EMPT | APC_XINT_GENL | + APC_XINT_PENA | APC_PDMA_READY; + sbus_writel(csr, chip->port + APCCSR); + } else { + csr |= APC_PPAUSE; + sbus_writel(csr, chip->port + APCCSR); + + csr &= ~APC_PDMA_READY; + sbus_writel(csr, chip->port + APCCSR); + } + break; + case CS4231_RECORD_ENABLE: + if (on) { + csr &= ~APC_XINT_CAPT; + sbus_writel(csr, chip->port + APCCSR); + + csr &= ~APC_CPAUSE; + sbus_writel(csr, chip->port + APCCSR); + + snd_cs4231_sbus_advance_dma(substream, &dummy); + + csr |= APC_GENL_INT | APC_CAPT_INT | APC_XINT_ENA | + APC_XINT_CAPT | APC_XINT_CEMP | APC_XINT_GENL | + APC_CDMA_READY; + + sbus_writel(csr, chip->port + APCCSR); + } else { + csr |= APC_CPAUSE; + sbus_writel(csr, chip->port + APCCSR); + + csr &= ~APC_CDMA_READY; + sbus_writel(csr, chip->port + APCCSR); + } + break; + } #endif #ifdef EBUS_SUPPORT } @@ -725,25 +731,12 @@ static int snd_cs4231_trigger(snd_pcm_substream_t *substream, int cmd) } } -#if 0 - printk("TRIGGER: what[%x] on(%d)\n", - what, (cmd == SNDRV_PCM_TRIGGER_START)); -#endif - spin_lock_irqsave(&chip->lock, flags); if (cmd == SNDRV_PCM_TRIGGER_START) { - cs4231_dma_trigger(chip, what, 1); + cs4231_dma_trigger(substream, what, 1); chip->image[CS4231_IFACE_CTRL] |= what; - if (what & CS4231_PLAYBACK_ENABLE) { - snd_cs4231_out(chip, CS4231_PLY_LWR_CNT, 0xff); - snd_cs4231_out(chip, CS4231_PLY_UPR_CNT, 0xff); - } - if (what & CS4231_RECORD_ENABLE) { - snd_cs4231_out(chip, CS4231_REC_LWR_CNT, 0xff); - snd_cs4231_out(chip, CS4231_REC_UPR_CNT, 0xff); - } } else { - cs4231_dma_trigger(chip, what, 0); + cs4231_dma_trigger(substream, what, 0); chip->image[CS4231_IFACE_CTRL] &= ~what; } snd_cs4231_out(chip, CS4231_IFACE_CTRL, @@ -755,9 +748,7 @@ static int snd_cs4231_trigger(snd_pcm_substream_t *substream, int cmd) result = -EINVAL; break; } -#if 0 - snd_cs4231_debug(chip); -#endif + return result; } @@ -790,9 +781,6 @@ static unsigned char snd_cs4231_get_format(cs4231_t *chip, int format, int chann } if (channels > 1) rformat |= CS4231_STEREO; -#if 0 - snd_printk("get_format: 0x%x (mode=0x%x)\n", format, mode); -#endif return rformat; } @@ -944,7 +932,7 @@ static void snd_cs4231_init(cs4231_t *chip) snd_cs4231_mce_down(chip); #ifdef SNDRV_DEBUG_MCE - snd_printk("init: (1)\n"); + snd_printdd("init: (1)\n"); #endif snd_cs4231_mce_up(chip); spin_lock_irqsave(&chip->lock, flags); @@ -957,7 +945,7 @@ static void snd_cs4231_init(cs4231_t *chip) snd_cs4231_mce_down(chip); #ifdef SNDRV_DEBUG_MCE - snd_printk("init: (2)\n"); + snd_printdd("init: (2)\n"); #endif snd_cs4231_mce_up(chip); @@ -967,7 +955,7 @@ static void snd_cs4231_init(cs4231_t *chip) snd_cs4231_mce_down(chip); #ifdef SNDRV_DEBUG_MCE - snd_printk("init: (3) - afei = 0x%x\n", chip->image[CS4231_ALT_FEATURE_1]); + snd_printdd("init: (3) - afei = 0x%x\n", chip->image[CS4231_ALT_FEATURE_1]); #endif spin_lock_irqsave(&chip->lock, flags); @@ -981,7 +969,7 @@ static void snd_cs4231_init(cs4231_t *chip) snd_cs4231_mce_down(chip); #ifdef SNDRV_DEBUG_MCE - snd_printk("init: (4)\n"); + snd_printdd("init: (4)\n"); #endif snd_cs4231_mce_up(chip); @@ -991,7 +979,7 @@ static void snd_cs4231_init(cs4231_t *chip) snd_cs4231_mce_down(chip); #ifdef SNDRV_DEBUG_MCE - snd_printk("init: (5)\n"); + snd_printdd("init: (5)\n"); #endif } @@ -1022,6 +1010,7 @@ static int snd_cs4231_open(cs4231_t *chip, unsigned int mode) CS4231_RECORD_IRQ | CS4231_TIMER_IRQ); snd_cs4231_out(chip, CS4231_IRQ_STATUS, 0); + spin_unlock_irqrestore(&chip->lock, flags); chip->mode = mode; @@ -1136,11 +1125,21 @@ static int snd_cs4231_playback_hw_free(snd_pcm_substream_t *substream) static int snd_cs4231_playback_prepare(snd_pcm_substream_t *substream) { cs4231_t *chip = snd_pcm_substream_chip(substream); + snd_pcm_runtime_t *runtime = substream->runtime; unsigned long flags; spin_lock_irqsave(&chip->lock, flags); + chip->image[CS4231_IFACE_CTRL] &= ~(CS4231_PLAYBACK_ENABLE | CS4231_PLAYBACK_PIO); + + if (runtime->period_size > 0xffff + 1) + BUG(); + + snd_cs4231_out(chip, CS4231_PLY_LWR_CNT, (runtime->period_size - 1) & 0x00ff); + snd_cs4231_out(chip, CS4231_PLY_UPR_CNT, (runtime->period_size - 1) >> 8 & 0x00ff); + chip->p_periods_sent = 0; + spin_unlock_irqrestore(&chip->lock, flags); return 0; @@ -1172,12 +1171,16 @@ static int snd_cs4231_capture_hw_free(snd_pcm_substream_t *substream) static int snd_cs4231_capture_prepare(snd_pcm_substream_t *substream) { cs4231_t *chip = snd_pcm_substream_chip(substream); + snd_pcm_runtime_t *runtime = substream->runtime; unsigned long flags; spin_lock_irqsave(&chip->lock, flags); chip->image[CS4231_IFACE_CTRL] &= ~(CS4231_RECORD_ENABLE | CS4231_RECORD_PIO); + snd_cs4231_out(chip, CS4231_REC_LWR_CNT, (runtime->period_size - 1) & 0x00ff); + snd_cs4231_out(chip, CS4231_REC_LWR_CNT, (runtime->period_size - 1) >> 8 & 0x00ff); + spin_unlock_irqrestore(&chip->lock, flags); return 0; @@ -1196,53 +1199,61 @@ static void snd_cs4231_overrange(cs4231_t *chip) chip->capture_substream->runtime->overrange++; } -static void snd_cs4231_generic_interrupt(cs4231_t *chip) +static irqreturn_t snd_cs4231_generic_interrupt(cs4231_t *chip) { unsigned long flags; unsigned char status; + /*This is IRQ is not raised by the cs4231*/ + if (!(__cs4231_readb(chip, CS4231P(chip, STATUS)) & CS4231_GLOBALIRQ)) + return IRQ_NONE; + status = snd_cs4231_in(chip, CS4231_IRQ_STATUS); - if (!status) - return; if (status & CS4231_TIMER_IRQ) { if (chip->timer) snd_timer_interrupt(chip->timer, chip->timer->sticks); } - if (status & CS4231_PLAYBACK_IRQ) - snd_pcm_period_elapsed(chip->playback_substream); - if (status & CS4231_RECORD_IRQ) { + + if (status & CS4231_RECORD_IRQ) snd_cs4231_overrange(chip); - snd_pcm_period_elapsed(chip->capture_substream); - } /* ACK the CS4231 interrupt. */ spin_lock_irqsave(&chip->lock, flags); snd_cs4231_outm(chip, CS4231_IRQ_STATUS, ~CS4231_ALL_IRQS | ~status, 0); spin_unlock_irqrestore(&chip->lock, flags); + + return 0; } #ifdef SBUS_SUPPORT static irqreturn_t snd_cs4231_sbus_interrupt(int irq, void *dev_id, struct pt_regs *regs) { cs4231_t *chip = dev_id; - u32 csr; - - csr = sbus_readl(chip->port + APCCSR); - if (!(csr & (APC_INT_PENDING | - APC_PLAY_INT | - APC_CAPT_INT | - APC_GENL_INT | - APC_XINT_PEMP | - APC_XINT_CEMP))) - return IRQ_NONE; /* ACK the APC interrupt. */ + u32 csr = sbus_readl(chip->port + APCCSR); + sbus_writel(csr, chip->port + APCCSR); - snd_cs4231_generic_interrupt(chip); + if ((chip->image[CS4231_IFACE_CTRL] & CS4231_PLAYBACK_ENABLE) && + (csr & APC_PLAY_INT) && + (csr & APC_XINT_PNVA) && + !(csr & APC_XINT_EMPT)) { + snd_cs4231_sbus_advance_dma(chip->playback_substream, + &chip->p_periods_sent); + snd_pcm_period_elapsed(chip->playback_substream); + } - return IRQ_HANDLED; + if ((chip->image[CS4231_IFACE_CTRL] & CS4231_RECORD_ENABLE) && + (csr & APC_CAPT_INT) && + (csr & APC_XINT_CNVA)) { + snd_cs4231_sbus_advance_dma(chip->capture_substream, + &chip->c_periods_sent); + snd_pcm_period_elapsed(chip->capture_substream); + } + + return snd_cs4231_generic_interrupt(chip); } #endif @@ -1290,7 +1301,8 @@ static snd_pcm_uframes_t snd_cs4231_playback_pointer(snd_pcm_substream_t *substr #ifdef EBUS_SUPPORT } #endif - ptr += (period_bytes - residue); + ptr += period_bytes - residue; + return bytes_to_frames(substream->runtime, ptr); } @@ -1314,7 +1326,7 @@ static snd_pcm_uframes_t snd_cs4231_capture_pointer(snd_pcm_substream_t * substr #ifdef EBUS_SUPPORT } #endif - ptr += (period_bytes - residue); + ptr += period_bytes - residue; return bytes_to_frames(substream->runtime, ptr); } @@ -1328,9 +1340,6 @@ static int snd_cs4231_probe(cs4231_t *chip) int i, id, vers; unsigned char *ptr; -#if 0 - snd_cs4231_debug(chip); -#endif id = vers = 0; for (i = 0; i < 50; i++) { mb(); @@ -1915,6 +1924,9 @@ static int cs4231_attach_finish(snd_card_t *card, cs4231_t *chip) if ((err = snd_cs4231_timer(chip)) < 0) goto out_err; + if ((err = snd_card_set_generic_dev(card)) < 0) + goto out_err; + if ((err = snd_card_register(card)) < 0) goto out_err; @@ -1966,7 +1978,7 @@ static int __init snd_cs4231_sbus_create(snd_card_t *card, int err; *rchip = NULL; - chip = kcalloc(1, sizeof(*chip), GFP_KERNEL); + chip = kzalloc(sizeof(*chip), GFP_KERNEL); if (chip == NULL) return -ENOMEM; @@ -1982,13 +1994,13 @@ static int __init snd_cs4231_sbus_create(snd_card_t *card, chip->port = sbus_ioremap(&sdev->resource[0], 0, chip->regs_size, "cs4231"); if (!chip->port) { - snd_printk("cs4231-%d: Unable to map chip registers.\n", dev); + snd_printdd("cs4231-%d: Unable to map chip registers.\n", dev); return -EIO; } if (request_irq(sdev->irqs[0], snd_cs4231_sbus_interrupt, SA_SHIRQ, "cs4231", chip)) { - snd_printk("cs4231-%d: Unable to grab SBUS IRQ %s\n", + snd_printdd("cs4231-%d: Unable to grab SBUS IRQ %s\n", dev, __irq_itoa(sdev->irqs[0])); snd_cs4231_sbus_free(chip); @@ -2080,7 +2092,7 @@ static int __init snd_cs4231_ebus_create(snd_card_t *card, int err; *rchip = NULL; - chip = kcalloc(1, sizeof(*chip), GFP_KERNEL); + chip = kzalloc(sizeof(*chip), GFP_KERNEL); if (chip == NULL) return -ENOMEM; @@ -2110,29 +2122,29 @@ static int __init snd_cs4231_ebus_create(snd_card_t *card, chip->eb2c.regs = ioremap(edev->resource[2].start, 0x10); if (!chip->port || !chip->eb2p.regs || !chip->eb2c.regs) { snd_cs4231_ebus_free(chip); - snd_printk("cs4231-%d: Unable to map chip registers.\n", dev); + snd_printdd("cs4231-%d: Unable to map chip registers.\n", dev); return -EIO; } if (ebus_dma_register(&chip->eb2c)) { snd_cs4231_ebus_free(chip); - snd_printk("cs4231-%d: Unable to register EBUS capture DMA\n", dev); + snd_printdd("cs4231-%d: Unable to register EBUS capture DMA\n", dev); return -EBUSY; } if (ebus_dma_irq_enable(&chip->eb2c, 1)) { snd_cs4231_ebus_free(chip); - snd_printk("cs4231-%d: Unable to enable EBUS capture IRQ\n", dev); + snd_printdd("cs4231-%d: Unable to enable EBUS capture IRQ\n", dev); return -EBUSY; } if (ebus_dma_register(&chip->eb2p)) { snd_cs4231_ebus_free(chip); - snd_printk("cs4231-%d: Unable to register EBUS play DMA\n", dev); + snd_printdd("cs4231-%d: Unable to register EBUS play DMA\n", dev); return -EBUSY; } if (ebus_dma_irq_enable(&chip->eb2p, 1)) { snd_cs4231_ebus_free(chip); - snd_printk("cs4231-%d: Unable to enable EBUS play IRQ\n", dev); + snd_printdd("cs4231-%d: Unable to enable EBUS play IRQ\n", dev); return -EBUSY; } diff --git a/sound/sparc/dbri.c b/sound/sparc/dbri.c index 941c7b1..b5c4c15 100644 --- a/sound/sparc/dbri.c +++ b/sound/sparc/dbri.c @@ -1,6 +1,6 @@ /* * Driver for DBRI sound chip found on Sparcs. - * Copyright (C) 2004 Martin Habets (mhabets@users.sourceforge.net) + * Copyright (C) 2004, 2005 Martin Habets (mhabets@users.sourceforge.net) * * Based entirely upon drivers/sbus/audio/dbri.c which is: * Copyright (C) 1997 Rudolf Koenig (rfkoenig@immd4.informatik.uni-erlangen.de) @@ -43,6 +43,12 @@ * audio devices. But the SUN HW group decided against it, at least on my * LX the speakerbox connector has at least 1 pin missing and 1 wrongly * connected. + * + * I've tried to stick to the following function naming conventions: + * snd_* ALSA stuff + * cs4215_* CS4215 codec specfic stuff + * dbri_* DBRI high-level stuff + * other DBRI low-level stuff */ #include <sound/driver.h> @@ -87,7 +93,7 @@ MODULE_PARM_DESC(enable, "Enable Sun DBRI soundcard."); #define D_DESC (1<<5) static int dbri_debug = 0; -module_param(dbri_debug, int, 0444); +module_param(dbri_debug, int, 0644); MODULE_PARM_DESC(dbri_debug, "Debug value for Sun DBRI soundcard."); #ifdef DBRI_DEBUG @@ -320,7 +326,8 @@ typedef struct snd_dbri { void __iomem *regs; /* dbri HW regs */ int dbri_version; /* 'e' and up is OK */ int dbri_irqp; /* intr queue pointer */ - int wait_seen; + int wait_send; /* sequence of command buffers send */ + int wait_ackd; /* sequence of command buffers acknowledged */ struct dbri_pipe pipes[DBRI_NO_PIPES]; /* DBRI's 32 data pipes */ struct dbri_desc descs[DBRI_NO_DESCS]; @@ -625,16 +632,13 @@ static __u32 reverse_bytes(__u32 b, int len) Commands are sent to the DBRI by building a list of them in memory, then writing the address of the first list item to DBRI register 8. -The list is terminated with a WAIT command, which can generate a -CPU interrupt if required. +The list is terminated with a WAIT command, which generates a +CPU interrupt to signal completion. Since the DBRI can run in parallel with the CPU, several means of -synchronization present themselves. The original scheme (Rudolf's) -was to set a flag when we "cmdlock"ed the DBRI, clear the flag when -an interrupt signaled completion, and wait on a wait_queue if a routine -attempted to cmdlock while the flag was set. The problems arose when -we tried to cmdlock from inside an interrupt handler, which might -cause scheduling in an interrupt (if we waited), etc, etc +synchronization present themselves. The method implemented here is close +to the original scheme (Rudolf's), and uses 2 counters (wait_send and +wait_ackd) to synchronize the command buffer between the CPU and the DBRI. A more sophisticated scheme might involve a circular command buffer or an array of command buffers. A routine could fill one with @@ -642,70 +646,75 @@ commands and link it onto a list. When a interrupt signaled completion of the current command buffer, look on the list for the next one. -I've decided to implement something much simpler - after each command, -the CPU waits for the DBRI to finish the command by polling the P bit -in DBRI register 0. I've tried to implement this in such a way -that might make implementing a more sophisticated scheme easier. - Every time a routine wants to write commands to the DBRI, it must first call dbri_cmdlock() and get an initial pointer into dbri->dma->cmd -in return. After the commands have been writen, dbri_cmdsend() is -called with the final pointer value. +in return. dbri_cmdlock() will block if the previous commands have not +been completed yet. After this the commands can be written to the buffer, +and dbri_cmdsend() is called with the final pointer value to send them +to the DBRI. */ +static void dbri_process_interrupt_buffer(snd_dbri_t * dbri); + enum dbri_lock_t { NoGetLock, GetLock }; +#define MAXLOOPS 10 static volatile s32 *dbri_cmdlock(snd_dbri_t * dbri, enum dbri_lock_t get) { + int maxloops = MAXLOOPS; + #ifndef SMP if ((get == GetLock) && spin_is_locked(&dbri->lock)) { printk(KERN_ERR "DBRI: cmdlock called while in spinlock."); } #endif + /* Delay if previous commands are still being processed */ + while ((--maxloops) > 0 && (dbri->wait_send != dbri->wait_ackd)) { + msleep_interruptible(1); + /* If dbri_cmdlock() got called from inside the + * interrupt handler, this will do the processing. + */ + dbri_process_interrupt_buffer(dbri); + } + if (maxloops == 0) { + printk(KERN_ERR "DBRI: Chip never completed command buffer %d\n", + dbri->wait_send); + } else { + dprintk(D_CMD, "Chip completed command buffer (%d)\n", + MAXLOOPS - maxloops - 1); + } + /*if (get == GetLock) spin_lock(&dbri->lock); */ return &dbri->dma->cmd[0]; } -static void dbri_process_interrupt_buffer(snd_dbri_t *); - static void dbri_cmdsend(snd_dbri_t * dbri, volatile s32 * cmd) { - int MAXLOOPS = 1000000; - int maxloops = MAXLOOPS; volatile s32 *ptr; + u32 reg; for (ptr = &dbri->dma->cmd[0]; ptr < cmd; ptr++) { dprintk(D_CMD, "cmd: %lx:%08x\n", (unsigned long)ptr, *ptr); } if ((cmd - &dbri->dma->cmd[0]) >= DBRI_NO_CMDS - 1) { - printk("DBRI: Command buffer overflow! (bug in driver)\n"); + printk(KERN_ERR "DBRI: Command buffer overflow! (bug in driver)\n"); /* Ignore the last part. */ cmd = &dbri->dma->cmd[DBRI_NO_CMDS - 3]; } + dbri->wait_send++; + dbri->wait_send &= 0xffff; /* restrict it to a 16 bit counter. */ *(cmd++) = DBRI_CMD(D_PAUSE, 0, 0); - *(cmd++) = DBRI_CMD(D_WAIT, 1, 0); - dbri->wait_seen = 0; + *(cmd++) = DBRI_CMD(D_WAIT, 1, dbri->wait_send); + + /* Set command pointer and signal it is valid. */ sbus_writel(dbri->dma_dvma, dbri->regs + REG8); - while ((--maxloops) > 0 && (sbus_readl(dbri->regs + REG0) & D_P)) - barrier(); - if (maxloops == 0) { - printk(KERN_ERR "DBRI: Chip never completed command buffer\n"); - dprintk(D_CMD, "DBRI: Chip never completed command buffer\n"); - } else { - while ((--maxloops) > 0 && (!dbri->wait_seen)) - dbri_process_interrupt_buffer(dbri); - if (maxloops == 0) { - printk(KERN_ERR "DBRI: Chip never acked WAIT\n"); - dprintk(D_CMD, "DBRI: Chip never acked WAIT\n"); - } else { - dprintk(D_CMD, "Chip completed command " - "buffer (%d)\n", MAXLOOPS - maxloops); - } - } + reg = sbus_readl(dbri->regs + REG0); + reg |= D_P; + sbus_writel(reg, dbri->regs + REG0); /*spin_unlock(&dbri->lock); */ } @@ -757,10 +766,11 @@ static void dbri_initialize(snd_dbri_t * dbri) for (n = 0; n < DBRI_NO_PIPES; n++) dbri->pipes[n].desc = dbri->pipes[n].first_desc = -1; - /* We should query the openprom to see what burst sizes this - * SBus supports. For now, just disable all SBus bursts */ + /* A brute approach - DBRI falls back to working burst size by itself + * On SS20 D_S does not work, so do not try so high. */ tmp = sbus_readl(dbri->regs + REG0); - tmp &= ~(D_G | D_S | D_E); + tmp |= D_G | D_E; + tmp &= ~D_S; sbus_writel(tmp, dbri->regs + REG0); /* @@ -805,13 +815,13 @@ static void reset_pipe(snd_dbri_t * dbri, int pipe) volatile int *cmd; if (pipe < 0 || pipe > 31) { - printk("DBRI: reset_pipe called with illegal pipe number\n"); + printk(KERN_ERR "DBRI: reset_pipe called with illegal pipe number\n"); return; } sdp = dbri->pipes[pipe].sdp; if (sdp == 0) { - printk("DBRI: reset_pipe called on uninitialized pipe\n"); + printk(KERN_ERR "DBRI: reset_pipe called on uninitialized pipe\n"); return; } @@ -834,12 +844,12 @@ static void reset_pipe(snd_dbri_t * dbri, int pipe) static void setup_pipe(snd_dbri_t * dbri, int pipe, int sdp) { if (pipe < 0 || pipe > 31) { - printk("DBRI: setup_pipe called with illegal pipe number\n"); + printk(KERN_ERR "DBRI: setup_pipe called with illegal pipe number\n"); return; } if ((sdp & 0xf800) != sdp) { - printk("DBRI: setup_pipe called with strange SDP value\n"); + printk(KERN_ERR "DBRI: setup_pipe called with strange SDP value\n"); /* sdp &= 0xf800; */ } @@ -872,13 +882,13 @@ static void link_time_slot(snd_dbri_t * dbri, int pipe, int nextpipe; if (pipe < 0 || pipe > 31 || basepipe < 0 || basepipe > 31) { - printk - ("DBRI: link_time_slot called with illegal pipe number\n"); + printk(KERN_ERR + "DBRI: link_time_slot called with illegal pipe number\n"); return; } if (dbri->pipes[pipe].sdp == 0 || dbri->pipes[basepipe].sdp == 0) { - printk("DBRI: link_time_slot called on uninitialized pipe\n"); + printk(KERN_ERR "DBRI: link_time_slot called on uninitialized pipe\n"); return; } @@ -960,8 +970,8 @@ static void unlink_time_slot(snd_dbri_t * dbri, int pipe, int val; if (pipe < 0 || pipe > 31 || prevpipe < 0 || prevpipe > 31) { - printk - ("DBRI: unlink_time_slot called with illegal pipe number\n"); + printk(KERN_ERR + "DBRI: unlink_time_slot called with illegal pipe number\n"); return; } @@ -1001,22 +1011,22 @@ static void xmit_fixed(snd_dbri_t * dbri, int pipe, unsigned int data) volatile s32 *cmd; if (pipe < 16 || pipe > 31) { - printk("DBRI: xmit_fixed: Illegal pipe number\n"); + printk(KERN_ERR "DBRI: xmit_fixed: Illegal pipe number\n"); return; } if (D_SDP_MODE(dbri->pipes[pipe].sdp) == 0) { - printk("DBRI: xmit_fixed: Uninitialized pipe %d\n", pipe); + printk(KERN_ERR "DBRI: xmit_fixed: Uninitialized pipe %d\n", pipe); return; } if (D_SDP_MODE(dbri->pipes[pipe].sdp) != D_SDP_FIXED) { - printk("DBRI: xmit_fixed: Non-fixed pipe %d\n", pipe); + printk(KERN_ERR "DBRI: xmit_fixed: Non-fixed pipe %d\n", pipe); return; } if (!(dbri->pipes[pipe].sdp & D_SDP_TO_SER)) { - printk("DBRI: xmit_fixed: Called on receive pipe %d\n", pipe); + printk(KERN_ERR "DBRI: xmit_fixed: Called on receive pipe %d\n", pipe); return; } @@ -1036,17 +1046,17 @@ static void xmit_fixed(snd_dbri_t * dbri, int pipe, unsigned int data) static void recv_fixed(snd_dbri_t * dbri, int pipe, volatile __u32 * ptr) { if (pipe < 16 || pipe > 31) { - printk("DBRI: recv_fixed called with illegal pipe number\n"); + printk(KERN_ERR "DBRI: recv_fixed called with illegal pipe number\n"); return; } if (D_SDP_MODE(dbri->pipes[pipe].sdp) != D_SDP_FIXED) { - printk("DBRI: recv_fixed called on non-fixed pipe %d\n", pipe); + printk(KERN_ERR "DBRI: recv_fixed called on non-fixed pipe %d\n", pipe); return; } if (dbri->pipes[pipe].sdp & D_SDP_TO_SER) { - printk("DBRI: recv_fixed called on transmit pipe %d\n", pipe); + printk(KERN_ERR "DBRI: recv_fixed called on transmit pipe %d\n", pipe); return; } @@ -1075,12 +1085,12 @@ static int setup_descs(snd_dbri_t * dbri, int streamno, unsigned int period) int last_desc = -1; if (info->pipe < 0 || info->pipe > 15) { - printk("DBRI: setup_descs: Illegal pipe number\n"); + printk(KERN_ERR "DBRI: setup_descs: Illegal pipe number\n"); return -2; } if (dbri->pipes[info->pipe].sdp == 0) { - printk("DBRI: setup_descs: Uninitialized pipe %d\n", + printk(KERN_ERR "DBRI: setup_descs: Uninitialized pipe %d\n", info->pipe); return -2; } @@ -1090,20 +1100,20 @@ static int setup_descs(snd_dbri_t * dbri, int streamno, unsigned int period) if (streamno == DBRI_PLAY) { if (!(dbri->pipes[info->pipe].sdp & D_SDP_TO_SER)) { - printk("DBRI: setup_descs: Called on receive pipe %d\n", + printk(KERN_ERR "DBRI: setup_descs: Called on receive pipe %d\n", info->pipe); return -2; } } else { if (dbri->pipes[info->pipe].sdp & D_SDP_TO_SER) { - printk - ("DBRI: setup_descs: Called on transmit pipe %d\n", + printk(KERN_ERR + "DBRI: setup_descs: Called on transmit pipe %d\n", info->pipe); return -2; } /* Should be able to queue multiple buffers to receive on a pipe */ if (pipe_active(dbri, info->pipe)) { - printk("DBRI: recv_on_pipe: Called on active pipe %d\n", + printk(KERN_ERR "DBRI: recv_on_pipe: Called on active pipe %d\n", info->pipe); return -2; } @@ -1120,7 +1130,7 @@ static int setup_descs(snd_dbri_t * dbri, int streamno, unsigned int period) break; } if (desc == DBRI_NO_DESCS) { - printk("DBRI: setup_descs: No descriptors\n"); + printk(KERN_ERR "DBRI: setup_descs: No descriptors\n"); return -1; } @@ -1165,7 +1175,7 @@ static int setup_descs(snd_dbri_t * dbri, int streamno, unsigned int period) } if (first_desc == -1 || last_desc == -1) { - printk("DBRI: setup_descs: Not enough descriptors available\n"); + printk(KERN_ERR "DBRI: setup_descs: Not enough descriptors available\n"); return -1; } @@ -1270,7 +1280,7 @@ static void reset_chi(snd_dbri_t * dbri, enum master_or_slave master_or_slave, int divisor = 12288 / clockrate; if (divisor > 255 || divisor * clockrate != 12288) - printk("DBRI: illegal bits_per_frame in setup_chi\n"); + printk(KERN_ERR "DBRI: illegal bits_per_frame in setup_chi\n"); *(cmd++) = DBRI_CMD(D_CHI, 0, D_CHI_CHICM(divisor) | D_CHI_FD | D_CHI_BPF(bits_per_frame)); @@ -1474,7 +1484,6 @@ static int cs4215_setctrl(snd_dbri_t * dbri) /* Temporarily mute outputs, and wait 1/8000 sec (125 us) * to make sure this takes. This avoids clicking noises. */ - cs4215_setdata(dbri, 1); udelay(125); @@ -1530,8 +1539,8 @@ static int cs4215_setctrl(snd_dbri_t * dbri) tmp |= D_C; /* Enable CHI */ sbus_writel(tmp, dbri->regs + REG0); - for (i = 64; ((dbri->mm.status & 0xe4) != 0x20); --i) { - udelay(125); + for (i = 10; ((dbri->mm.status & 0xe4) != 0x20); --i) { + msleep_interruptible(1); } if (i == 0) { dprintk(D_MM, "CS4215 didn't respond to CLB (0x%02x)\n", @@ -1678,8 +1687,8 @@ buffer and calls dbri_process_one_interrupt() for each interrupt word. Complicated interrupts are handled by dedicated functions (which appear first in this file). Any pending interrupts can be serviced by calling dbri_process_interrupt_buffer(), which works even if the CPU's -interrupts are disabled. This function is used by dbri_cmdsend() -to make sure we're synced up with the chip after each command sequence, +interrupts are disabled. This function is used by dbri_cmdlock() +to make sure we're synced up with the chip before each command sequence, even if we're running cli'ed. */ @@ -1765,11 +1774,13 @@ DECLARE_TASKLET(xmit_descs_task, xmit_descs, 0); * Called by main interrupt handler when DBRI signals transmission complete * on a pipe (interrupt triggered by the B bit in a transmit descriptor). * - * Walks through the pipe's list of transmit buffer descriptors, releasing - * each one's DMA buffer (if present), flagging the descriptor available, - * and signaling its callback routine (if present), before proceeding - * to the next one. Stops when the first descriptor is found without + * Walks through the pipe's list of transmit buffer descriptors and marks + * them as available. Stops when the first descriptor is found without * TBC (Transmit Buffer Complete) set, or we've run through them all. + * + * The DMA buffers are not released, but re-used. Since the transmit buffer + * descriptors are not clobbered, they can be re-submitted as is. This is + * done by the xmit_descs() tasklet above since that could take longer. */ static void transmission_complete_intr(snd_dbri_t * dbri, int pipe) @@ -1885,7 +1896,11 @@ static void dbri_process_one_interrupt(snd_dbri_t * dbri, int x) } if (channel == D_INTR_CMD && command == D_WAIT) { - dbri->wait_seen++; + dbri->wait_ackd = val; + if (dbri->wait_send != val) { + printk(KERN_ERR "Processing wait command %d when %d was send.\n", + val, dbri->wait_send); + } return; } @@ -1994,8 +2009,7 @@ static irqreturn_t snd_dbri_interrupt(int irq, void *dev_id, * The only one I've seen is MRR, which will be triggered * if you let a transmit pipe underrun, then try to CDP it. * - * If these things persist, we should probably reset - * and re-init the chip. + * If these things persist, we reset the chip. */ if ((++errcnt) % 10 == 0) { dprintk(D_INT, "Interrupt errors exceeded.\n"); @@ -2094,7 +2108,7 @@ static int snd_dbri_hw_params(snd_pcm_substream_t * substream, if ((ret = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params))) < 0) { - snd_printk(KERN_ERR "malloc_pages failed with %d\n", ret); + printk(KERN_ERR "malloc_pages failed with %d\n", ret); return ret; } @@ -2455,8 +2469,7 @@ static int __init snd_dbri_mixer(snd_dbri_t * dbri) for (idx = 0; idx < NUM_CS4215_CONTROLS; idx++) { if ((err = snd_ctl_add(card, - snd_ctl_new1(&dbri_controls[idx], - dbri))) < 0) + snd_ctl_new1(&dbri_controls[idx], dbri))) < 0) return err; } @@ -2490,8 +2503,6 @@ static void dbri_debug_read(snd_info_entry_t * entry, int pipe; snd_iprintf(buffer, "debug=%d\n", dbri_debug); - snd_iprintf(buffer, "CHI pipe in=%d, out=%d\n", - dbri->chi_in_pipe, dbri->chi_out_pipe); for (pipe = 0; pipe < 32; pipe++) { if (pipe_active(dbri, pipe)) { struct dbri_pipe *pptr = &dbri->pipes[pipe]; @@ -2506,18 +2517,6 @@ static void dbri_debug_read(snd_info_entry_t * entry, } } } - -static void dbri_debug_write(snd_info_entry_t * entry, - snd_info_buffer_t * buffer) -{ - char line[80]; - int i; - - if (snd_info_get_line(buffer, line, 80) == 0) { - sscanf(line, "%d\n", &i); - dbri_debug = i & 0x3f; - } -} #endif void snd_dbri_proc(snd_dbri_t * dbri) @@ -2531,9 +2530,7 @@ void snd_dbri_proc(snd_dbri_t * dbri) #ifdef DBRI_DEBUG err = snd_card_proc_new(dbri->card, "debug", &entry); snd_info_set_text_ops(entry, dbri, 4096, dbri_debug_read); - entry->mode = S_IFREG | S_IRUGO | S_IWUSR; /* Writable for root */ - entry->c.text.write_size = 256; - entry->c.text.write = dbri_debug_write; + entry->mode = S_IFREG | S_IRUGO; /* Readable only. */ #endif } @@ -2637,7 +2634,11 @@ static int __init dbri_attach(int prom_node, struct sbus_dev *sdev) return -ENOENT; } - prom_getproperty(prom_node, "intr", (char *)&irq, sizeof(irq)); + err = prom_getproperty(prom_node, "intr", (char *)&irq, sizeof(irq)); + if (err < 0) { + printk(KERN_ERR "DBRI-%d: Firmware node lacks IRQ property.\n", dev); + return -ENODEV; + } card = snd_card_new(index[dev], id[dev], THIS_MODULE, sizeof(snd_dbri_t)); @@ -2657,26 +2658,20 @@ static int __init dbri_attach(int prom_node, struct sbus_dev *sdev) } dbri = (snd_dbri_t *) card->private_data; - if ((err = snd_dbri_pcm(dbri)) < 0) { - snd_dbri_free(dbri); - snd_card_free(card); - return err; - } + if ((err = snd_dbri_pcm(dbri)) < 0) + goto _err; - if ((err = snd_dbri_mixer(dbri)) < 0) { - snd_dbri_free(dbri); - snd_card_free(card); - return err; - } + if ((err = snd_dbri_mixer(dbri)) < 0) + goto _err; /* /proc file handling */ snd_dbri_proc(dbri); - if ((err = snd_card_register(card)) < 0) { - snd_dbri_free(dbri); - snd_card_free(card); - return err; - } + if ((err = snd_card_set_generic_dev(card)) < 0) + goto _err; + + if ((err = snd_card_register(card)) < 0) + goto _err; printk(KERN_INFO "audio%d at %p (irq %d) is DBRI(%c)+CS4215(%d)\n", dev, dbri->regs, @@ -2684,6 +2679,11 @@ static int __init dbri_attach(int prom_node, struct sbus_dev *sdev) dev++; return 0; + + _err: + snd_dbri_free(dbri); + snd_card_free(card); + return err; } /* Probe for the dbri chip and then attach the driver. */ diff --git a/sound/synth/emux/emux.c b/sound/synth/emux/emux.c index 60d0b2c..9e2b4c0 100644 --- a/sound/synth/emux/emux.c +++ b/sound/synth/emux/emux.c @@ -40,7 +40,7 @@ int snd_emux_new(snd_emux_t **remu) snd_emux_t *emu; *remu = NULL; - emu = kcalloc(1, sizeof(*emu), GFP_KERNEL); + emu = kzalloc(sizeof(*emu), GFP_KERNEL); if (emu == NULL) return -ENOMEM; diff --git a/sound/synth/emux/emux_seq.c b/sound/synth/emux/emux_seq.c index e41b28d..8ccd33f 100644 --- a/sound/synth/emux/emux_seq.c +++ b/sound/synth/emux/emux_seq.c @@ -146,7 +146,7 @@ snd_emux_create_port(snd_emux_t *emu, char *name, int i, type, cap; /* Allocate structures for this channel */ - if ((p = kcalloc(1, sizeof(*p), GFP_KERNEL)) == NULL) { + if ((p = kzalloc(sizeof(*p), GFP_KERNEL)) == NULL) { snd_printk("no memory\n"); return NULL; } diff --git a/sound/synth/emux/soundfont.c b/sound/synth/emux/soundfont.c index 901a7db..d0925ea 100644 --- a/sound/synth/emux/soundfont.c +++ b/sound/synth/emux/soundfont.c @@ -266,7 +266,7 @@ newsf(snd_sf_list_t *sflist, int type, char *name) } /* not found -- create a new one */ - sf = kcalloc(1, sizeof(*sf), GFP_KERNEL); + sf = kzalloc(sizeof(*sf), GFP_KERNEL); if (sf == NULL) return NULL; sf->id = sflist->fonts_size; @@ -346,7 +346,7 @@ sf_zone_new(snd_sf_list_t *sflist, snd_soundfont_t *sf) { snd_sf_zone_t *zp; - if ((zp = kcalloc(1, sizeof(*zp), GFP_KERNEL)) == NULL) + if ((zp = kzalloc(sizeof(*zp), GFP_KERNEL)) == NULL) return NULL; zp->next = sf->zones; sf->zones = zp; @@ -377,7 +377,7 @@ sf_sample_new(snd_sf_list_t *sflist, snd_soundfont_t *sf) { snd_sf_sample_t *sp; - if ((sp = kcalloc(1, sizeof(*sp), GFP_KERNEL)) == NULL) + if ((sp = kzalloc(sizeof(*sp), GFP_KERNEL)) == NULL) return NULL; sp->next = sf->samples; @@ -1362,7 +1362,7 @@ snd_sf_new(snd_sf_callback_t *callback, snd_util_memhdr_t *hdr) { snd_sf_list_t *sflist; - if ((sflist = kcalloc(1, sizeof(*sflist), GFP_KERNEL)) == NULL) + if ((sflist = kzalloc(sizeof(*sflist), GFP_KERNEL)) == NULL) return NULL; init_MUTEX(&sflist->presets_mutex); diff --git a/sound/synth/util_mem.c b/sound/synth/util_mem.c index 8b131a1..5f75bf3 100644 --- a/sound/synth/util_mem.c +++ b/sound/synth/util_mem.c @@ -38,7 +38,7 @@ snd_util_memhdr_new(int memsize) { snd_util_memhdr_t *hdr; - hdr = kcalloc(1, sizeof(*hdr), GFP_KERNEL); + hdr = kzalloc(sizeof(*hdr), GFP_KERNEL); if (hdr == NULL) return NULL; hdr->size = memsize; diff --git a/sound/usb/usbaudio.c b/sound/usb/usbaudio.c index bfbec58..d5ae2055 100644 --- a/sound/usb/usbaudio.c +++ b/sound/usb/usbaudio.c @@ -1439,9 +1439,11 @@ static int snd_usb_pcm_prepare(snd_pcm_substream_t *substream) static snd_pcm_hardware_t snd_usb_playback = { - .info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED | - SNDRV_PCM_INFO_BLOCK_TRANSFER | - SNDRV_PCM_INFO_MMAP_VALID), + .info = SNDRV_PCM_INFO_MMAP | + SNDRV_PCM_INFO_MMAP_VALID | + SNDRV_PCM_INFO_BATCH | + SNDRV_PCM_INFO_INTERLEAVED | + SNDRV_PCM_INFO_BLOCK_TRANSFER, .buffer_bytes_max = (256*1024), .period_bytes_min = 64, .period_bytes_max = (128*1024), @@ -1451,9 +1453,11 @@ static snd_pcm_hardware_t snd_usb_playback = static snd_pcm_hardware_t snd_usb_capture = { - .info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED | - SNDRV_PCM_INFO_BLOCK_TRANSFER | - SNDRV_PCM_INFO_MMAP_VALID), + .info = SNDRV_PCM_INFO_MMAP | + SNDRV_PCM_INFO_MMAP_VALID | + SNDRV_PCM_INFO_BATCH | + SNDRV_PCM_INFO_INTERLEAVED | + SNDRV_PCM_INFO_BLOCK_TRANSFER, .buffer_bytes_max = (256*1024), .period_bytes_min = 64, .period_bytes_max = (128*1024), @@ -3132,7 +3136,7 @@ static int snd_usb_audio_create(struct usb_device *dev, int idx, return -ENOMEM; } - chip = kcalloc(1, sizeof(*chip), GFP_KERNEL); + chip = kzalloc(sizeof(*chip), GFP_KERNEL); if (! chip) { snd_card_free(card); return -ENOMEM; diff --git a/sound/usb/usbmidi.c b/sound/usb/usbmidi.c index 93dedde..e0d0365 100644 --- a/sound/usb/usbmidi.c +++ b/sound/usb/usbmidi.c @@ -841,7 +841,7 @@ static int snd_usbmidi_in_endpoint_create(snd_usb_midi_t* umidi, int length; rep->in = NULL; - ep = kcalloc(1, sizeof(*ep), GFP_KERNEL); + ep = kzalloc(sizeof(*ep), GFP_KERNEL); if (!ep) return -ENOMEM; ep->umidi = umidi; @@ -913,7 +913,7 @@ static int snd_usbmidi_out_endpoint_create(snd_usb_midi_t* umidi, void* buffer; rep->out = NULL; - ep = kcalloc(1, sizeof(*ep), GFP_KERNEL); + ep = kzalloc(sizeof(*ep), GFP_KERNEL); if (!ep) return -ENOMEM; ep->umidi = umidi; @@ -1537,7 +1537,7 @@ int snd_usb_create_midi_interface(snd_usb_audio_t* chip, int out_ports, in_ports; int i, err; - umidi = kcalloc(1, sizeof(*umidi), GFP_KERNEL); + umidi = kzalloc(sizeof(*umidi), GFP_KERNEL); if (!umidi) return -ENOMEM; umidi->chip = chip; diff --git a/sound/usb/usbmixer.c b/sound/usb/usbmixer.c index fa7056f..c3c08c9 100644 --- a/sound/usb/usbmixer.c +++ b/sound/usb/usbmixer.c @@ -824,7 +824,7 @@ static void build_feature_ctl(mixer_build_t *state, unsigned char *desc, if (check_ignored_ctl(state, unitid, control)) return; - cval = kcalloc(1, sizeof(*cval), GFP_KERNEL); + cval = kzalloc(sizeof(*cval), GFP_KERNEL); if (! cval) { snd_printk(KERN_ERR "cannot malloc kcontrol\n"); return; @@ -997,7 +997,7 @@ static void build_mixer_unit_ctl(mixer_build_t *state, unsigned char *desc, if (check_ignored_ctl(state, unitid, 0)) return; - cval = kcalloc(1, sizeof(*cval), GFP_KERNEL); + cval = kzalloc(sizeof(*cval), GFP_KERNEL); if (! cval) return; @@ -1244,7 +1244,7 @@ static int build_audio_procunit(mixer_build_t *state, int unitid, unsigned char continue; if (check_ignored_ctl(state, unitid, valinfo->control)) continue; - cval = kcalloc(1, sizeof(*cval), GFP_KERNEL); + cval = kzalloc(sizeof(*cval), GFP_KERNEL); if (! cval) { snd_printk(KERN_ERR "cannot malloc kcontrol\n"); return -ENOMEM; @@ -1430,7 +1430,7 @@ static int parse_audio_selector_unit(mixer_build_t *state, int unitid, unsigned if (check_ignored_ctl(state, unitid, 0)) return 0; - cval = kcalloc(1, sizeof(*cval), GFP_KERNEL); + cval = kzalloc(sizeof(*cval), GFP_KERNEL); if (! cval) { snd_printk(KERN_ERR "cannot malloc kcontrol\n"); return -ENOMEM; @@ -1945,7 +1945,7 @@ int snd_usb_create_mixer(snd_usb_audio_t *chip, int ctrlif) strcpy(chip->card->mixername, "USB Mixer"); - mixer = kcalloc(1, sizeof(*mixer), GFP_KERNEL); + mixer = kzalloc(sizeof(*mixer), GFP_KERNEL); if (!mixer) return -ENOMEM; mixer->chip = chip; diff --git a/sound/usb/usx2y/usbusx2yaudio.c b/sound/usb/usx2y/usbusx2yaudio.c index 62dfd28..0f09e0d 100644 --- a/sound/usb/usx2y/usbusx2yaudio.c +++ b/sound/usb/usx2y/usbusx2yaudio.c @@ -957,7 +957,7 @@ static int usX2Y_audio_stream_new(snd_card_t *card, int playback_endpoint, int c for (i = playback_endpoint ? SNDRV_PCM_STREAM_PLAYBACK : SNDRV_PCM_STREAM_CAPTURE; i <= SNDRV_PCM_STREAM_CAPTURE; ++i) { - usX2Y_substream[i] = kcalloc(1, sizeof(snd_usX2Y_substream_t), GFP_KERNEL); + usX2Y_substream[i] = kzalloc(sizeof(snd_usX2Y_substream_t), GFP_KERNEL); if (NULL == usX2Y_substream[i]) { snd_printk(KERN_ERR "cannot malloc\n"); return -ENOMEM; |