diff options
614 files changed, 16611 insertions, 8393 deletions
diff --git a/Documentation/00-INDEX b/Documentation/00-INDEX index 8d556707bb6..30b327a116e 100644 --- a/Documentation/00-INDEX +++ b/Documentation/00-INDEX @@ -109,6 +109,8 @@ cpu-hotplug.txt - document describing CPU hotplug support in the Linux kernel. cpu-load.txt - document describing how CPU load statistics are collected. +cpuidle/ + - info on CPU_IDLE, CPU idle state management subsystem. cpusets.txt - documents the cpusets feature; assign CPUs and Mem to a set of tasks. cputopology.txt diff --git a/Documentation/DocBook/Makefile b/Documentation/DocBook/Makefile index 6a0ad4715e9..300e1707893 100644 --- a/Documentation/DocBook/Makefile +++ b/Documentation/DocBook/Makefile @@ -8,7 +8,7 @@ DOCBOOKS := wanbook.xml z8530book.xml mcabook.xml videobook.xml \ kernel-hacking.xml kernel-locking.xml deviceiobook.xml \ - procfs-guide.xml writing_usb_driver.xml \ + procfs-guide.xml writing_usb_driver.xml networking.xml \ kernel-api.xml filesystems.xml lsm.xml usb.xml \ gadget.xml libata.xml mtdnand.xml librs.xml rapidio.xml \ genericirq.xml s390-drivers.xml uio-howto.xml scsi.xml diff --git a/Documentation/DocBook/filesystems.tmpl b/Documentation/DocBook/filesystems.tmpl index 5eaef87e8f1..5e87ad58c0b 100644 --- a/Documentation/DocBook/filesystems.tmpl +++ b/Documentation/DocBook/filesystems.tmpl @@ -398,4 +398,24 @@ an example. </chapter> + <chapter id="splice"> + <title>splice API</title> + <para> + splice is a method for moving blocks of data around inside the + kernel, without continually transferring them between the kernel + and user space. + </para> +!Ffs/splice.c + </chapter> + + <chapter id="pipes"> + <title>pipes API</title> + <para> + Pipe interfaces are all for in-kernel (builtin image) use. + They are not exported for use by modules. + </para> +!Iinclude/linux/pipe_fs_i.h +!Ffs/pipe.c + </chapter> + </book> diff --git a/Documentation/DocBook/kernel-api.tmpl b/Documentation/DocBook/kernel-api.tmpl index 059aaf20951..f31601e8bd8 100644 --- a/Documentation/DocBook/kernel-api.tmpl +++ b/Documentation/DocBook/kernel-api.tmpl @@ -204,65 +204,6 @@ X!Ilib/string.c </sect1> </chapter> - <chapter id="netcore"> - <title>Linux Networking</title> - <sect1><title>Networking Base Types</title> -!Iinclude/linux/net.h - </sect1> - <sect1><title>Socket Buffer Functions</title> -!Iinclude/linux/skbuff.h -!Iinclude/net/sock.h -!Enet/socket.c -!Enet/core/skbuff.c -!Enet/core/sock.c -!Enet/core/datagram.c -!Enet/core/stream.c - </sect1> - <sect1><title>Socket Filter</title> -!Enet/core/filter.c - </sect1> - <sect1><title>Generic Network Statistics</title> -!Iinclude/linux/gen_stats.h -!Enet/core/gen_stats.c -!Enet/core/gen_estimator.c - </sect1> - <sect1><title>SUN RPC subsystem</title> -<!-- The !D functionality is not perfect, garbage has to be protected by comments -!Dnet/sunrpc/sunrpc_syms.c ---> -!Enet/sunrpc/xdr.c -!Enet/sunrpc/svcsock.c -!Enet/sunrpc/sched.c - </sect1> - </chapter> - - <chapter id="netdev"> - <title>Network device support</title> - <sect1><title>Driver Support</title> -!Enet/core/dev.c -!Enet/ethernet/eth.c -!Enet/sched/sch_generic.c -!Iinclude/linux/etherdevice.h -!Iinclude/linux/netdevice.h - </sect1> - <sect1><title>PHY Support</title> -!Edrivers/net/phy/phy.c -!Idrivers/net/phy/phy.c -!Edrivers/net/phy/phy_device.c -!Idrivers/net/phy/phy_device.c -!Edrivers/net/phy/mdio_bus.c -!Idrivers/net/phy/mdio_bus.c - </sect1> -<!-- FIXME: Removed for now since no structured comments in source - <sect1><title>Wireless</title> -X!Enet/core/wireless.c - </sect1> ---> - <sect1><title>Synchronous PPP</title> -!Edrivers/net/wan/syncppp.c - </sect1> - </chapter> - <chapter id="modload"> <title>Module Support</title> <sect1><title>Module Loading</title> @@ -508,11 +449,6 @@ X!Isound/sound_firmware.c !Edrivers/serial/8250.c </chapter> - <chapter id="z85230"> - <title>Z85230 Support Library</title> -!Edrivers/net/wan/z85230.c - </chapter> - <chapter id="fbdev"> <title>Frame Buffer Library</title> @@ -712,24 +648,4 @@ X!Idrivers/video/console/fonts.c !Edrivers/i2c/i2c-core.c </chapter> - <chapter id="splice"> - <title>splice API</title> - <para> - splice is a method for moving blocks of data around inside the - kernel, without continually transferring them between the kernel - and user space. - </para> -!Ffs/splice.c - </chapter> - - <chapter id="pipes"> - <title>pipes API</title> - <para> - Pipe interfaces are all for in-kernel (builtin image) use. - They are not exported for use by modules. - </para> -!Iinclude/linux/pipe_fs_i.h -!Ffs/pipe.c - </chapter> - </book> diff --git a/Documentation/DocBook/networking.tmpl b/Documentation/DocBook/networking.tmpl new file mode 100644 index 00000000000..f24f9e85e4a --- /dev/null +++ b/Documentation/DocBook/networking.tmpl @@ -0,0 +1,106 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.1.2//EN" + "http://www.oasis-open.org/docbook/xml/4.1.2/docbookx.dtd" []> + +<book id="LinuxNetworking"> + <bookinfo> + <title>Linux Networking and Network Devices APIs</title> + + <legalnotice> + <para> + This documentation is free software; 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. + </para> + + <para> + 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. + </para> + + <para> + 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 + </para> + + <para> + For more details see the file COPYING in the source + distribution of Linux. + </para> + </legalnotice> + </bookinfo> + +<toc></toc> + + <chapter id="netcore"> + <title>Linux Networking</title> + <sect1><title>Networking Base Types</title> +!Iinclude/linux/net.h + </sect1> + <sect1><title>Socket Buffer Functions</title> +!Iinclude/linux/skbuff.h +!Iinclude/net/sock.h +!Enet/socket.c +!Enet/core/skbuff.c +!Enet/core/sock.c +!Enet/core/datagram.c +!Enet/core/stream.c + </sect1> + <sect1><title>Socket Filter</title> +!Enet/core/filter.c + </sect1> + <sect1><title>Generic Network Statistics</title> +!Iinclude/linux/gen_stats.h +!Enet/core/gen_stats.c +!Enet/core/gen_estimator.c + </sect1> + <sect1><title>SUN RPC subsystem</title> +<!-- The !D functionality is not perfect, garbage has to be protected by comments +!Dnet/sunrpc/sunrpc_syms.c +--> +!Enet/sunrpc/xdr.c +!Enet/sunrpc/svc_xprt.c +!Enet/sunrpc/xprt.c +!Enet/sunrpc/sched.c +!Enet/sunrpc/socklib.c +!Enet/sunrpc/stats.c +!Enet/sunrpc/rpc_pipe.c +!Enet/sunrpc/rpcb_clnt.c +!Enet/sunrpc/clnt.c + </sect1> + </chapter> + + <chapter id="netdev"> + <title>Network device support</title> + <sect1><title>Driver Support</title> +!Enet/core/dev.c +!Enet/ethernet/eth.c +!Enet/sched/sch_generic.c +!Iinclude/linux/etherdevice.h +!Iinclude/linux/netdevice.h + </sect1> + <sect1><title>PHY Support</title> +!Edrivers/net/phy/phy.c +!Idrivers/net/phy/phy.c +!Edrivers/net/phy/phy_device.c +!Idrivers/net/phy/phy_device.c +!Edrivers/net/phy/mdio_bus.c +!Idrivers/net/phy/mdio_bus.c + </sect1> +<!-- FIXME: Removed for now since no structured comments in source + <sect1><title>Wireless</title> +X!Enet/core/wireless.c + </sect1> +--> + <sect1><title>Synchronous PPP</title> +!Edrivers/net/wan/syncppp.c + </sect1> + </chapter> + +</book> diff --git a/Documentation/RCU/NMI-RCU.txt b/Documentation/RCU/NMI-RCU.txt index d0634a5c344..c64158ecde4 100644 --- a/Documentation/RCU/NMI-RCU.txt +++ b/Documentation/RCU/NMI-RCU.txt @@ -25,7 +25,7 @@ the NMI handler to take the default machine-specific action. This nmi_callback variable is a global function pointer to the current NMI handler. - fastcall void do_nmi(struct pt_regs * regs, long error_code) + void do_nmi(struct pt_regs * regs, long error_code) { int cpu; diff --git a/Documentation/SubmitChecklist b/Documentation/SubmitChecklist index 34e06d2f194..da10e071424 100644 --- a/Documentation/SubmitChecklist +++ b/Documentation/SubmitChecklist @@ -20,7 +20,11 @@ kernel patches. 4: ppc64 is a good architecture for cross-compilation checking because it tends to use `unsigned long' for 64-bit quantities. -5: Matches kernel coding style(!) +5: Check your patch for general style as detailed in + Documentation/CodingStyle. Check for trivial violations with the + patch style checker prior to submission (scripts/checkpatch.pl). + You should be able to justify all violations that remain in + your patch. 6: Any new or modified CONFIG options don't muck up the config menu. @@ -79,13 +83,3 @@ kernel patches. 23: Tested after it has been merged into the -mm patchset to make sure that it still works with all of the other queued patches and various changes in the VM, VFS, and other subsystems. - -24: Avoid whitespace damage such as indenting with spaces or whitespace - at the end of lines. You can test this by feeding the patch to - "git apply --check --whitespace=error-all" - -25: Check your patch for general style as detailed in - Documentation/CodingStyle. Check for trivial violations with the - patch style checker prior to submission (scripts/checkpatch.pl). - You should be able to justify all violations that remain in - your patch. diff --git a/Documentation/cpuidle/core.txt b/Documentation/cpuidle/core.txt new file mode 100644 index 00000000000..63ecc5dc9d8 --- /dev/null +++ b/Documentation/cpuidle/core.txt @@ -0,0 +1,23 @@ + + Supporting multiple CPU idle levels in kernel + + cpuidle + +General Information: + +Various CPUs today support multiple idle levels that are differentiated +by varying exit latencies and power consumption during idle. +cpuidle is a generic in-kernel infrastructure that separates +idle policy (governor) from idle mechanism (driver) and provides a +standardized infrastructure to support independent development of +governors and drivers. + +cpuidle resides under drivers/cpuidle. + +Boot options: +"cpuidle_sysfs_switch" +enables current_governor interface in /sys/devices/system/cpu/cpuidle/, +which can be used to switch governors at run time. This boot option +is meant for developer testing only. In normal usage, kernel picks the +best governor based on governor ratings. +SEE ALSO: sysfs.txt in this directory. diff --git a/Documentation/cpuidle/driver.txt b/Documentation/cpuidle/driver.txt new file mode 100644 index 00000000000..7a9e09ece93 --- /dev/null +++ b/Documentation/cpuidle/driver.txt @@ -0,0 +1,31 @@ + + + Supporting multiple CPU idle levels in kernel + + cpuidle drivers + + + + +cpuidle driver hooks into the cpuidle infrastructure and handles the +architecture/platform dependent part of CPU idle states. Driver +provides the platform idle state detection capability and also +has mechanisms in place to support actual entry-exit into CPU idle states. + +cpuidle driver initializes the cpuidle_device structure for each CPU device +and registers with cpuidle using cpuidle_register_device. + +It can also support the dynamic changes (like battery <-> AC), by using +cpuidle_pause_and_lock, cpuidle_disable_device and cpuidle_enable_device, +cpuidle_resume_and_unlock. + +Interfaces: +extern int cpuidle_register_driver(struct cpuidle_driver *drv); +extern void cpuidle_unregister_driver(struct cpuidle_driver *drv); +extern int cpuidle_register_device(struct cpuidle_device *dev); +extern void cpuidle_unregister_device(struct cpuidle_device *dev); + +extern void cpuidle_pause_and_lock(void); +extern void cpuidle_resume_and_unlock(void); +extern int cpuidle_enable_device(struct cpuidle_device *dev); +extern void cpuidle_disable_device(struct cpuidle_device *dev); diff --git a/Documentation/cpuidle/governor.txt b/Documentation/cpuidle/governor.txt new file mode 100644 index 00000000000..12c6bd50c9f --- /dev/null +++ b/Documentation/cpuidle/governor.txt @@ -0,0 +1,29 @@ + + + + Supporting multiple CPU idle levels in kernel + + cpuidle governors + + + + +cpuidle governor is policy routine that decides what idle state to enter at +any given time. cpuidle core uses different callbacks to the governor. + +* enable() to enable governor for a particular device +* disable() to disable governor for a particular device +* select() to select an idle state to enter +* reflect() called after returning from the idle state, which can be used + by the governor for some record keeping. + +More than one governor can be registered at the same time and +users can switch between drivers using /sysfs interface (when enabled). +More than one governor part is supported for developers to easily experiment +with different governors. By default, most optimal governor based on your +kernel configuration and platform will be selected by cpuidle. + +Interfaces: +extern int cpuidle_register_governor(struct cpuidle_governor *gov); +extern void cpuidle_unregister_governor(struct cpuidle_governor *gov); +struct cpuidle_governor diff --git a/Documentation/cpuidle/sysfs.txt b/Documentation/cpuidle/sysfs.txt new file mode 100644 index 00000000000..50d7b164275 --- /dev/null +++ b/Documentation/cpuidle/sysfs.txt @@ -0,0 +1,79 @@ + + + Supporting multiple CPU idle levels in kernel + + cpuidle sysfs + +System global cpuidle related information and tunables are under +/sys/devices/system/cpu/cpuidle + +The current interfaces in this directory has self-explanatory names: +* current_driver +* current_governor_ro + +With cpuidle_sysfs_switch boot option (meant for developer testing) +following objects are visible instead. +* current_driver +* available_governors +* current_governor +In this case users can switch the governor at run time by writing +to current_governor. + + +Per logical CPU specific cpuidle information are under +/sys/devices/system/cpu/cpuX/cpuidle +for each online cpu X + +-------------------------------------------------------------------------------- +# ls -lR /sys/devices/system/cpu/cpu0/cpuidle/ +/sys/devices/system/cpu/cpu0/cpuidle/: +total 0 +drwxr-xr-x 2 root root 0 Feb 8 10:42 state0 +drwxr-xr-x 2 root root 0 Feb 8 10:42 state1 +drwxr-xr-x 2 root root 0 Feb 8 10:42 state2 +drwxr-xr-x 2 root root 0 Feb 8 10:42 state3 + +/sys/devices/system/cpu/cpu0/cpuidle/state0: +total 0 +-r--r--r-- 1 root root 4096 Feb 8 10:42 desc +-r--r--r-- 1 root root 4096 Feb 8 10:42 latency +-r--r--r-- 1 root root 4096 Feb 8 10:42 name +-r--r--r-- 1 root root 4096 Feb 8 10:42 power +-r--r--r-- 1 root root 4096 Feb 8 10:42 time +-r--r--r-- 1 root root 4096 Feb 8 10:42 usage + +/sys/devices/system/cpu/cpu0/cpuidle/state1: +total 0 +-r--r--r-- 1 root root 4096 Feb 8 10:42 desc +-r--r--r-- 1 root root 4096 Feb 8 10:42 latency +-r--r--r-- 1 root root 4096 Feb 8 10:42 name +-r--r--r-- 1 root root 4096 Feb 8 10:42 power +-r--r--r-- 1 root root 4096 Feb 8 10:42 time +-r--r--r-- 1 root root 4096 Feb 8 10:42 usage + +/sys/devices/system/cpu/cpu0/cpuidle/state2: +total 0 +-r--r--r-- 1 root root 4096 Feb 8 10:42 desc +-r--r--r-- 1 root root 4096 Feb 8 10:42 latency +-r--r--r-- 1 root root 4096 Feb 8 10:42 name +-r--r--r-- 1 root root 4096 Feb 8 10:42 power +-r--r--r-- 1 root root 4096 Feb 8 10:42 time +-r--r--r-- 1 root root 4096 Feb 8 10:42 usage + +/sys/devices/system/cpu/cpu0/cpuidle/state3: +total 0 +-r--r--r-- 1 root root 4096 Feb 8 10:42 desc +-r--r--r-- 1 root root 4096 Feb 8 10:42 latency +-r--r--r-- 1 root root 4096 Feb 8 10:42 name +-r--r--r-- 1 root root 4096 Feb 8 10:42 power +-r--r--r-- 1 root root 4096 Feb 8 10:42 time +-r--r--r-- 1 root root 4096 Feb 8 10:42 usage +-------------------------------------------------------------------------------- + + +* desc : Small description about the idle state (string) +* latency : Latency to exit out of this idle state (in microseconds) +* name : Name of the idle state (string) +* power : Power consumed while in this idle state (in milliwatts) +* time : Total time spent in this idle state (in microseconds) +* usage : Number of times this state was entered (count) diff --git a/Documentation/kprobes.txt b/Documentation/kprobes.txt index 30c101761d0..83f515c2905 100644 --- a/Documentation/kprobes.txt +++ b/Documentation/kprobes.txt @@ -92,9 +92,8 @@ handler has run. Up to MAX_STACK_SIZE bytes are copied -- e.g., 64 bytes on i386. Note that the probed function's args may be passed on the stack -or in registers (e.g., for x86_64 or for an i386 fastcall function). -The jprobe will work in either case, so long as the handler's -prototype matches that of the probed function. +or in registers. The jprobe will work in either case, so long as the +handler's prototype matches that of the probed function. 1.3 Return Probes @@ -270,9 +269,9 @@ Kprobes runs the handler whose address is jp->entry. The handler should have the same arg list and return type as the probed function; and just before it returns, it must call jprobe_return(). (The handler never actually returns, since jprobe_return() returns -control to Kprobes.) If the probed function is declared asmlinkage, -fastcall, or anything else that affects how args are passed, the -handler's declaration must match. +control to Kprobes.) If the probed function is declared asmlinkage +or anything else that affects how args are passed, the handler's +declaration must match. register_jprobe() returns 0 on success, or a negative errno otherwise. diff --git a/Documentation/networking/tcp.txt b/Documentation/networking/tcp.txt index 0121edc3ba0..7d11bb5dc30 100644 --- a/Documentation/networking/tcp.txt +++ b/Documentation/networking/tcp.txt @@ -1,7 +1,7 @@ TCP protocol ============ -Last updated: 21 June 2005 +Last updated: 9 February 2008 Contents ======== @@ -52,9 +52,9 @@ research and RFC's before developing new modules. The method that is used to determine which congestion control mechanism is determined by the setting of the sysctl net.ipv4.tcp_congestion_control. The default congestion control will be the last one registered (LIFO); -so if you built everything as modules. the default will be reno. If you -build with the default's from Kconfig, then BIC will be builtin (not a module) -and it will end up the default. +so if you built everything as modules, the default will be reno. If you +build with the defaults from Kconfig, then CUBIC will be builtin (not a +module) and it will end up the default. If you really want a particular default value then you will need to set it with the sysctl. If you use a sysctl, the module will be autoloaded diff --git a/Documentation/sched-rt-group.txt b/Documentation/sched-rt-group.txt new file mode 100644 index 00000000000..1c6332f4543 --- /dev/null +++ b/Documentation/sched-rt-group.txt @@ -0,0 +1,59 @@ + + +Real-Time group scheduling. + +The problem space: + +In order to schedule multiple groups of realtime tasks each group must +be assigned a fixed portion of the CPU time available. Without a minimum +guarantee a realtime group can obviously fall short. A fuzzy upper limit +is of no use since it cannot be relied upon. Which leaves us with just +the single fixed portion. + +CPU time is divided by means of specifying how much time can be spent +running in a given period. Say a frame fixed realtime renderer must +deliver 25 frames a second, which yields a period of 0.04s. Now say +it will also have to play some music and respond to input, leaving it +with around 80% for the graphics. We can then give this group a runtime +of 0.8 * 0.04s = 0.032s. + +This way the graphics group will have a 0.04s period with a 0.032s runtime +limit. + +Now if the audio thread needs to refill the DMA buffer every 0.005s, but +needs only about 3% CPU time to do so, it can do with a 0.03 * 0.005s += 0.00015s. + + +The Interface: + +system wide: + +/proc/sys/kernel/sched_rt_period_ms +/proc/sys/kernel/sched_rt_runtime_us + +CONFIG_FAIR_USER_SCHED + +/sys/kernel/uids/<uid>/cpu_rt_runtime_us + +or + +CONFIG_FAIR_CGROUP_SCHED + +/cgroup/<cgroup>/cpu.rt_runtime_us + +[ time is specified in us because the interface is s32; this gives an + operating range of ~35m to 1us ] + +The period takes values in [ 1, INT_MAX ], runtime in [ -1, INT_MAX - 1 ]. + +A runtime of -1 specifies runtime == period, ie. no limit. + +New groups get the period from /proc/sys/kernel/sched_rt_period_us and +a runtime of 0. + +Settings are constrained to: + + \Sum_{i} runtime_{i} / global_period <= global_runtime / global_period + +in order to keep the configuration schedulable. diff --git a/Documentation/sysctl/kernel.txt b/Documentation/sysctl/kernel.txt index dc8801d4e94..276a7e63782 100644 --- a/Documentation/sysctl/kernel.txt +++ b/Documentation/sysctl/kernel.txt @@ -29,7 +29,7 @@ show up in /proc/sys/kernel: - java-interpreter [ binfmt_java, obsolete ] - kstack_depth_to_print [ X86 only ] - l2cr [ PPC only ] -- modprobe ==> Documentation/kmod.txt +- modprobe ==> Documentation/debugging-modules.txt - msgmax - msgmnb - msgmni diff --git a/Documentation/video4linux/CARDLIST.em28xx b/Documentation/video4linux/CARDLIST.em28xx index 6a8469f2bca..f40e09296f3 100644 --- a/Documentation/video4linux/CARDLIST.em28xx +++ b/Documentation/video4linux/CARDLIST.em28xx @@ -8,7 +8,7 @@ 7 -> Leadtek Winfast USB II (em2800) 8 -> Kworld USB2800 (em2800) 9 -> Pinnacle Dazzle DVC 90/DVC 100 (em2820/em2840) [2304:0207,2304:021a] - 10 -> Hauppauge WinTV HVR 900 (em2880) [2040:6500] + 10 -> Hauppauge WinTV HVR 900 (em2880) [2040:6500,2040:6502] 11 -> Terratec Hybrid XS (em2880) [0ccd:0042] 12 -> Kworld PVR TV 2800 RF (em2820/em2840) 13 -> Terratec Prodigy XS (em2880) [0ccd:0047] diff --git a/Documentation/video4linux/CARDLIST.saa7134 b/Documentation/video4linux/CARDLIST.saa7134 index 5d3b6b4d251..0424901ebc7 100644 --- a/Documentation/video4linux/CARDLIST.saa7134 +++ b/Documentation/video4linux/CARDLIST.saa7134 @@ -92,9 +92,9 @@ 91 -> AVerMedia A169 B [1461:7360] 92 -> AVerMedia A169 B1 [1461:6360] 93 -> Medion 7134 Bridge #2 [16be:0005] - 94 -> LifeView FlyDVB-T Hybrid Cardbus/MSI TV @nywhere A/D NB [5168:3306,5168:3502,4e42:3502] + 94 -> LifeView FlyDVB-T Hybrid Cardbus/MSI TV @nywhere A/D NB [5168:3306,5168:3502,5168:3307,4e42:3502] 95 -> LifeView FlyVIDEO3000 (NTSC) [5169:0138] - 96 -> Medion Md8800 Quadro [16be:0007,16be:0008] + 96 -> Medion Md8800 Quadro [16be:0007,16be:0008,16be:000d] 97 -> LifeView FlyDVB-S /Acorp TV134DS [5168:0300,4e42:0300] 98 -> Proteus Pro 2309 [0919:2003] 99 -> AVerMedia TV Hybrid A16AR [1461:2c00] @@ -129,3 +129,5 @@ 128 -> Beholder BeholdTV Columbus TVFM [0000:5201] 129 -> Beholder BeholdTV 607 / BeholdTV 609 [5ace:6070,5ace:6071,5ace:6072,5ace:6073,5ace:6090,5ace:6091,5ace:6092,5ace:6093] 130 -> Beholder BeholdTV M6 / BeholdTV M6 Extra [5ace:6190,5ace:6193] +131 -> Twinhan Hybrid DTV-DVB 3056 PCI [1822:0022] +132 -> Genius TVGO AM11MCE diff --git a/Documentation/video4linux/zr364xx.txt b/Documentation/video4linux/zr364xx.txt index 4d9a0c33f2f..5c81e3ae645 100644 --- a/Documentation/video4linux/zr364xx.txt +++ b/Documentation/video4linux/zr364xx.txt @@ -25,7 +25,7 @@ modprobe zr364xx debug=X mode=Y - debug : set to 1 to enable verbose debug messages - mode : 0 = 320x240, 1 = 160x120, 2 = 640x480 You can then use the camera with V4L2 compatible applications, for example Ekiga. -To capture a single image, try this: dd if=/dev/video0 of=test.jpg bs=1 count=1 +To capture a single image, try this: dd if=/dev/video0 of=test.jpg bs=1M count=1 links : http://mxhaard.free.fr/ (support for many others cams including some Aiptek PocketDV) @@ -63,3 +63,5 @@ Vendor Product Distributor Model 0x06d6 0x0034 Trust Powerc@m 750 0x0a17 0x0062 Pentax Optio 50L 0x06d6 0x003b Trust Powerc@m 970Z +0x0a17 0x004e Pentax Optio 50 +0x041e 0x405d Creative DiVi CAM 516 diff --git a/MAINTAINERS b/MAINTAINERS index 6680ec44779..082d1ee154a 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1255,8 +1255,8 @@ W: http://linux-net.osdl.org/index.php/DCCP S: Maintained DECnet NETWORK LAYER -P: Patrick Caulfield -M: patrick@tykepenguin.com +P: Christine Caulfield +M: christine.caulfield@googlemail.com W: http://linux-decnet.sourceforge.net L: linux-decnet-user@lists.sourceforge.net S: Maintained @@ -1318,8 +1318,8 @@ L: linux-kernel@vger.kernel.org S: Maintained DISTRIBUTED LOCK MANAGER -P: Patrick Caulfield -M: pcaulfie@redhat.com +P: Christine Caulfield +M: ccaulfie@redhat.com P: David Teigland M: teigland@redhat.com L: cluster-devel@redhat.com @@ -1616,6 +1616,7 @@ S: Maintained FILESYSTEMS (VFS and infrastructure) P: Alexander Viro M: viro@zeniv.linux.org.uk +L: linux-fsdevel@vger.kernel.org S: Maintained FIREWIRE SUBSYSTEM (drivers/firewire, <linux/firewire*.h>) @@ -1923,7 +1924,7 @@ S: Maintained IDE/ATAPI CDROM DRIVER P: Borislav Petkov -M: bbpetkov@yahoo.de +M: petkovbb@gmail.com L: linux-ide@vger.kernel.org S: Maintained @@ -1,8 +1,8 @@ VERSION = 2 PATCHLEVEL = 6 SUBLEVEL = 25 -EXTRAVERSION = -rc1 -NAME = Arr Matey! A Hairy Bilge Rat! +EXTRAVERSION = -rc2 +NAME = Funky Weasel is Jiggy wit it # *DOCUMENTATION* # To see a list of typical targets execute "make help" @@ -507,6 +507,10 @@ else KBUILD_CFLAGS += -O2 endif +# Force gcc to behave correct even for buggy distributions +# Arch Makefiles may override this setting +KBUILD_CFLAGS += $(call cc-option, -fno-stack-protector) + include $(srctree)/arch/$(SRCARCH)/Makefile ifdef CONFIG_FRAME_POINTER @@ -525,9 +529,6 @@ ifdef CONFIG_DEBUG_SECTION_MISMATCH KBUILD_CFLAGS += $(call cc-option, -fno-inline-functions-called-once) endif -# Force gcc to behave correct even for buggy distributions -KBUILD_CFLAGS += $(call cc-option, -fno-stack-protector) - # arch Makefile may override CC so keep this after arch Makefile is included NOSTDINC_FLAGS += -nostdinc -isystem $(shell $(CC) -print-file-name=include) CHECKFLAGS += $(NOSTDINC_FLAGS) @@ -810,7 +811,9 @@ endif $(Q)rm -f .old_version # build vmlinux.o first to catch section mismatch errors early -$(kallsyms.o): vmlinux.o +ifdef CONFIG_KALLSYMS +.tmp_vmlinux1: vmlinux.o +endif vmlinux.o: $(vmlinux-lds) $(vmlinux-init) $(vmlinux-main) FORCE $(call if_changed_rule,vmlinux-modpost) diff --git a/arch/alpha/kernel/osf_sys.c b/arch/alpha/kernel/osf_sys.c index 973c5c3705e..8c71daf94a5 100644 --- a/arch/alpha/kernel/osf_sys.c +++ b/arch/alpha/kernel/osf_sys.c @@ -259,8 +259,8 @@ osf_statfs(char __user *path, struct osf_statfs __user *buffer, unsigned long bu retval = user_path_walk(path, &nd); if (!retval) { - retval = do_osf_statfs(nd.dentry, buffer, bufsiz); - path_release(&nd); + retval = do_osf_statfs(nd.path.dentry, buffer, bufsiz); + path_put(&nd.path); } return retval; } diff --git a/arch/alpha/kernel/time.c b/arch/alpha/kernel/time.c index 1dd50d07693..75480cab089 100644 --- a/arch/alpha/kernel/time.c +++ b/arch/alpha/kernel/time.c @@ -119,13 +119,8 @@ irqreturn_t timer_interrupt(int irq, void *dev) state.partial_tick = delta & ((1UL << FIX_SHIFT) - 1); nticks = delta >> FIX_SHIFT; - while (nticks > 0) { - do_timer(1); -#ifndef CONFIG_SMP - update_process_times(user_mode(get_irq_regs())); -#endif - nticks--; - } + if (nticks) + do_timer(nticks); /* * If we have an externally synchronized Linux clock, then update @@ -141,6 +136,12 @@ irqreturn_t timer_interrupt(int irq, void *dev) } write_sequnlock(&xtime_lock); + +#ifndef CONFIG_SMP + while (nticks--) + update_process_times(user_mode(get_irq_regs())); +#endif + return IRQ_HANDLED; } diff --git a/arch/blackfin/kernel/time.c b/arch/blackfin/kernel/time.c index 5bd64e341df..9bdc8f99183 100644 --- a/arch/blackfin/kernel/time.c +++ b/arch/blackfin/kernel/time.c @@ -137,9 +137,6 @@ irqreturn_t timer_interrupt(int irq, void *dummy) do_timer(1); -#ifndef CONFIG_SMP - update_process_times(user_mode(get_irq_regs())); -#endif profile_tick(CPU_PROFILING); /* @@ -161,6 +158,11 @@ irqreturn_t timer_interrupt(int irq, void *dummy) last_rtc_update = xtime.tv_sec - 600; } write_sequnlock(&xtime_lock); + +#ifndef CONFIG_SMP + update_process_times(user_mode(get_irq_regs())); +#endif + return IRQ_HANDLED; } diff --git a/arch/blackfin/kernel/traps.c b/arch/blackfin/kernel/traps.c index 58717cb1970..56a67ab698c 100644 --- a/arch/blackfin/kernel/traps.c +++ b/arch/blackfin/kernel/traps.c @@ -126,15 +126,13 @@ static void decode_address(char *buf, unsigned long address) struct vm_area_struct *vma = vml->vma; if (address >= vma->vm_start && address < vma->vm_end) { + char _tmpbuf[256]; char *name = p->comm; struct file *file = vma->vm_file; - if (file) { - char _tmpbuf[256]; - name = d_path(file->f_dentry, - file->f_vfsmnt, - _tmpbuf, - sizeof(_tmpbuf)); - } + + if (file) + name = d_path(&file->f_path, _tmpbuf, + sizeof(_tmpbuf)); /* FLAT does not have its text aligned to the start of * the map while FDPIC ELF does ... diff --git a/arch/cris/arch-v10/lib/memset.c b/arch/cris/arch-v10/lib/memset.c index 42c1101043a..c94ea9b3ec2 100644 --- a/arch/cris/arch-v10/lib/memset.c +++ b/arch/cris/arch-v10/lib/memset.c @@ -1,252 +1,259 @@ -/*#************************************************************************#*/ -/*#-------------------------------------------------------------------------*/ -/*# */ -/*# FUNCTION NAME: memset() */ -/*# */ -/*# PARAMETERS: void* dst; Destination address. */ -/*# int c; Value of byte to write. */ -/*# int len; Number of bytes to write. */ -/*# */ -/*# RETURNS: dst. */ -/*# */ -/*# DESCRIPTION: Sets the memory dst of length len bytes to c, as standard. */ -/*# Framework taken from memcpy. This routine is */ -/*# very sensitive to compiler changes in register allocation. */ -/*# Should really be rewritten to avoid this problem. */ -/*# */ -/*#-------------------------------------------------------------------------*/ -/*# */ -/*# HISTORY */ -/*# */ -/*# DATE NAME CHANGES */ -/*# ---- ---- ------- */ -/*# 990713 HP Tired of watching this function (or */ -/*# really, the nonoptimized generic */ -/*# implementation) take up 90% of simulator */ -/*# output. Measurements needed. */ -/*# */ -/*#-------------------------------------------------------------------------*/ - -#include <linux/types.h> - -/* No, there's no macro saying 12*4, since it is "hard" to get it into - the asm in a good way. Thus better to expose the problem everywhere. - */ - -/* Assuming 1 cycle per dword written or read (ok, not really true), and - one per instruction, then 43+3*(n/48-1) <= 24+24*(n/48-1) - so n >= 45.7; n >= 0.9; we win on the first full 48-byte block to set. */ - -#define ZERO_BLOCK_SIZE (1*12*4) - -void *memset(void *pdst, - int c, - size_t plen) +/* A memset for CRIS. + Copyright (C) 1999-2005 Axis Communications. + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + 2. Neither the name of Axis Communications nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY AXIS COMMUNICATIONS AND ITS CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL AXIS + COMMUNICATIONS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. */ + +/* FIXME: This file should really only be used for reference, as the + result is somewhat depending on gcc generating what we expect rather + than what we describe. An assembly file should be used instead. */ + +/* Note the multiple occurrence of the expression "12*4", including the + asm. It is hard to get it into the asm in a good way. Thus better to + expose the problem everywhere: no macro. */ + +/* Assuming one cycle per dword written or read (ok, not really true; the + world is not ideal), and one cycle per instruction, then 43+3*(n/48-1) + <= 24+24*(n/48-1) so n >= 45.7; n >= 0.9; we win on the first full + 48-byte block to set. */ + +#define MEMSET_BY_BLOCK_THRESHOLD (1 * 48) + +/* No name ambiguities in this file. */ +__asm__ (".syntax no_register_prefix"); + +void *memset(void *pdst, int c, unsigned int plen) { - /* Ok. Now we want the parameters put in special registers. - Make sure the compiler is able to make something useful of this. */ + /* Now we want the parameters in special registers. Make sure the + compiler does something usable with this. */ register char *return_dst __asm__ ("r10") = pdst; register int n __asm__ ("r12") = plen; register int lc __asm__ ("r11") = c; - /* Most apps use memset sanely. Only those memsetting about 3..4 - bytes or less get penalized compared to the generic implementation - - and that's not really sane use. */ + /* Most apps use memset sanely. Memsetting about 3..4 bytes or less get + penalized here compared to the generic implementation. */ - /* Ugh. This is fragile at best. Check with newer GCC releases, if - they compile cascaded "x |= x << 8" sanely! */ - __asm__("movu.b %0,$r13\n\t" - "lslq 8,$r13\n\t" - "move.b %0,$r13\n\t" - "move.d $r13,%0\n\t" - "lslq 16,$r13\n\t" - "or.d $r13,%0" - : "=r" (lc) : "0" (lc) : "r13"); + /* This is fragile performancewise at best. Check with newer GCC + releases, if they compile cascaded "x |= x << 8" to sane code. */ + __asm__("movu.b %0,r13 \n\ + lslq 8,r13 \n\ + move.b %0,r13 \n\ + move.d r13,%0 \n\ + lslq 16,r13 \n\ + or.d r13,%0" + : "=r" (lc) /* Inputs. */ + : "0" (lc) /* Outputs. */ + : "r13"); /* Trash. */ { register char *dst __asm__ ("r13") = pdst; - /* This is NONPORTABLE, but since this whole routine is */ - /* grossly nonportable that doesn't matter. */ + if (((unsigned long) pdst & 3) != 0 + /* Oops! n = 0 must be a valid call, regardless of alignment. */ + && n >= 3) + { + if ((unsigned long) dst & 1) + { + *dst = (char) lc; + n--; + dst++; + } - if (((unsigned long) pdst & 3) != 0 - /* Oops! n=0 must be a legal call, regardless of alignment. */ - && n >= 3) - { - if ((unsigned long)dst & 1) - { - *dst = (char) lc; - n--; - dst++; - } - - if ((unsigned long)dst & 2) - { - *(short *)dst = lc; - n -= 2; - dst += 2; - } - } + if ((unsigned long) dst & 2) + { + *(short *) dst = lc; + n -= 2; + dst += 2; + } + } - /* Now the fun part. For the threshold value of this, check the equation - above. */ - /* Decide which copying method to use. */ - if (n >= ZERO_BLOCK_SIZE) - { - /* For large copies we use 'movem' */ - - /* It is not optimal to tell the compiler about clobbering any - registers; that will move the saving/restoring of those registers - to the function prologue/epilogue, and make non-movem sizes - suboptimal. - - This method is not foolproof; it assumes that the "asm reg" - declarations at the beginning of the function really are used - here (beware: they may be moved to temporary registers). - This way, we do not have to save/move the registers around into - temporaries; we can safely use them straight away. - - If you want to check that the allocation was right; then - check the equalities in the first comment. It should say - "r13=r13, r12=r12, r11=r11" */ - __asm__ volatile ("\n\ - ;; Check that the following is true (same register names on \n\ - ;; both sides of equal sign, as in r8=r8): \n\ - ;; %0=r13, %1=r12, %4=r11 \n\ - ;; \n\ - ;; Save the registers we'll clobber in the movem process \n\ - ;; on the stack. Don't mention them to gcc, it will only be \n\ - ;; upset. \n\ - subq 11*4,$sp \n\ - movem $r10,[$sp] \n\ + /* Decide which setting method to use. */ + if (n >= MEMSET_BY_BLOCK_THRESHOLD) + { + /* It is not optimal to tell the compiler about clobbering any + registers; that will move the saving/restoring of those registers + to the function prologue/epilogue, and make non-block sizes + suboptimal. */ + __asm__ volatile + ("\ + ;; GCC does promise correct register allocations, but let's \n\ + ;; make sure it keeps its promises. \n\ + .ifnc %0-%1-%4,$r13-$r12-$r11 \n\ + .error \"GCC reg alloc bug: %0-%1-%4 != $r13-$r12-$r11\" \n\ + .endif \n\ + \n\ + ;; Save the registers we'll clobber in the movem process \n\ + ;; on the stack. Don't mention them to gcc, it will only be \n\ + ;; upset. \n\ + subq 11*4,sp \n\ + movem r10,[sp] \n\ \n\ - move.d $r11,$r0 \n\ - move.d $r11,$r1 \n\ - move.d $r11,$r2 \n\ - move.d $r11,$r3 \n\ - move.d $r11,$r4 \n\ - move.d $r11,$r5 \n\ - move.d $r11,$r6 \n\ - move.d $r11,$r7 \n\ - move.d $r11,$r8 \n\ - move.d $r11,$r9 \n\ - move.d $r11,$r10 \n\ + move.d r11,r0 \n\ + move.d r11,r1 \n\ + move.d r11,r2 \n\ + move.d r11,r3 \n\ + move.d r11,r4 \n\ + move.d r11,r5 \n\ + move.d r11,r6 \n\ + move.d r11,r7 \n\ + move.d r11,r8 \n\ + move.d r11,r9 \n\ + move.d r11,r10 \n\ \n\ - ;; Now we've got this: \n\ - ;; r13 - dst \n\ - ;; r12 - n \n\ + ;; Now we've got this: \n\ + ;; r13 - dst \n\ + ;; r12 - n \n\ \n\ - ;; Update n for the first loop \n\ - subq 12*4,$r12 \n\ + ;; Update n for the first loop \n\ + subq 12*4,r12 \n\ 0: \n\ - subq 12*4,$r12 \n\ - bge 0b \n\ - movem $r11,[$r13+] \n\ +" +#ifdef __arch_common_v10_v32 + /* Cater to branch offset difference between v32 and v10. We + assume the branch below has an 8-bit offset. */ +" setf\n" +#endif +" subq 12*4,r12 \n\ + bge 0b \n\ + movem r11,[r13+] \n\ \n\ - addq 12*4,$r12 ;; compensate for last loop underflowing n \n\ + ;; Compensate for last loop underflowing n. \n\ + addq 12*4,r12 \n\ \n\ - ;; Restore registers from stack \n\ - movem [$sp+],$r10" + ;; Restore registers from stack. \n\ + movem [sp+],r10" - /* Outputs */ : "=r" (dst), "=r" (n) - /* Inputs */ : "0" (dst), "1" (n), "r" (lc)); + /* Outputs. */ + : "=r" (dst), "=r" (n) - } + /* Inputs. */ + : "0" (dst), "1" (n), "r" (lc)); + } + + /* An ad-hoc unroll, used for 4*12-1..16 bytes. */ + while (n >= 16) + { + *(long *) dst = lc; dst += 4; + *(long *) dst = lc; dst += 4; + *(long *) dst = lc; dst += 4; + *(long *) dst = lc; dst += 4; + n -= 16; + } - /* Either we directly starts copying, using dword copying - in a loop, or we copy as much as possible with 'movem' - and then the last block (<44 bytes) is copied here. - This will work since 'movem' will have updated src,dst,n. */ - - while ( n >= 16 ) - { - *((long*)dst)++ = lc; - *((long*)dst)++ = lc; - *((long*)dst)++ = lc; - *((long*)dst)++ = lc; - n -= 16; - } - - /* A switch() is definitely the fastest although it takes a LOT of code. - * Particularly if you inline code this. - */ switch (n) - { + { case 0: break; + case 1: - *(char*)dst = (char) lc; + *dst = (char) lc; break; + case 2: - *(short*)dst = (short) lc; + *(short *) dst = (short) lc; break; + case 3: - *((short*)dst)++ = (short) lc; - *(char*)dst = (char) lc; + *(short *) dst = (short) lc; dst += 2; + *dst = (char) lc; break; + case 4: - *((long*)dst)++ = lc; + *(long *) dst = lc; break; + case 5: - *((long*)dst)++ = lc; - *(char*)dst = (char) lc; + *(long *) dst = lc; dst += 4; + *dst = (char) lc; break; + case 6: - *((long*)dst)++ = lc; - *(short*)dst = (short) lc; + *(long *) dst = lc; dst += 4; + *(short *) dst = (short) lc; break; + case 7: - *((long*)dst)++ = lc; - *((short*)dst)++ = (short) lc; - *(char*)dst = (char) lc; + *(long *) dst = lc; dst += 4; + *(short *) dst = (short) lc; dst += 2; + *dst = (char) lc; break; + case 8: - *((long*)dst)++ = lc; - *((long*)dst)++ = lc; + *(long *) dst = lc; dst += 4; + *(long *) dst = lc; break; + case 9: - *((long*)dst)++ = lc; - *((long*)dst)++ = lc; - *(char*)dst = (char) lc; + *(long *) dst = lc; dst += 4; + *(long *) dst = lc; dst += 4; + *dst = (char) lc; break; + case 10: - *((long*)dst)++ = lc; - *((long*)dst)++ = lc; - *(short*)dst = (short) lc; + *(long *) dst = lc; dst += 4; + *(long *) dst = lc; dst += 4; + *(short *) dst = (short) lc; break; + case 11: - *((long*)dst)++ = lc; - *((long*)dst)++ = lc; - *((short*)dst)++ = (short) lc; - *(char*)dst = (char) lc; + *(long *) dst = lc; dst += 4; + *(long *) dst = lc; dst += 4; + *(short *) dst = (short) lc; dst += 2; + *dst = (char) lc; break; + case 12: - *((long*)dst)++ = lc; - *((long*)dst)++ = lc; - *((long*)dst)++ = lc; + *(long *) dst = lc; dst += 4; + *(long *) dst = lc; dst += 4; + *(long *) dst = lc; break; + case 13: - *((long*)dst)++ = lc; - *((long*)dst)++ = lc; - *((long*)dst)++ = lc; - *(char*)dst = (char) lc; + *(long *) dst = lc; dst += 4; + *(long *) dst = lc; dst += 4; + *(long *) dst = lc; dst += 4; + *dst = (char) lc; break; + case 14: - *((long*)dst)++ = lc; - *((long*)dst)++ = lc; - *((long*)dst)++ = lc; - *(short*)dst = (short) lc; + *(long *) dst = lc; dst += 4; + *(long *) dst = lc; dst += 4; + *(long *) dst = lc; dst += 4; + *(short *) dst = (short) lc; break; + case 15: - *((long*)dst)++ = lc; - *((long*)dst)++ = lc; - *((long*)dst)++ = lc; - *((short*)dst)++ = (short) lc; - *(char*)dst = (char) lc; + *(long *) dst = lc; dst += 4; + *(long *) dst = lc; dst += 4; + *(long *) dst = lc; dst += 4; + *(short *) dst = (short) lc; dst += 2; + *dst = (char) lc; break; - } + } } - return return_dst; /* destination pointer. */ -} /* memset() */ + return return_dst; +} diff --git a/arch/cris/arch-v32/lib/memset.c b/arch/cris/arch-v32/lib/memset.c index ffca1214674..c94ea9b3ec2 100644 --- a/arch/cris/arch-v32/lib/memset.c +++ b/arch/cris/arch-v32/lib/memset.c @@ -1,253 +1,259 @@ -/*#************************************************************************#*/ -/*#-------------------------------------------------------------------------*/ -/*# */ -/*# FUNCTION NAME: memset() */ -/*# */ -/*# PARAMETERS: void* dst; Destination address. */ -/*# int c; Value of byte to write. */ -/*# int len; Number of bytes to write. */ -/*# */ -/*# RETURNS: dst. */ -/*# */ -/*# DESCRIPTION: Sets the memory dst of length len bytes to c, as standard. */ -/*# Framework taken from memcpy. This routine is */ -/*# very sensitive to compiler changes in register allocation. */ -/*# Should really be rewritten to avoid this problem. */ -/*# */ -/*#-------------------------------------------------------------------------*/ -/*# */ -/*# HISTORY */ -/*# */ -/*# DATE NAME CHANGES */ -/*# ---- ---- ------- */ -/*# 990713 HP Tired of watching this function (or */ -/*# really, the nonoptimized generic */ -/*# implementation) take up 90% of simulator */ -/*# output. Measurements needed. */ -/*# */ -/*#-------------------------------------------------------------------------*/ - -#include <linux/types.h> - -/* No, there's no macro saying 12*4, since it is "hard" to get it into - the asm in a good way. Thus better to expose the problem everywhere. - */ - -/* Assuming 1 cycle per dword written or read (ok, not really true), and - one per instruction, then 43+3*(n/48-1) <= 24+24*(n/48-1) - so n >= 45.7; n >= 0.9; we win on the first full 48-byte block to set. */ - -#define ZERO_BLOCK_SIZE (1*12*4) - -void *memset(void *pdst, - int c, - size_t plen) +/* A memset for CRIS. + Copyright (C) 1999-2005 Axis Communications. + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + 2. Neither the name of Axis Communications nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY AXIS COMMUNICATIONS AND ITS CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL AXIS + COMMUNICATIONS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. */ + +/* FIXME: This file should really only be used for reference, as the + result is somewhat depending on gcc generating what we expect rather + than what we describe. An assembly file should be used instead. */ + +/* Note the multiple occurrence of the expression "12*4", including the + asm. It is hard to get it into the asm in a good way. Thus better to + expose the problem everywhere: no macro. */ + +/* Assuming one cycle per dword written or read (ok, not really true; the + world is not ideal), and one cycle per instruction, then 43+3*(n/48-1) + <= 24+24*(n/48-1) so n >= 45.7; n >= 0.9; we win on the first full + 48-byte block to set. */ + +#define MEMSET_BY_BLOCK_THRESHOLD (1 * 48) + +/* No name ambiguities in this file. */ +__asm__ (".syntax no_register_prefix"); + +void *memset(void *pdst, int c, unsigned int plen) { - /* Ok. Now we want the parameters put in special registers. - Make sure the compiler is able to make something useful of this. */ + /* Now we want the parameters in special registers. Make sure the + compiler does something usable with this. */ register char *return_dst __asm__ ("r10") = pdst; register int n __asm__ ("r12") = plen; register int lc __asm__ ("r11") = c; - /* Most apps use memset sanely. Only those memsetting about 3..4 - bytes or less get penalized compared to the generic implementation - - and that's not really sane use. */ + /* Most apps use memset sanely. Memsetting about 3..4 bytes or less get + penalized here compared to the generic implementation. */ - /* Ugh. This is fragile at best. Check with newer GCC releases, if - they compile cascaded "x |= x << 8" sanely! */ - __asm__("movu.b %0,$r13 \n\ - lslq 8,$r13 \n\ - move.b %0,$r13 \n\ - move.d $r13,%0 \n\ - lslq 16,$r13 \n\ - or.d $r13,%0" - : "=r" (lc) : "0" (lc) : "r13"); + /* This is fragile performancewise at best. Check with newer GCC + releases, if they compile cascaded "x |= x << 8" to sane code. */ + __asm__("movu.b %0,r13 \n\ + lslq 8,r13 \n\ + move.b %0,r13 \n\ + move.d r13,%0 \n\ + lslq 16,r13 \n\ + or.d r13,%0" + : "=r" (lc) /* Inputs. */ + : "0" (lc) /* Outputs. */ + : "r13"); /* Trash. */ { register char *dst __asm__ ("r13") = pdst; - /* This is NONPORTABLE, but since this whole routine is */ - /* grossly nonportable that doesn't matter. */ + if (((unsigned long) pdst & 3) != 0 + /* Oops! n = 0 must be a valid call, regardless of alignment. */ + && n >= 3) + { + if ((unsigned long) dst & 1) + { + *dst = (char) lc; + n--; + dst++; + } - if (((unsigned long) pdst & 3) != 0 - /* Oops! n=0 must be a legal call, regardless of alignment. */ - && n >= 3) - { - if ((unsigned long)dst & 1) - { - *dst = (char) lc; - n--; - dst++; - } - - if ((unsigned long)dst & 2) - { - *(short *)dst = lc; - n -= 2; - dst += 2; - } - } + if ((unsigned long) dst & 2) + { + *(short *) dst = lc; + n -= 2; + dst += 2; + } + } - /* Now the fun part. For the threshold value of this, check the equation - above. */ - /* Decide which copying method to use. */ - if (n >= ZERO_BLOCK_SIZE) - { - /* For large copies we use 'movem' */ - - /* It is not optimal to tell the compiler about clobbering any - registers; that will move the saving/restoring of those registers - to the function prologue/epilogue, and make non-movem sizes - suboptimal. - - This method is not foolproof; it assumes that the "asm reg" - declarations at the beginning of the function really are used - here (beware: they may be moved to temporary registers). - This way, we do not have to save/move the registers around into - temporaries; we can safely use them straight away. - - If you want to check that the allocation was right; then - check the equalities in the first comment. It should say - "r13=r13, r12=r12, r11=r11" */ - __asm__ volatile (" \n\ - ;; Check that the register asm declaration got right. \n\ - ;; The GCC manual says it will work, but there *has* been bugs. \n\ - .ifnc %0-%1-%4,$r13-$r12-$r11 \n\ - .err \n\ - .endif \n\ + /* Decide which setting method to use. */ + if (n >= MEMSET_BY_BLOCK_THRESHOLD) + { + /* It is not optimal to tell the compiler about clobbering any + registers; that will move the saving/restoring of those registers + to the function prologue/epilogue, and make non-block sizes + suboptimal. */ + __asm__ volatile + ("\ + ;; GCC does promise correct register allocations, but let's \n\ + ;; make sure it keeps its promises. \n\ + .ifnc %0-%1-%4,$r13-$r12-$r11 \n\ + .error \"GCC reg alloc bug: %0-%1-%4 != $r13-$r12-$r11\" \n\ + .endif \n\ \n\ - ;; Save the registers we'll clobber in the movem process \n\ - ;; on the stack. Don't mention them to gcc, it will only be \n\ - ;; upset. \n\ - subq 11*4,$sp \n\ - movem $r10,[$sp] \n\ + ;; Save the registers we'll clobber in the movem process \n\ + ;; on the stack. Don't mention them to gcc, it will only be \n\ + ;; upset. \n\ + subq 11*4,sp \n\ + movem r10,[sp] \n\ \n\ - move.d $r11,$r0 \n\ - move.d $r11,$r1 \n\ - move.d $r11,$r2 \n\ - move.d $r11,$r3 \n\ - move.d $r11,$r4 \n\ - move.d $r11,$r5 \n\ - move.d $r11,$r6 \n\ - move.d $r11,$r7 \n\ - move.d $r11,$r8 \n\ - move.d $r11,$r9 \n\ - move.d $r11,$r10 \n\ + move.d r11,r0 \n\ + move.d r11,r1 \n\ + move.d r11,r2 \n\ + move.d r11,r3 \n\ + move.d r11,r4 \n\ + move.d r11,r5 \n\ + move.d r11,r6 \n\ + move.d r11,r7 \n\ + move.d r11,r8 \n\ + move.d r11,r9 \n\ + move.d r11,r10 \n\ \n\ - ;; Now we've got this: \n\ - ;; r13 - dst \n\ - ;; r12 - n \n\ + ;; Now we've got this: \n\ + ;; r13 - dst \n\ + ;; r12 - n \n\ \n\ - ;; Update n for the first loop \n\ - subq 12*4,$r12 \n\ + ;; Update n for the first loop \n\ + subq 12*4,r12 \n\ 0: \n\ - subq 12*4,$r12 \n\ - bge 0b \n\ - movem $r11,[$r13+] \n\ +" +#ifdef __arch_common_v10_v32 + /* Cater to branch offset difference between v32 and v10. We + assume the branch below has an 8-bit offset. */ +" setf\n" +#endif +" subq 12*4,r12 \n\ + bge 0b \n\ + movem r11,[r13+] \n\ \n\ - addq 12*4,$r12 ;; compensate for last loop underflowing n \n\ + ;; Compensate for last loop underflowing n. \n\ + addq 12*4,r12 \n\ \n\ - ;; Restore registers from stack \n\ - movem [$sp+],$r10" + ;; Restore registers from stack. \n\ + movem [sp+],r10" - /* Outputs */ : "=r" (dst), "=r" (n) - /* Inputs */ : "0" (dst), "1" (n), "r" (lc)); - } + /* Outputs. */ + : "=r" (dst), "=r" (n) + + /* Inputs. */ + : "0" (dst), "1" (n), "r" (lc)); + } + + /* An ad-hoc unroll, used for 4*12-1..16 bytes. */ + while (n >= 16) + { + *(long *) dst = lc; dst += 4; + *(long *) dst = lc; dst += 4; + *(long *) dst = lc; dst += 4; + *(long *) dst = lc; dst += 4; + n -= 16; + } - /* Either we directly starts copying, using dword copying - in a loop, or we copy as much as possible with 'movem' - and then the last block (<44 bytes) is copied here. - This will work since 'movem' will have updated src,dst,n. */ - - while ( n >= 16 ) - { - *((long*)dst)++ = lc; - *((long*)dst)++ = lc; - *((long*)dst)++ = lc; - *((long*)dst)++ = lc; - n -= 16; - } - - /* A switch() is definitely the fastest although it takes a LOT of code. - * Particularly if you inline code this. - */ switch (n) - { + { case 0: break; + case 1: - *(char*)dst = (char) lc; + *dst = (char) lc; break; + case 2: - *(short*)dst = (short) lc; + *(short *) dst = (short) lc; break; + case 3: - *((short*)dst)++ = (short) lc; - *(char*)dst = (char) lc; + *(short *) dst = (short) lc; dst += 2; + *dst = (char) lc; break; + case 4: - *((long*)dst)++ = lc; + *(long *) dst = lc; break; + case 5: - *((long*)dst)++ = lc; - *(char*)dst = (char) lc; + *(long *) dst = lc; dst += 4; + *dst = (char) lc; break; + case 6: - *((long*)dst)++ = lc; - *(short*)dst = (short) lc; + *(long *) dst = lc; dst += 4; + *(short *) dst = (short) lc; break; + case 7: - *((long*)dst)++ = lc; - *((short*)dst)++ = (short) lc; - *(char*)dst = (char) lc; + *(long *) dst = lc; dst += 4; + *(short *) dst = (short) lc; dst += 2; + *dst = (char) lc; break; + case 8: - *((long*)dst)++ = lc; - *((long*)dst)++ = lc; + *(long *) dst = lc; dst += 4; + *(long *) dst = lc; break; + case 9: - *((long*)dst)++ = lc; - *((long*)dst)++ = lc; - *(char*)dst = (char) lc; + *(long *) dst = lc; dst += 4; + *(long *) dst = lc; dst += 4; + *dst = (char) lc; break; + case 10: - *((long*)dst)++ = lc; - *((long*)dst)++ = lc; - *(short*)dst = (short) lc; + *(long *) dst = lc; dst += 4; + *(long *) dst = lc; dst += 4; + *(short *) dst = (short) lc; break; + case 11: - *((long*)dst)++ = lc; - *((long*)dst)++ = lc; - *((short*)dst)++ = (short) lc; - *(char*)dst = (char) lc; + *(long *) dst = lc; dst += 4; + *(long *) dst = lc; dst += 4; + *(short *) dst = (short) lc; dst += 2; + *dst = (char) lc; break; + case 12: - *((long*)dst)++ = lc; - *((long*)dst)++ = lc; - *((long*)dst)++ = lc; + *(long *) dst = lc; dst += 4; + *(long *) dst = lc; dst += 4; + *(long *) dst = lc; break; + case 13: - *((long*)dst)++ = lc; - *((long*)dst)++ = lc; - *((long*)dst)++ = lc; - *(char*)dst = (char) lc; + *(long *) dst = lc; dst += 4; + *(long *) dst = lc; dst += 4; + *(long *) dst = lc; dst += 4; + *dst = (char) lc; break; + case 14: - *((long*)dst)++ = lc; - *((long*)dst)++ = lc; - *((long*)dst)++ = lc; - *(short*)dst = (short) lc; + *(long *) dst = lc; dst += 4; + *(long *) dst = lc; dst += 4; + *(long *) dst = lc; dst += 4; + *(short *) dst = (short) lc; break; + case 15: - *((long*)dst)++ = lc; - *((long*)dst)++ = lc; - *((long*)dst)++ = lc; - *((short*)dst)++ = (short) lc; - *(char*)dst = (char) lc; + *(long *) dst = lc; dst += 4; + *(long *) dst = lc; dst += 4; + *(long *) dst = lc; dst += 4; + *(short *) dst = (short) lc; dst += 2; + *dst = (char) lc; break; - } + } } - return return_dst; /* destination pointer. */ -} /* memset() */ + return return_dst; +} diff --git a/arch/frv/kernel/time.c b/arch/frv/kernel/time.c index 925fb0199a0..69f6a4ef5d6 100644 --- a/arch/frv/kernel/time.c +++ b/arch/frv/kernel/time.c @@ -63,6 +63,7 @@ static irqreturn_t timer_interrupt(int irq, void *dummy) /* last time the cmos clock got updated */ static long last_rtc_update = 0; + profile_tick(CPU_PROFILING); /* * Here we are in the timer irq handler. We just have irqs locally * disabled but we don't know if the timer_bh is running on the other @@ -73,8 +74,6 @@ static irqreturn_t timer_interrupt(int irq, void *dummy) write_seqlock(&xtime_lock); do_timer(1); - update_process_times(user_mode(get_irq_regs())); - profile_tick(CPU_PROFILING); /* * If we have an externally synchronized Linux clock, then update @@ -99,6 +98,9 @@ static irqreturn_t timer_interrupt(int irq, void *dummy) #endif /* CONFIG_HEARTBEAT */ write_sequnlock(&xtime_lock); + + update_process_times(user_mode(get_irq_regs())); + return IRQ_HANDLED; } diff --git a/arch/frv/kernel/vmlinux.lds.S b/arch/frv/kernel/vmlinux.lds.S index ef7527b8b0c..17725a55aed 100644 --- a/arch/frv/kernel/vmlinux.lds.S +++ b/arch/frv/kernel/vmlinux.lds.S @@ -105,11 +105,9 @@ SECTIONS SCHED_TEXT LOCK_TEXT #ifdef CONFIG_DEBUG_INFO - *( INIT_TEXT EXIT_TEXT - .exitcall.exit - ) + *(.exitcall.exit) #endif *(.fixup) *(.gnu.warning) diff --git a/arch/m68knommu/kernel/time.c b/arch/m68knommu/kernel/time.c index 89cdbcaeb45..0ccfb2ad638 100644 --- a/arch/m68knommu/kernel/time.c +++ b/arch/m68knommu/kernel/time.c @@ -42,14 +42,12 @@ irqreturn_t arch_timer_interrupt(int irq, void *dummy) /* last time the cmos clock got updated */ static long last_rtc_update=0; + if (current->pid) + profile_tick(CPU_PROFILING); + write_seqlock(&xtime_lock); do_timer(1); -#ifndef CONFIG_SMP - update_process_times(user_mode(get_irq_regs())); -#endif - if (current->pid) - profile_tick(CPU_PROFILING); /* * If we have an externally synchronized Linux clock, then update @@ -67,6 +65,10 @@ irqreturn_t arch_timer_interrupt(int irq, void *dummy) } write_sequnlock(&xtime_lock); + +#ifndef CONFIG_SMP + update_process_times(user_mode(get_irq_regs())); +#endif return(IRQ_HANDLED); } diff --git a/arch/m68knommu/platform/5206/Makefile b/arch/m68knommu/platform/5206/Makefile index c7bb0cef31a..a439d9ab3f2 100644 --- a/arch/m68knommu/platform/5206/Makefile +++ b/arch/m68knommu/platform/5206/Makefile @@ -12,9 +12,7 @@ # EXTRA_AFLAGS += -DTRAP_DBG_INTERRUPT # -ifdef CONFIG_FULLDEBUG -EXTRA_AFLAGS += -DDEBUGGER_COMPATIBLE_CACHE=1 -endif +asflags-$(CONFIG_FULLDEBUG) := -DDEBUGGER_COMPATIBLE_CACHE=1 obj-y := config.o diff --git a/arch/m68knommu/platform/5206e/Makefile b/arch/m68knommu/platform/5206e/Makefile index c7bb0cef31a..a439d9ab3f2 100644 --- a/arch/m68knommu/platform/5206e/Makefile +++ b/arch/m68knommu/platform/5206e/Makefile @@ -12,9 +12,7 @@ # EXTRA_AFLAGS += -DTRAP_DBG_INTERRUPT # -ifdef CONFIG_FULLDEBUG -EXTRA_AFLAGS += -DDEBUGGER_COMPATIBLE_CACHE=1 -endif +asflags-$(CONFIG_FULLDEBUG) := -DDEBUGGER_COMPATIBLE_CACHE=1 obj-y := config.o diff --git a/arch/m68knommu/platform/520x/Makefile b/arch/m68knommu/platform/520x/Makefile index 31b4eb51739..a50e76acc8f 100644 --- a/arch/m68knommu/platform/520x/Makefile +++ b/arch/m68knommu/platform/520x/Makefile @@ -12,8 +12,6 @@ # EXTRA_AFLAGS += -DTRAP_DBG_INTERRUPT # -ifdef CONFIG_FULLDEBUG -EXTRA_AFLAGS += -DDEBUGGER_COMPATIBLE_CACHE=1 -endif +asflags-$(CONFIG_FULLDEBUG) := -DDEBUGGER_COMPATIBLE_CACHE=1 obj-y := config.o diff --git a/arch/m68knommu/platform/523x/Makefile b/arch/m68knommu/platform/523x/Makefile index ac9fbece8a4..5694d593f02 100644 --- a/arch/m68knommu/platform/523x/Makefile +++ b/arch/m68knommu/platform/523x/Makefile @@ -12,8 +12,6 @@ # EXTRA_AFLAGS += -DTRAP_DBG_INTERRUPT # -ifdef CONFIG_FULLDEBUG -EXTRA_AFLAGS += -DDEBUGGER_COMPATIBLE_CACHE=1 -endif +asflags-$(CONFIG_FULLDEBUG) := -DDEBUGGER_COMPATIBLE_CACHE=1 obj-y := config.o diff --git a/arch/m68knommu/platform/5249/Makefile b/arch/m68knommu/platform/5249/Makefile index c7bb0cef31a..a439d9ab3f2 100644 --- a/arch/m68knommu/platform/5249/Makefile +++ b/arch/m68knommu/platform/5249/Makefile @@ -12,9 +12,7 @@ # EXTRA_AFLAGS += -DTRAP_DBG_INTERRUPT # -ifdef CONFIG_FULLDEBUG -EXTRA_AFLAGS += -DDEBUGGER_COMPATIBLE_CACHE=1 -endif +asflags-$(CONFIG_FULLDEBUG) := -DDEBUGGER_COMPATIBLE_CACHE=1 obj-y := config.o diff --git a/arch/m68knommu/platform/5272/Makefile b/arch/m68knommu/platform/5272/Makefile index 7475c38c3b4..26135d92b34 100644 --- a/arch/m68knommu/platform/5272/Makefile +++ b/arch/m68knommu/platform/5272/Makefile @@ -12,9 +12,7 @@ # EXTRA_AFLAGS += -DTRAP_DBG_INTERRUPT # -ifdef CONFIG_FULLDEBUG -EXTRA_AFLAGS += -DDEBUGGER_COMPATIBLE_CACHE=1 -endif +asflags-$(CONFIG_FULLDEBUG) := -DDEBUGGER_COMPATIBLE_CACHE=1 obj-y := config.o diff --git a/arch/m68knommu/platform/527x/Makefile b/arch/m68knommu/platform/527x/Makefile index 7475c38c3b4..26135d92b34 100644 --- a/arch/m68knommu/platform/527x/Makefile +++ b/arch/m68knommu/platform/527x/Makefile @@ -12,9 +12,7 @@ # EXTRA_AFLAGS += -DTRAP_DBG_INTERRUPT # -ifdef CONFIG_FULLDEBUG -EXTRA_AFLAGS += -DDEBUGGER_COMPATIBLE_CACHE=1 -endif +asflags-$(CONFIG_FULLDEBUG) := -DDEBUGGER_COMPATIBLE_CACHE=1 obj-y := config.o diff --git a/arch/m68knommu/platform/528x/Makefile b/arch/m68knommu/platform/528x/Makefile index 7475c38c3b4..26135d92b34 100644 --- a/arch/m68knommu/platform/528x/Makefile +++ b/arch/m68knommu/platform/528x/Makefile @@ -12,9 +12,7 @@ # EXTRA_AFLAGS += -DTRAP_DBG_INTERRUPT # -ifdef CONFIG_FULLDEBUG -EXTRA_AFLAGS += -DDEBUGGER_COMPATIBLE_CACHE=1 -endif +asflags-$(CONFIG_FULLDEBUG) := -DDEBUGGER_COMPATIBLE_CACHE=1 obj-y := config.o diff --git a/arch/m68knommu/platform/5307/Makefile b/arch/m68knommu/platform/5307/Makefile index 580fd6658d7..cfd586860fd 100644 --- a/arch/m68knommu/platform/5307/Makefile +++ b/arch/m68knommu/platform/5307/Makefile @@ -12,9 +12,7 @@ # EXTRA_AFLAGS += -DTRAP_DBG_INTERRUPT # -ifdef CONFIG_FULLDEBUG -EXTRA_AFLAGS += -DDEBUGGER_COMPATIBLE_CACHE=1 -endif +asflags-$(CONFIG_FULLDEBUG) := -DDEBUGGER_COMPATIBLE_CACHE=1 obj-y += config.o diff --git a/arch/m68knommu/platform/532x/Makefile b/arch/m68knommu/platform/532x/Makefile index 475b92866a9..e431912f562 100644 --- a/arch/m68knommu/platform/532x/Makefile +++ b/arch/m68knommu/platform/532x/Makefile @@ -12,9 +12,7 @@ # EXTRA_AFLAGS += -DTRAP_DBG_INTERRUPT # -ifdef CONFIG_FULLDEBUG -EXTRA_AFLAGS += -DDEBUGGER_COMPATIBLE_CACHE=1 -endif +asflags-$(CONFIG_FULLDEBUG) := -DDEBUGGER_COMPATIBLE_CACHE=1 #obj-y := config.o usb-mcf532x.o spi-mcf532x.o obj-y := config.o diff --git a/arch/m68knommu/platform/5407/Makefile b/arch/m68knommu/platform/5407/Makefile index 68633b27df5..e6035e7a2d3 100644 --- a/arch/m68knommu/platform/5407/Makefile +++ b/arch/m68knommu/platform/5407/Makefile @@ -12,9 +12,7 @@ # EXTRA_AFLAGS += -DTRAP_DBG_INTERRUPT # -ifdef CONFIG_FULLDEBUG -EXTRA_AFLAGS += -DDEBUGGER_COMPATIBLE_CACHE=1 -endif +asflags-$(CONFIG_FULLDEBUG) := -DDEBUGGER_COMPATIBLE_CACHE=1 obj-y := config.o diff --git a/arch/m68knommu/platform/coldfire/Makefile b/arch/m68knommu/platform/coldfire/Makefile index e5fff297ae0..40cf20be1b9 100644 --- a/arch/m68knommu/platform/coldfire/Makefile +++ b/arch/m68knommu/platform/coldfire/Makefile @@ -12,9 +12,7 @@ # EXTRA_AFLAGS += -DTRAP_DBG_INTERRUPT # -ifdef CONFIG_FULLDEBUG -AFLAGS += -DDEBUGGER_COMPATIBLE_CACHE=1 -endif +asflags-$(CONFIG_FULLDEBUG) := -DDEBUGGER_COMPATIBLE_CACHE=1 obj-$(CONFIG_COLDFIRE) += dma.o entry.o vectors.o obj-$(CONFIG_M5206) += timers.o diff --git a/arch/m68knommu/platform/coldfire/entry.S b/arch/m68knommu/platform/coldfire/entry.S index b333731b875..111b66dc737 100644 --- a/arch/m68knommu/platform/coldfire/entry.S +++ b/arch/m68knommu/platform/coldfire/entry.S @@ -197,14 +197,13 @@ ENTRY(fasthandler) RESTORE_LOCAL ENTRY(ret_from_interrupt) - jeq 2f -1: - RESTORE_ALL -2: moveb %sp@(PT_SR),%d0 andl #0x7,%d0 - jhi 1b + jeq 1f + RESTORE_ALL + +1: /* check if we need to do software interrupts */ movel irq_stat+CPUSTAT_SOFTIRQ_PENDING,%d0 jeq ret_from_exception diff --git a/arch/m68knommu/platform/coldfire/timers.c b/arch/m68knommu/platform/coldfire/timers.c index a60213e877e..ba5a9f32ebd 100644 --- a/arch/m68knommu/platform/coldfire/timers.c +++ b/arch/m68knommu/platform/coldfire/timers.c @@ -148,25 +148,32 @@ irqreturn_t coldfire_profile_tick(int irq, void *dummy) /* Reset ColdFire timer2 */ __raw_writeb(MCFTIMER_TER_CAP | MCFTIMER_TER_REF, PA(MCFTIMER_TER)); if (current->pid) - profile_tick(CPU_PROFILING, regs); + profile_tick(CPU_PROFILING); return IRQ_HANDLED; } /***************************************************************************/ +static struct irqaction coldfire_profile_irq = { + .name = "profile timer", + .flags = IRQF_DISABLED | IRQF_TIMER, + .handler = coldfire_profile_tick, +}; + void coldfire_profile_init(void) { - printk(KERN_INFO "PROFILE: lodging TIMER2 @ %dHz as profile timer\n", PROFILEHZ); + printk(KERN_INFO "PROFILE: lodging TIMER2 @ %dHz as profile timer\n", + PROFILEHZ); + + setup_irq(mcf_profilevector, &coldfire_profile_irq); /* Set up TIMER 2 as high speed profile clock */ __raw_writew(MCFTIMER_TMR_DISABLE, PA(MCFTIMER_TMR)); - __raw_writetrr(((MCF_CLK / 16) / PROFILEHZ), PA(MCFTIMER_TRR)); + __raw_writetrr(((MCF_BUSCLK / 16) / PROFILEHZ), PA(MCFTIMER_TRR)); __raw_writew(MCFTIMER_TMR_ENORI | MCFTIMER_TMR_CLK16 | MCFTIMER_TMR_RESTART | MCFTIMER_TMR_ENABLE, PA(MCFTIMER_TMR)); - request_irq(mcf_profilevector, coldfire_profile_tick, - (IRQF_DISABLED | IRQ_FLG_FAST), "profile timer", NULL); mcf_settimericr(2, 7); } diff --git a/arch/mips/kernel/sysirix.c b/arch/mips/kernel/sysirix.c index d70c4e0e85f..672fba84b2c 100644 --- a/arch/mips/kernel/sysirix.c +++ b/arch/mips/kernel/sysirix.c @@ -694,7 +694,7 @@ asmlinkage int irix_statfs(const char __user *path, if (error) goto out; - error = vfs_statfs(nd.dentry, &kbuf); + error = vfs_statfs(nd.path.dentry, &kbuf); if (error) goto dput_and_out; @@ -711,7 +711,7 @@ asmlinkage int irix_statfs(const char __user *path, } dput_and_out: - path_release(&nd); + path_put(&nd.path); out: return error; } @@ -1360,7 +1360,7 @@ asmlinkage int irix_statvfs(char __user *fname, struct irix_statvfs __user *buf) error = user_path_walk(fname, &nd); if (error) goto out; - error = vfs_statfs(nd.dentry, &kbuf); + error = vfs_statfs(nd.path.dentry, &kbuf); if (error) goto dput_and_out; @@ -1385,7 +1385,7 @@ asmlinkage int irix_statvfs(char __user *fname, struct irix_statvfs __user *buf) error |= __put_user(0, &buf->f_fstr[i]); dput_and_out: - path_release(&nd); + path_put(&nd.path); out: return error; } @@ -1611,7 +1611,7 @@ asmlinkage int irix_statvfs64(char __user *fname, struct irix_statvfs64 __user * error = user_path_walk(fname, &nd); if (error) goto out; - error = vfs_statfs(nd.dentry, &kbuf); + error = vfs_statfs(nd.path.dentry, &kbuf); if (error) goto dput_and_out; @@ -1636,7 +1636,7 @@ asmlinkage int irix_statvfs64(char __user *fname, struct irix_statvfs64 __user * error |= __put_user(0, &buf->f_fstr[i]); dput_and_out: - path_release(&nd); + path_put(&nd.path); out: return error; } diff --git a/arch/parisc/hpux/sys_hpux.c b/arch/parisc/hpux/sys_hpux.c index 3e025df2dc8..0c5b9dabb47 100644 --- a/arch/parisc/hpux/sys_hpux.c +++ b/arch/parisc/hpux/sys_hpux.c @@ -219,10 +219,10 @@ asmlinkage long hpux_statfs(const char __user *path, error = user_path_walk(path, &nd); if (!error) { struct hpux_statfs tmp; - error = vfs_statfs_hpux(nd.dentry, &tmp); + error = vfs_statfs_hpux(nd.path.dentry, &tmp); if (!error && copy_to_user(buf, &tmp, sizeof(tmp))) error = -EFAULT; - path_release(&nd); + path_put(&nd.path); } return error; } diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig index 485513c9f1a..5b8d8382b76 100644 --- a/arch/powerpc/Kconfig +++ b/arch/powerpc/Kconfig @@ -442,10 +442,6 @@ config SECCOMP If unsure, say Y. Only embedded should say N here. -config WANT_DEVICE_TREE - bool - default n - endmenu config ISA_DMA_API diff --git a/arch/powerpc/boot/Makefile b/arch/powerpc/boot/Makefile index 49797a45416..63d07ccbb9d 100644 --- a/arch/powerpc/boot/Makefile +++ b/arch/powerpc/boot/Makefile @@ -147,6 +147,8 @@ HOSTCFLAGS += -I$(src)/dtc-src/ -I$(src)/libfdt/ targets += dtc-src/dtc-parser.tab.c targets += dtc-src/dtc-lexer.lex.c +clean-files += dtc-src/dtc-parser.tab.h + ifdef DTC_GENPARSER BISON = bison FLEX = flex diff --git a/arch/powerpc/boot/ps3-hvcall.S b/arch/powerpc/boot/ps3-hvcall.S index 585965f7e6a..d6068f1829c 100644 --- a/arch/powerpc/boot/ps3-hvcall.S +++ b/arch/powerpc/boot/ps3-hvcall.S @@ -145,7 +145,7 @@ .macro STORE_REGS_5_2 lwz r11, 16(r1) std r4, 0(r11) - lwz r11, 24(r1) + lwz r11, 20(r1) std r5, 0(r11) .endm diff --git a/arch/powerpc/kernel/Makefile b/arch/powerpc/kernel/Makefile index 0662ae46f72..c1baf9d5903 100644 --- a/arch/powerpc/kernel/Makefile +++ b/arch/powerpc/kernel/Makefile @@ -104,3 +104,5 @@ quiet_cmd_systbl_chk = CALL $< PHONY += systbl_chk systbl_chk: $(src)/systbl_chk.sh $(obj)/systbl_chk.i $(call cmd,systbl_chk) + +clean-files := vmlinux.lds diff --git a/arch/powerpc/kernel/process.c b/arch/powerpc/kernel/process.c index b9d88374f14..4846bf543a8 100644 --- a/arch/powerpc/kernel/process.c +++ b/arch/powerpc/kernel/process.c @@ -462,7 +462,7 @@ void show_regs(struct pt_regs * regs) current, task_pid_nr(current), current->comm, task_thread_info(current)); #ifdef CONFIG_SMP - printk(" CPU: %d", smp_processor_id()); + printk(" CPU: %d", raw_smp_processor_id()); #endif /* CONFIG_SMP */ for (i = 0; i < 32; i++) { diff --git a/arch/powerpc/kernel/vdso.c b/arch/powerpc/kernel/vdso.c index 3702df7dc56..d3437c4c4a6 100644 --- a/arch/powerpc/kernel/vdso.c +++ b/arch/powerpc/kernel/vdso.c @@ -336,9 +336,9 @@ static unsigned long __init find_function32(struct lib32_elfinfo *lib, return sym->st_value - VDSO32_LBASE; } -static int vdso_do_func_patch32(struct lib32_elfinfo *v32, - struct lib64_elfinfo *v64, - const char *orig, const char *fix) +static int __init vdso_do_func_patch32(struct lib32_elfinfo *v32, + struct lib64_elfinfo *v64, + const char *orig, const char *fix) { Elf32_Sym *sym32_gen, *sym32_fix; @@ -433,9 +433,9 @@ static unsigned long __init find_function64(struct lib64_elfinfo *lib, #endif } -static int vdso_do_func_patch64(struct lib32_elfinfo *v32, - struct lib64_elfinfo *v64, - const char *orig, const char *fix) +static int __init vdso_do_func_patch64(struct lib32_elfinfo *v32, + struct lib64_elfinfo *v64, + const char *orig, const char *fix) { Elf64_Sym *sym64_gen, *sym64_fix; diff --git a/arch/powerpc/oprofile/cell/spu_task_sync.c b/arch/powerpc/oprofile/cell/spu_task_sync.c index 4a890cb42b9..257b13cb18a 100644 --- a/arch/powerpc/oprofile/cell/spu_task_sync.c +++ b/arch/powerpc/oprofile/cell/spu_task_sync.c @@ -198,14 +198,13 @@ out: * dcookie user still being registered (namely, the reader * of the event buffer). */ -static inline unsigned long fast_get_dcookie(struct dentry *dentry, - struct vfsmount *vfsmnt) +static inline unsigned long fast_get_dcookie(struct path *path) { unsigned long cookie; - if (dentry->d_cookie) - return (unsigned long)dentry; - get_dcookie(dentry, vfsmnt, &cookie); + if (path->dentry->d_cookie) + return (unsigned long)path->dentry; + get_dcookie(path, &cookie); return cookie; } @@ -240,8 +239,7 @@ get_exec_dcookie_and_offset(struct spu *spu, unsigned int *offsetp, continue; if (!(vma->vm_flags & VM_EXECUTABLE)) continue; - app_cookie = fast_get_dcookie(vma->vm_file->f_dentry, - vma->vm_file->f_vfsmnt); + app_cookie = fast_get_dcookie(&vma->vm_file->f_path); pr_debug("got dcookie for %s\n", vma->vm_file->f_dentry->d_name.name); app = vma->vm_file; @@ -262,8 +260,7 @@ get_exec_dcookie_and_offset(struct spu *spu, unsigned int *offsetp, break; } - *spu_bin_dcookie = fast_get_dcookie(vma->vm_file->f_dentry, - vma->vm_file->f_vfsmnt); + *spu_bin_dcookie = fast_get_dcookie(&vma->vm_file->f_path); pr_debug("got dcookie for %s\n", vma->vm_file->f_dentry->d_name.name); up_read(&mm->mmap_sem); diff --git a/arch/powerpc/platforms/512x/Kconfig b/arch/powerpc/platforms/512x/Kconfig index c6fa49e23dc..4c0da0c079e 100644 --- a/arch/powerpc/platforms/512x/Kconfig +++ b/arch/powerpc/platforms/512x/Kconfig @@ -13,7 +13,6 @@ config MPC5121_ADS bool "Freescale MPC5121E ADS" depends on PPC_MULTIPLATFORM && PPC32 select DEFAULT_UIMAGE - select WANT_DEVICE_TREE select PPC_MPC5121 help This option enables support for the MPC5121E ADS board. diff --git a/arch/powerpc/platforms/52xx/Kconfig b/arch/powerpc/platforms/52xx/Kconfig index 515f244c90b..cf945d55c27 100644 --- a/arch/powerpc/platforms/52xx/Kconfig +++ b/arch/powerpc/platforms/52xx/Kconfig @@ -8,7 +8,6 @@ config PPC_MPC5200_SIMPLE bool "Generic support for simple MPC5200 based boards" depends on PPC_MPC52xx select DEFAULT_UIMAGE - select WANT_DEVICE_TREE help This option enables support for a simple MPC52xx based boards which do not need a custom platform specific setup. Such boards are @@ -35,7 +34,6 @@ config PPC_LITE5200 bool "Freescale Lite5200 Eval Board" depends on PPC_MPC52xx select DEFAULT_UIMAGE - select WANT_DEVICE_TREE config PPC_MPC5200_BUGFIX bool "MPC5200 (L25R) bugfix support" diff --git a/arch/powerpc/platforms/Kconfig b/arch/powerpc/platforms/Kconfig index fcedbec07f9..0afd2259554 100644 --- a/arch/powerpc/platforms/Kconfig +++ b/arch/powerpc/platforms/Kconfig @@ -15,7 +15,6 @@ config PPC_MULTIPLATFORM config PPC_82xx bool "Freescale 82xx" depends on 6xx - select WANT_DEVICE_TREE config PPC_83xx bool "Freescale 83xx" @@ -23,7 +22,6 @@ config PPC_83xx select FSL_SOC select MPC83xx select IPIC - select WANT_DEVICE_TREE select FSL_EMB_PERFMON config PPC_86xx diff --git a/arch/powerpc/platforms/Kconfig.cputype b/arch/powerpc/platforms/Kconfig.cputype index 69941ba7097..73d81ce14b6 100644 --- a/arch/powerpc/platforms/Kconfig.cputype +++ b/arch/powerpc/platforms/Kconfig.cputype @@ -29,26 +29,22 @@ config PPC_85xx bool "Freescale 85xx" select E500 select FSL_SOC - select WANT_DEVICE_TREE select MPC85xx config PPC_8xx bool "Freescale 8xx" select FSL_SOC select 8xx - select WANT_DEVICE_TREE select PPC_LIB_RHEAP config 40x bool "AMCC 40x" select PPC_DCR_NATIVE - select WANT_DEVICE_TREE select PPC_UDBG_16550 config 44x bool "AMCC 44x" select PPC_DCR_NATIVE - select WANT_DEVICE_TREE select PPC_UDBG_16550 config E200 diff --git a/arch/powerpc/platforms/cell/ras.c b/arch/powerpc/platforms/cell/ras.c index b2494ebcdbe..e43024c0392 100644 --- a/arch/powerpc/platforms/cell/ras.c +++ b/arch/powerpc/platforms/cell/ras.c @@ -1,4 +1,13 @@ -#define DEBUG +/* + * Copyright 2006-2008, IBM Corporation. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ + +#undef DEBUG #include <linux/types.h> #include <linux/kernel.h> diff --git a/arch/powerpc/platforms/cell/spufs/inode.c b/arch/powerpc/platforms/cell/spufs/inode.c index e6e6559c55e..6d1228c66c5 100644 --- a/arch/powerpc/platforms/cell/spufs/inode.c +++ b/arch/powerpc/platforms/cell/spufs/inode.c @@ -1,3 +1,4 @@ + /* * SPU file system * @@ -592,7 +593,7 @@ long spufs_create(struct nameidata *nd, unsigned int flags, mode_t mode, ret = -EINVAL; /* check if we are on spufs */ - if (nd->dentry->d_sb->s_type != &spufs_type) + if (nd->path.dentry->d_sb->s_type != &spufs_type) goto out; /* don't accept undefined flags */ @@ -600,9 +601,9 @@ long spufs_create(struct nameidata *nd, unsigned int flags, mode_t mode, goto out; /* only threads can be underneath a gang */ - if (nd->dentry != nd->dentry->d_sb->s_root) { + if (nd->path.dentry != nd->path.dentry->d_sb->s_root) { if ((flags & SPU_CREATE_GANG) || - !SPUFS_I(nd->dentry->d_inode)->i_gang) + !SPUFS_I(nd->path.dentry->d_inode)->i_gang) goto out; } @@ -618,16 +619,17 @@ long spufs_create(struct nameidata *nd, unsigned int flags, mode_t mode, mode &= ~current->fs->umask; if (flags & SPU_CREATE_GANG) - return spufs_create_gang(nd->dentry->d_inode, - dentry, nd->mnt, mode); + return spufs_create_gang(nd->path.dentry->d_inode, + dentry, nd->path.mnt, mode); else - return spufs_create_context(nd->dentry->d_inode, - dentry, nd->mnt, flags, mode, filp); + return spufs_create_context(nd->path.dentry->d_inode, + dentry, nd->path.mnt, flags, mode, + filp); out_dput: dput(dentry); out_dir: - mutex_unlock(&nd->dentry->d_inode->i_mutex); + mutex_unlock(&nd->path.dentry->d_inode->i_mutex); out: return ret; } diff --git a/arch/powerpc/platforms/cell/spufs/sputrace.c b/arch/powerpc/platforms/cell/spufs/sputrace.c index 2b1953f6f12..01974f7776e 100644 --- a/arch/powerpc/platforms/cell/spufs/sputrace.c +++ b/arch/powerpc/platforms/cell/spufs/sputrace.c @@ -146,34 +146,28 @@ static void sputrace_log_item(const char *name, struct spu_context *ctx, wake_up(&sputrace_wait); } -static void spu_context_event(const struct marker *mdata, - void *private, const char *format, ...) +static void spu_context_event(void *probe_private, void *call_data, + const char *format, va_list *args) { - struct spu_probe *p = mdata->private; - va_list ap; + struct spu_probe *p = probe_private; struct spu_context *ctx; struct spu *spu; - va_start(ap, format); - ctx = va_arg(ap, struct spu_context *); - spu = va_arg(ap, struct spu *); + ctx = va_arg(*args, struct spu_context *); + spu = va_arg(*args, struct spu *); sputrace_log_item(p->name, ctx, spu); - va_end(ap); } -static void spu_context_nospu_event(const struct marker *mdata, - void *private, const char *format, ...) +static void spu_context_nospu_event(void *probe_private, void *call_data, + const char *format, va_list *args) { - struct spu_probe *p = mdata->private; - va_list ap; + struct spu_probe *p = probe_private; struct spu_context *ctx; - va_start(ap, format); - ctx = va_arg(ap, struct spu_context *); + ctx = va_arg(*args, struct spu_context *); sputrace_log_item(p->name, ctx, NULL); - va_end(ap); } struct spu_probe spu_probes[] = { @@ -219,10 +213,6 @@ static int __init sputrace_init(void) if (error) printk(KERN_INFO "Unable to register probe %s\n", p->name); - - error = marker_arm(p->name); - if (error) - printk(KERN_INFO "Unable to arm probe %s\n", p->name); } return 0; @@ -238,7 +228,8 @@ static void __exit sputrace_exit(void) int i; for (i = 0; i < ARRAY_SIZE(spu_probes); i++) - marker_probe_unregister(spu_probes[i].name); + marker_probe_unregister(spu_probes[i].name, + spu_probes[i].probe_func, &spu_probes[i]); remove_proc_entry("sputrace", NULL); kfree(sputrace_log); diff --git a/arch/powerpc/platforms/cell/spufs/syscalls.c b/arch/powerpc/platforms/cell/spufs/syscalls.c index 43040441317..49c87769b1f 100644 --- a/arch/powerpc/platforms/cell/spufs/syscalls.c +++ b/arch/powerpc/platforms/cell/spufs/syscalls.c @@ -73,7 +73,7 @@ static long do_spu_create(const char __user *pathname, unsigned int flags, LOOKUP_OPEN|LOOKUP_CREATE, &nd); if (!ret) { ret = spufs_create(&nd, flags, mode, neighbor); - path_release(&nd); + path_put(&nd.path); } putname(tmp); } diff --git a/arch/powerpc/platforms/embedded6xx/Kconfig b/arch/powerpc/platforms/embedded6xx/Kconfig index 6c808375793..42908896781 100644 --- a/arch/powerpc/platforms/embedded6xx/Kconfig +++ b/arch/powerpc/platforms/embedded6xx/Kconfig @@ -24,7 +24,6 @@ config STORCENTER select MPIC select FSL_SOC select PPC_UDBG_16550 if SERIAL_8250 - select WANT_DEVICE_TREE select MPC10X_OPENPIC select MPC10X_BRIDGE help @@ -37,7 +36,6 @@ config MPC7448HPC2 select TSI108_BRIDGE select DEFAULT_UIMAGE select PPC_UDBG_16550 - select WANT_DEVICE_TREE select TSI108_BRIDGE help Select MPC7448HPC2 if configuring for Freescale MPC7448HPC2 (Taiga) @@ -48,7 +46,6 @@ config PPC_HOLLY depends on EMBEDDED6xx select TSI108_BRIDGE select PPC_UDBG_16550 - select WANT_DEVICE_TREE select TSI108_BRIDGE help Select PPC_HOLLY if configuring for an IBM 750GX/CL Eval @@ -59,7 +56,6 @@ config PPC_PRPMC2800 depends on EMBEDDED6xx select MV64X60 select NOT_COHERENT_CACHE - select WANT_DEVICE_TREE help This option enables support for the Motorola PrPMC2800 board diff --git a/arch/powerpc/platforms/iseries/vio.c b/arch/powerpc/platforms/iseries/vio.c index be06cfd9fa3..657b72f6849 100644 --- a/arch/powerpc/platforms/iseries/vio.c +++ b/arch/powerpc/platforms/iseries/vio.c @@ -75,7 +75,7 @@ static struct property *new_property(const char *name, int length, return np; } -static void __init free_property(struct property *np) +static void free_property(struct property *np) { kfree(np); } diff --git a/arch/sh/Kconfig b/arch/sh/Kconfig index d87d4bf8880..b3400b5ad5c 100644 --- a/arch/sh/Kconfig +++ b/arch/sh/Kconfig @@ -93,6 +93,9 @@ config ARCH_NO_VIRT_TO_BUS config ARCH_SUPPORTS_AOUT def_bool y +config IO_TRAPPED + bool + source "init/Kconfig" menu "System type" @@ -312,6 +315,13 @@ config CPU_SUBTYPE_SH7722 select ARCH_SPARSEMEM_ENABLE select SYS_SUPPORTS_NUMA +config CPU_SUBTYPE_SH7366 + bool "Support SH7366 processor" + select CPU_SH4AL_DSP + select CPU_SHX2 + select ARCH_SPARSEMEM_ENABLE + select SYS_SUPPORTS_NUMA + # SH-5 Processor Support config CPU_SUBTYPE_SH5_101 @@ -456,6 +466,7 @@ config SH_RTS7751R2D bool "RTS7751R2D" depends on CPU_SUBTYPE_SH7751R select SYS_SUPPORTS_PCI + select IO_TRAPPED help Select RTS7751R2D if configuring for a Renesas Technology Sales SH-Graphics board. @@ -472,6 +483,14 @@ config SH_HIGHLANDER bool "Highlander" depends on CPU_SUBTYPE_SH7780 || CPU_SUBTYPE_SH7785 select SYS_SUPPORTS_PCI + select IO_TRAPPED + +config SH_MIGOR + bool "Migo-R" + depends on CPU_SUBTYPE_SH7722 + help + Select Migo-R if configuring for the SH7722 Migo-R platform + by Renesas System Solutions Asia Pte. Ltd. config SH_EDOSK7705 bool "EDOSK7705" diff --git a/arch/sh/Kconfig.cpu b/arch/sh/Kconfig.cpu index d850184d069..0e27fe3b182 100644 --- a/arch/sh/Kconfig.cpu +++ b/arch/sh/Kconfig.cpu @@ -12,6 +12,7 @@ config CPU_LITTLE_ENDIAN config CPU_BIG_ENDIAN bool "Big Endian" + depends on !CPU_SH5 endchoice @@ -87,9 +88,6 @@ config SH64_ID2815_WORKAROUND config CPU_HAS_INTEVT bool -config CPU_HAS_MASKREG_IRQ - bool - config CPU_HAS_IPR_IRQ bool diff --git a/arch/sh/Kconfig.debug b/arch/sh/Kconfig.debug index f7c716166ce..5dcb74b947a 100644 --- a/arch/sh/Kconfig.debug +++ b/arch/sh/Kconfig.debug @@ -29,7 +29,8 @@ config EARLY_SCIF_CONSOLE config EARLY_SCIF_CONSOLE_PORT hex depends on EARLY_SCIF_CONSOLE - default "0xffe00000" if CPU_SUBTYPE_SH7780 || CPU_SUBTYPE_SH7763 + default "0xffe00000" if CPU_SUBTYPE_SH7780 || CPU_SUBTYPE_SH7763 + default "0xffe00000" if CPU_SUBTYPE_SH7722 || CPU_SUBTYPE_SH7366 default "0xffea0000" if CPU_SUBTYPE_SH7785 default "0xfffe8000" if CPU_SUBTYPE_SH7203 default "0xfffe9800" if CPU_SUBTYPE_SH7206 || CPU_SUBTYPE_SH7263 diff --git a/arch/sh/Makefile b/arch/sh/Makefile index 17fc36186bf..81381e5773c 100644 --- a/arch/sh/Makefile +++ b/arch/sh/Makefile @@ -116,6 +116,7 @@ machdir-$(CONFIG_SH_RTS7751R2D) += renesas/rts7751r2d machdir-$(CONFIG_SH_7751_SYSTEMH) += renesas/systemh machdir-$(CONFIG_SH_EDOSK7705) += renesas/edosk7705 machdir-$(CONFIG_SH_HIGHLANDER) += renesas/r7780rp +machdir-$(CONFIG_SH_MIGOR) += renesas/migor machdir-$(CONFIG_SH_SDK7780) += renesas/sdk7780 machdir-$(CONFIG_SH_7710VOIPGW) += renesas/sh7710voipgw machdir-$(CONFIG_SH_X3PROTO) += renesas/x3proto diff --git a/arch/sh/boards/renesas/migor/Makefile b/arch/sh/boards/renesas/migor/Makefile new file mode 100644 index 00000000000..77037567633 --- /dev/null +++ b/arch/sh/boards/renesas/migor/Makefile @@ -0,0 +1 @@ +obj-y := setup.o diff --git a/arch/sh/boards/renesas/migor/setup.c b/arch/sh/boards/renesas/migor/setup.c new file mode 100644 index 00000000000..21ab8c8fb59 --- /dev/null +++ b/arch/sh/boards/renesas/migor/setup.c @@ -0,0 +1,61 @@ +/* + * Renesas System Solutions Asia Pte. Ltd - Migo-R + * + * Copyright (C) 2008 Magnus Damm + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + */ +#include <linux/init.h> +#include <linux/platform_device.h> +#include <linux/interrupt.h> +#include <asm/machvec.h> +#include <asm/io.h> + +/* Address IRQ Size Bus Description + * 0x00000000 64MB 16 NOR Flash (SP29PL256N) + * 0x0c000000 64MB 64 SDRAM (2xK4M563233G) + * 0x10000000 IRQ0 16 Ethernet (SMC91C111) + * 0x14000000 IRQ4 16 USB 2.0 Host Controller (M66596) + * 0x18000000 8GB 8 NAND Flash (K9K8G08U0A) + */ + +static struct resource smc91x_eth_resources[] = { + [0] = { + .name = "smc91x-regs" , + .start = P2SEGADDR(0x10000300), + .end = P2SEGADDR(0x1000030f), + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = 32, /* IRQ0 */ + .flags = IORESOURCE_IRQ | IRQF_TRIGGER_HIGH, + }, +}; + +static struct platform_device smc91x_eth_device = { + .name = "smc91x", + .num_resources = ARRAY_SIZE(smc91x_eth_resources), + .resource = smc91x_eth_resources, +}; + +static struct platform_device *migor_devices[] __initdata = { + &smc91x_eth_device, +}; + +static int __init migor_devices_setup(void) +{ + return platform_add_devices(migor_devices, ARRAY_SIZE(migor_devices)); +} +__initcall(migor_devices_setup); + +static void __init migor_setup(char **cmdline_p) +{ + ctrl_outw(0x1000, 0xa4050110); /* Enable IRQ0 in PJCR */ +} + +static struct sh_machine_vector mv_migor __initmv = { + .mv_name = "Migo-R", + .mv_setup = migor_setup, +}; diff --git a/arch/sh/boards/renesas/r7780rp/setup.c b/arch/sh/boards/renesas/r7780rp/setup.c index f7a8d5c9d51..2f68bea7890 100644 --- a/arch/sh/boards/renesas/r7780rp/setup.c +++ b/arch/sh/boards/renesas/r7780rp/setup.c @@ -23,6 +23,7 @@ #include <asm/clock.h> #include <asm/heartbeat.h> #include <asm/io.h> +#include <asm/io_trapped.h> static struct resource r8a66597_usb_host_resources[] = { [0] = { @@ -181,13 +182,27 @@ static struct platform_device *r7780rp_devices[] __initdata = { &m66592_usb_peripheral_device, &heartbeat_device, #ifndef CONFIG_SH_R7780RP - &cf_ide_device, &ax88796_device, #endif }; +/* + * The CF is connected using a 16-bit bus where 8-bit operations are + * unsupported. The linux ata driver is however using 8-bit operations, so + * insert a trapped io filter to convert 8-bit operations into 16-bit. + */ +static struct trapped_io cf_trapped_io = { + .resource = cf_ide_resources, + .num_resources = 2, + .minimum_bus_width = 16, +}; + static int __init r7780rp_devices_setup(void) { +#ifndef CONFIG_SH_R7780RP + if (register_trapped_io(&cf_trapped_io) == 0) + platform_device_register(&cf_ide_device); +#endif return platform_add_devices(r7780rp_devices, ARRAY_SIZE(r7780rp_devices)); } @@ -226,34 +241,6 @@ static void r7780rp_power_off(void) ctrl_outw(0x0001, PA_POFF); } -static inline unsigned char is_ide_ioaddr(unsigned long addr) -{ - return ((cf_ide_resources[0].start <= addr && - addr <= cf_ide_resources[0].end) || - (cf_ide_resources[1].start <= addr && - addr <= cf_ide_resources[1].end)); -} - -void highlander_writeb(u8 b, void __iomem *addr) -{ - unsigned long tmp = (unsigned long __force)addr; - - if (is_ide_ioaddr(tmp)) - ctrl_outw((u16)b, tmp); - else - ctrl_outb(b, tmp); -} - -u8 highlander_readb(void __iomem *addr) -{ - unsigned long tmp = (unsigned long __force)addr; - - if (is_ide_ioaddr(tmp)) - return ctrl_inw(tmp) & 0xff; - else - return ctrl_inb(tmp); -} - /* * Initialize the board */ @@ -338,6 +325,4 @@ static struct sh_machine_vector mv_highlander __initmv = { .mv_setup = highlander_setup, .mv_init_irq = highlander_init_irq, .mv_irq_demux = highlander_irq_demux, - .mv_readb = highlander_readb, - .mv_writeb = highlander_writeb, }; diff --git a/arch/sh/boards/renesas/rts7751r2d/setup.c b/arch/sh/boards/renesas/rts7751r2d/setup.c index a0ef81b7de3..f21ee49ef3a 100644 --- a/arch/sh/boards/renesas/rts7751r2d/setup.c +++ b/arch/sh/boards/renesas/rts7751r2d/setup.c @@ -21,6 +21,7 @@ #include <asm/machvec.h> #include <asm/rts7751r2d.h> #include <asm/io.h> +#include <asm/io_trapped.h> #include <asm/spi.h> static struct resource cf_ide_resources[] = { @@ -214,13 +215,25 @@ static struct platform_device *rts7751r2d_devices[] __initdata = { &uart_device, &sm501_device, #endif - &cf_ide_device, &heartbeat_device, &spi_sh_sci_device, }; +/* + * The CF is connected with a 16-bit bus where 8-bit operations are + * unsupported. The linux ata driver is however using 8-bit operations, so + * insert a trapped io filter to convert 8-bit operations into 16-bit. + */ +static struct trapped_io cf_trapped_io = { + .resource = cf_ide_resources, + .num_resources = 2, + .minimum_bus_width = 16, +}; + static int __init rts7751r2d_devices_setup(void) { + if (register_trapped_io(&cf_trapped_io) == 0) + platform_device_register(&cf_ide_device); spi_register_board_info(spi_bus, ARRAY_SIZE(spi_bus)); return platform_add_devices(rts7751r2d_devices, ARRAY_SIZE(rts7751r2d_devices)); @@ -232,34 +245,6 @@ static void rts7751r2d_power_off(void) ctrl_outw(0x0001, PA_POWOFF); } -static inline unsigned char is_ide_ioaddr(unsigned long addr) -{ - return ((cf_ide_resources[0].start <= addr && - addr <= cf_ide_resources[0].end) || - (cf_ide_resources[1].start <= addr && - addr <= cf_ide_resources[1].end)); -} - -void rts7751r2d_writeb(u8 b, void __iomem *addr) -{ - unsigned long tmp = (unsigned long __force)addr; - - if (is_ide_ioaddr(tmp)) - ctrl_outw((u16)b, tmp); - else - ctrl_outb(b, tmp); -} - -u8 rts7751r2d_readb(void __iomem *addr) -{ - unsigned long tmp = (unsigned long __force)addr; - - if (is_ide_ioaddr(tmp)) - return ctrl_inw(tmp) & 0xff; - else - return ctrl_inb(tmp); -} - /* * Initialize the board */ @@ -310,6 +295,4 @@ static struct sh_machine_vector mv_rts7751r2d __initmv = { .mv_setup = rts7751r2d_setup, .mv_init_irq = init_rts7751r2d_IRQ, .mv_irq_demux = rts7751r2d_irq_demux, - .mv_writeb = rts7751r2d_writeb, - .mv_readb = rts7751r2d_readb, }; diff --git a/arch/sh/boards/renesas/sdk7780/Kconfig b/arch/sh/boards/renesas/sdk7780/Kconfig index e4f5b6985be..065f1df09bf 100644 --- a/arch/sh/boards/renesas/sdk7780/Kconfig +++ b/arch/sh/boards/renesas/sdk7780/Kconfig @@ -4,13 +4,6 @@ choice prompt "SDK7780 options" default SH_SDK7780_BASE -config SH_SDK7780_STANDALONE - bool "SDK7780 board support" - depends on CPU_SUBTYPE_SH7780 - help - Selecting this option will enable support for the - standalone version of the SDK7780. If in doubt, say Y. - config SH_SDK7780_BASE bool "SDK7780 with base-board support" depends on CPU_SUBTYPE_SH7780 diff --git a/arch/sh/cchips/hd6446x/hd64465/setup.c b/arch/sh/cchips/hd6446x/hd64465/setup.c index 5cef0db4018..9b8820c3670 100644 --- a/arch/sh/cchips/hd6446x/hd64465/setup.c +++ b/arch/sh/cchips/hd6446x/hd64465/setup.c @@ -17,10 +17,8 @@ #include <linux/interrupt.h> #include <linux/init.h> #include <linux/irq.h> - #include <asm/io.h> #include <asm/irq.h> - #include <asm/hd64465/hd64465.h> static void disable_hd64465_irq(unsigned int irq) @@ -28,51 +26,45 @@ static void disable_hd64465_irq(unsigned int irq) unsigned short nimr; unsigned short mask = 1 << (irq - HD64465_IRQ_BASE); - pr_debug("disable_hd64465_irq(%d): mask=%x\n", irq, mask); + pr_debug("disable_hd64465_irq(%d): mask=%x\n", irq, mask); nimr = inw(HD64465_REG_NIMR); nimr |= mask; outw(nimr, HD64465_REG_NIMR); } - static void enable_hd64465_irq(unsigned int irq) { unsigned short nimr; unsigned short mask = 1 << (irq - HD64465_IRQ_BASE); - pr_debug("enable_hd64465_irq(%d): mask=%x\n", irq, mask); + pr_debug("enable_hd64465_irq(%d): mask=%x\n", irq, mask); nimr = inw(HD64465_REG_NIMR); nimr &= ~mask; outw(nimr, HD64465_REG_NIMR); } - static void mask_and_ack_hd64465(unsigned int irq) { disable_hd64465_irq(irq); } - static void end_hd64465_irq(unsigned int irq) { if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS))) enable_hd64465_irq(irq); } - static unsigned int startup_hd64465_irq(unsigned int irq) -{ +{ enable_hd64465_irq(irq); return 0; } - static void shutdown_hd64465_irq(unsigned int irq) { disable_hd64465_irq(irq); } - static struct hw_interrupt_type hd64465_irq_type = { .typename = "HD64465-IRQ", .startup = startup_hd64465_irq, @@ -83,7 +75,6 @@ static struct hw_interrupt_type hd64465_irq_type = { .end = end_hd64465_irq, }; - static irqreturn_t hd64465_interrupt(int irq, void *dev_id) { printk(KERN_INFO @@ -93,9 +84,6 @@ static irqreturn_t hd64465_interrupt(int irq, void *dev_id) return IRQ_NONE; } - -/*====================================================*/ - /* * Support for a secondary IRQ demux step. This is necessary * because the HD64465 presents a very thin interface to the @@ -103,8 +91,7 @@ static irqreturn_t hd64465_interrupt(int irq, void *dev_id) * normally done in hardware by other PCMCIA host bridges is * instead done in software. */ -static struct -{ +static struct { int (*func)(int, void *); void *dev; } hd64465_demux[HD64465_IRQ_NUM]; @@ -112,19 +99,17 @@ static struct void hd64465_register_irq_demux(int irq, int (*demux)(int irq, void *dev), void *dev) { - hd64465_demux[irq - HD64465_IRQ_BASE].func = demux; - hd64465_demux[irq - HD64465_IRQ_BASE].dev = dev; + hd64465_demux[irq - HD64465_IRQ_BASE].func = demux; + hd64465_demux[irq - HD64465_IRQ_BASE].dev = dev; } EXPORT_SYMBOL(hd64465_register_irq_demux); void hd64465_unregister_irq_demux(int irq) { - hd64465_demux[irq - HD64465_IRQ_BASE].func = 0; + hd64465_demux[irq - HD64465_IRQ_BASE].func = 0; } EXPORT_SYMBOL(hd64465_unregister_irq_demux); - - int hd64465_irq_demux(int irq) { if (irq == CONFIG_HD64465_IRQ) { @@ -132,16 +117,16 @@ int hd64465_irq_demux(int irq) unsigned short nirr = inw(HD64465_REG_NIRR); unsigned short nimr = inw(HD64465_REG_NIMR); - pr_debug("hd64465_irq_demux, nirr=%04x, nimr=%04x\n", nirr, nimr); + pr_debug("hd64465_irq_demux, nirr=%04x, nimr=%04x\n", nirr, nimr); nirr &= ~nimr; for (bit = 1, i = 0 ; i < HD64465_IRQ_NUM ; bit <<= 1, i++) if (nirr & bit) - break; + break; - if (i < HD64465_IRQ_NUM) { + if (i < HD64465_IRQ_NUM) { irq = HD64465_IRQ_BASE + i; - if (hd64465_demux[i].func != 0) - irq = hd64465_demux[i].func(irq, hd64465_demux[i].dev); + if (hd64465_demux[i].func != 0) + irq = hd64465_demux[i].func(irq, hd64465_demux[i].dev); } } return irq; @@ -154,7 +139,6 @@ static struct irqaction irq0 = { .name = "HD64465", }; - static int __init setup_hd64465(void) { int i; @@ -176,8 +160,8 @@ static int __init setup_hd64465(void) rev = inw(HD64465_REG_SRR); printk(KERN_INFO "HD64465 hardware revision %d.%d\n", (rev >> 8) & 0xff, rev & 0xff); - - outw(0xffff, HD64465_REG_NIMR); /* mask all interrupts */ + + outw(0xffff, HD64465_REG_NIMR); /* mask all interrupts */ for (i = 0; i < HD64465_IRQ_NUM ; i++) { irq_desc[HD64465_IRQ_BASE + i].chip = &hd64465_irq_type; @@ -185,16 +169,13 @@ static int __init setup_hd64465(void) setup_irq(CONFIG_HD64465_IRQ, &irq0); -#ifdef CONFIG_SERIAL /* wake up the UART from STANDBY at this point */ smscr = inw(HD64465_REG_SMSCR); outw(smscr & (~HD64465_SMSCR_UARTST), HD64465_REG_SMSCR); /* remap IO ports for first ISA serial port to HD64465 UART */ hd64465_port_map(0x3f8, 8, CONFIG_HD64465_IOBASE + 0x8000, 1); -#endif return 0; } - module_init(setup_hd64465); diff --git a/arch/sh/configs/migor_defconfig b/arch/sh/configs/migor_defconfig new file mode 100644 index 00000000000..ee5900817f8 --- /dev/null +++ b/arch/sh/configs/migor_defconfig @@ -0,0 +1,824 @@ +# +# Automatically generated make config: don't edit +# Linux kernel version: 2.6.24 +# Wed Feb 6 21:52:20 2008 +# +CONFIG_SUPERH=y +CONFIG_SUPERH32=y +CONFIG_RWSEM_GENERIC_SPINLOCK=y +CONFIG_GENERIC_BUG=y +CONFIG_GENERIC_FIND_NEXT_BIT=y +CONFIG_GENERIC_HWEIGHT=y +CONFIG_GENERIC_HARDIRQS=y +CONFIG_GENERIC_IRQ_PROBE=y +CONFIG_GENERIC_CALIBRATE_DELAY=y +CONFIG_GENERIC_TIME=y +CONFIG_GENERIC_CLOCKEVENTS=y +CONFIG_SYS_SUPPORTS_NUMA=y +CONFIG_STACKTRACE_SUPPORT=y +CONFIG_LOCKDEP_SUPPORT=y +# CONFIG_ARCH_HAS_ILOG2_U32 is not set +# CONFIG_ARCH_HAS_ILOG2_U64 is not set +CONFIG_ARCH_NO_VIRT_TO_BUS=y +CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config" + +# +# General setup +# +CONFIG_EXPERIMENTAL=y +CONFIG_BROKEN_ON_SMP=y +CONFIG_INIT_ENV_ARG_LIMIT=32 +CONFIG_LOCALVERSION="" +CONFIG_LOCALVERSION_AUTO=y +CONFIG_SWAP=y +CONFIG_SYSVIPC=y +CONFIG_SYSVIPC_SYSCTL=y +# CONFIG_POSIX_MQUEUE is not set +# CONFIG_BSD_PROCESS_ACCT is not set +# CONFIG_TASKSTATS is not set +# CONFIG_USER_NS is not set +# CONFIG_PID_NS is not set +# CONFIG_AUDIT is not set +CONFIG_IKCONFIG=y +CONFIG_IKCONFIG_PROC=y +CONFIG_LOG_BUF_SHIFT=14 +# CONFIG_CGROUPS is not set +CONFIG_FAIR_GROUP_SCHED=y +CONFIG_FAIR_USER_SCHED=y +# CONFIG_FAIR_CGROUP_SCHED is not set +CONFIG_SYSFS_DEPRECATED=y +# CONFIG_RELAY is not set +CONFIG_BLK_DEV_INITRD=y +CONFIG_INITRAMFS_SOURCE="" +# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set +CONFIG_SYSCTL=y +CONFIG_EMBEDDED=y +CONFIG_UID16=y +# CONFIG_SYSCTL_SYSCALL is not set +CONFIG_KALLSYMS=y +# CONFIG_KALLSYMS_EXTRA_PASS is not set +CONFIG_HOTPLUG=y +CONFIG_PRINTK=y +CONFIG_BUG=y +CONFIG_ELF_CORE=y +CONFIG_BASE_FULL=y +CONFIG_FUTEX=y +CONFIG_ANON_INODES=y +CONFIG_EPOLL=y +CONFIG_SIGNALFD=y +CONFIG_EVENTFD=y +CONFIG_SHMEM=y +CONFIG_VM_EVENT_COUNTERS=y +CONFIG_SLAB=y +# CONFIG_SLUB is not set +# CONFIG_SLOB is not set +CONFIG_PROFILING=y +# CONFIG_MARKERS is not set +CONFIG_OPROFILE=y +CONFIG_HAVE_OPROFILE=y +# CONFIG_HAVE_KPROBES is not set +CONFIG_SLABINFO=y +CONFIG_RT_MUTEXES=y +# CONFIG_TINY_SHMEM is not set +CONFIG_BASE_SMALL=0 +CONFIG_MODULES=y +# CONFIG_MODULE_UNLOAD is not set +# CONFIG_MODVERSIONS is not set +# CONFIG_MODULE_SRCVERSION_ALL is not set +# CONFIG_KMOD is not set +CONFIG_BLOCK=y +# CONFIG_LBD is not set +# CONFIG_BLK_DEV_IO_TRACE is not set +# CONFIG_LSF is not set +# CONFIG_BLK_DEV_BSG is not set + +# +# IO Schedulers +# +CONFIG_IOSCHED_NOOP=y +CONFIG_IOSCHED_AS=y +CONFIG_IOSCHED_DEADLINE=y +CONFIG_IOSCHED_CFQ=y +CONFIG_DEFAULT_AS=y +# CONFIG_DEFAULT_DEADLINE is not set +# CONFIG_DEFAULT_CFQ is not set +# CONFIG_DEFAULT_NOOP is not set +CONFIG_DEFAULT_IOSCHED="anticipatory" +CONFIG_CLASSIC_RCU=y +# CONFIG_PREEMPT_RCU is not set + +# +# System type +# +CONFIG_CPU_SH4=y +CONFIG_CPU_SH4A=y +CONFIG_CPU_SH4AL_DSP=y +CONFIG_CPU_SHX2=y +# CONFIG_CPU_SUBTYPE_SH7619 is not set +# CONFIG_CPU_SUBTYPE_SH7203 is not set +# CONFIG_CPU_SUBTYPE_SH7206 is not set +# CONFIG_CPU_SUBTYPE_SH7263 is not set +# CONFIG_CPU_SUBTYPE_SH7705 is not set +# CONFIG_CPU_SUBTYPE_SH7706 is not set +# CONFIG_CPU_SUBTYPE_SH7707 is not set +# CONFIG_CPU_SUBTYPE_SH7708 is not set +# CONFIG_CPU_SUBTYPE_SH7709 is not set +# CONFIG_CPU_SUBTYPE_SH7710 is not set +# CONFIG_CPU_SUBTYPE_SH7712 is not set +# CONFIG_CPU_SUBTYPE_SH7720 is not set +# CONFIG_CPU_SUBTYPE_SH7721 is not set +# CONFIG_CPU_SUBTYPE_SH7750 is not set +# CONFIG_CPU_SUBTYPE_SH7091 is not set +# CONFIG_CPU_SUBTYPE_SH7750R is not set +# CONFIG_CPU_SUBTYPE_SH7750S is not set +# CONFIG_CPU_SUBTYPE_SH7751 is not set +# CONFIG_CPU_SUBTYPE_SH7751R is not set +# CONFIG_CPU_SUBTYPE_SH7760 is not set +# CONFIG_CPU_SUBTYPE_SH4_202 is not set +# CONFIG_CPU_SUBTYPE_SH7763 is not set +# CONFIG_CPU_SUBTYPE_SH7770 is not set +# CONFIG_CPU_SUBTYPE_SH7780 is not set +# CONFIG_CPU_SUBTYPE_SH7785 is not set +# CONFIG_CPU_SUBTYPE_SHX3 is not set +# CONFIG_CPU_SUBTYPE_SH7343 is not set +CONFIG_CPU_SUBTYPE_SH7722=y +# CONFIG_CPU_SUBTYPE_SH5_101 is not set +# CONFIG_CPU_SUBTYPE_SH5_103 is not set + +# +# Memory management options +# +CONFIG_QUICKLIST=y +CONFIG_MMU=y +CONFIG_PAGE_OFFSET=0x80000000 +CONFIG_MEMORY_START=0x0c000000 +CONFIG_MEMORY_SIZE=0x04000000 +CONFIG_29BIT=y +# CONFIG_X2TLB is not set +CONFIG_VSYSCALL=y +CONFIG_NUMA=y +CONFIG_NODES_SHIFT=1 +CONFIG_ARCH_SPARSEMEM_ENABLE=y +CONFIG_ARCH_SPARSEMEM_DEFAULT=y +CONFIG_MAX_ACTIVE_REGIONS=2 +CONFIG_ARCH_POPULATES_NODE_MAP=y +CONFIG_ARCH_SELECT_MEMORY_MODEL=y +CONFIG_ARCH_ENABLE_MEMORY_HOTPLUG=y +CONFIG_PAGE_SIZE_4KB=y +# CONFIG_PAGE_SIZE_8KB is not set +# CONFIG_PAGE_SIZE_64KB is not set +CONFIG_SELECT_MEMORY_MODEL=y +# CONFIG_FLATMEM_MANUAL is not set +# CONFIG_DISCONTIGMEM_MANUAL is not set +CONFIG_SPARSEMEM_MANUAL=y +CONFIG_SPARSEMEM=y +CONFIG_NEED_MULTIPLE_NODES=y +CONFIG_HAVE_MEMORY_PRESENT=y +CONFIG_SPARSEMEM_STATIC=y +# CONFIG_SPARSEMEM_VMEMMAP_ENABLE is not set +# CONFIG_MEMORY_HOTPLUG is not set +CONFIG_SPLIT_PTLOCK_CPUS=4 +# CONFIG_MIGRATION is not set +# CONFIG_RESOURCES_64BIT is not set +CONFIG_ZONE_DMA_FLAG=0 +CONFIG_NR_QUICK=2 + +# +# Cache configuration +# +# CONFIG_SH_DIRECT_MAPPED is not set +CONFIG_CACHE_WRITEBACK=y +# CONFIG_CACHE_WRITETHROUGH is not set +# CONFIG_CACHE_OFF is not set + +# +# Processor features +# +CONFIG_CPU_LITTLE_ENDIAN=y +# CONFIG_CPU_BIG_ENDIAN is not set +# CONFIG_SH_FPU_EMU is not set +CONFIG_SH_DSP=y +# CONFIG_SH_STORE_QUEUES is not set +CONFIG_CPU_HAS_INTEVT=y +CONFIG_CPU_HAS_SR_RB=y +CONFIG_CPU_HAS_PTEA=y +CONFIG_CPU_HAS_DSP=y + +# +# Board support +# +# CONFIG_SH_7722_SOLUTION_ENGINE is not set +CONFIG_SH_MIGOR=y + +# +# Timer and clock configuration +# +CONFIG_SH_TMU=y +CONFIG_SH_TIMER_IRQ=16 +CONFIG_SH_PCLK_FREQ=33333333 +# CONFIG_TICK_ONESHOT is not set +# CONFIG_NO_HZ is not set +# CONFIG_HIGH_RES_TIMERS is not set +CONFIG_GENERIC_CLOCKEVENTS_BUILD=y + +# +# CPU Frequency scaling +# +# CONFIG_CPU_FREQ is not set + +# +# DMA support +# +# CONFIG_SH_DMA is not set + +# +# Companion Chips +# + +# +# Additional SuperH Device Drivers +# +# CONFIG_HEARTBEAT is not set +# CONFIG_PUSH_SWITCH is not set + +# +# Kernel features +# +# CONFIG_HZ_100 is not set +CONFIG_HZ_250=y +# CONFIG_HZ_300 is not set +# CONFIG_HZ_1000 is not set +CONFIG_HZ=250 +# CONFIG_SCHED_HRTICK is not set +# CONFIG_KEXEC is not set +# CONFIG_CRASH_DUMP is not set +CONFIG_PREEMPT_NONE=y +# CONFIG_PREEMPT_VOLUNTARY is not set +# CONFIG_PREEMPT is not set +CONFIG_RCU_TRACE=y +CONFIG_GUSA=y + +# +# Boot options +# +CONFIG_ZERO_PAGE_OFFSET=0x00001000 +CONFIG_BOOT_LINK_OFFSET=0x00800000 +CONFIG_CMDLINE_BOOL=y +CONFIG_CMDLINE="console=ttySC0,115200 earlyprintk=serial ip=on" + +# +# Bus options +# +# CONFIG_ARCH_SUPPORTS_MSI is not set +# CONFIG_PCCARD is not set + +# +# Executable file formats +# +CONFIG_BINFMT_ELF=y +# CONFIG_BINFMT_MISC is not set + +# +# Networking +# +CONFIG_NET=y + +# +# Networking options +# +CONFIG_PACKET=y +# CONFIG_PACKET_MMAP is not set +CONFIG_UNIX=y +CONFIG_XFRM=y +# CONFIG_XFRM_USER is not set +# CONFIG_XFRM_SUB_POLICY is not set +# CONFIG_XFRM_MIGRATE is not set +# CONFIG_XFRM_STATISTICS is not set +# 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 is not set +# 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 is not set +# CONFIG_INET_AH is not set +# CONFIG_INET_ESP is not set +# CONFIG_INET_IPCOMP is not set +# CONFIG_INET_XFRM_TUNNEL is not set +# CONFIG_INET_TUNNEL is not set +CONFIG_INET_XFRM_MODE_TRANSPORT=y +CONFIG_INET_XFRM_MODE_TUNNEL=y +CONFIG_INET_XFRM_MODE_BEET=y +# CONFIG_INET_LRO is not set +CONFIG_INET_DIAG=y +CONFIG_INET_TCP_DIAG=y +# CONFIG_TCP_CONG_ADVANCED is not set +CONFIG_TCP_CONG_CUBIC=y +CONFIG_DEFAULT_TCP_CONG="cubic" +# CONFIG_TCP_MD5SIG is not set +# CONFIG_IPV6 is not set +# CONFIG_INET6_XFRM_TUNNEL is not set +# CONFIG_INET6_TUNNEL is not set +# CONFIG_NETWORK_SECMARK is not set +# CONFIG_NETFILTER is not set +# CONFIG_IP_DCCP is not set +# CONFIG_IP_SCTP is not set +# CONFIG_TIPC is not set +# CONFIG_ATM is not set +# CONFIG_BRIDGE is not set +# CONFIG_VLAN_8021Q is not set +# CONFIG_DECNET is not set +# CONFIG_LLC2 is not set +# CONFIG_IPX is not set +# CONFIG_ATALK is not set +# CONFIG_X25 is not set +# CONFIG_LAPB is not set +# CONFIG_ECONET is not set +# CONFIG_WAN_ROUTER is not set +# CONFIG_NET_SCHED is not set + +# +# Network testing +# +# CONFIG_NET_PKTGEN is not set +# CONFIG_HAMRADIO is not set +# CONFIG_CAN is not set +# CONFIG_IRDA is not set +# CONFIG_BT is not set +# CONFIG_AF_RXRPC is not set + +# +# Wireless +# +# CONFIG_CFG80211 is not set +CONFIG_WIRELESS_EXT=y +# CONFIG_MAC80211 is not set +# CONFIG_IEEE80211 is not set +# CONFIG_RFKILL is not set +# CONFIG_NET_9P is not set + +# +# Device Drivers +# + +# +# Generic Driver Options +# +CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" +CONFIG_STANDALONE=y +CONFIG_PREVENT_FIRMWARE_BUILD=y +CONFIG_FW_LOADER=m +# CONFIG_SYS_HYPERVISOR is not set +# CONFIG_CONNECTOR is not set +# CONFIG_MTD is not set +# CONFIG_PARPORT is not set +CONFIG_BLK_DEV=y +# CONFIG_BLK_DEV_COW_COMMON is not set +# CONFIG_BLK_DEV_LOOP is not set +# CONFIG_BLK_DEV_NBD is not set +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_COUNT=16 +CONFIG_BLK_DEV_RAM_SIZE=4096 +CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024 +# CONFIG_CDROM_PKTCDVD is not set +# CONFIG_ATA_OVER_ETH is not set +CONFIG_MISC_DEVICES=y +# CONFIG_EEPROM_93CX6 is not set +# CONFIG_IDE is not set + +# +# SCSI device support +# +# CONFIG_RAID_ATTRS is not set +CONFIG_SCSI=y +CONFIG_SCSI_DMA=y +# CONFIG_SCSI_TGT is not set +# CONFIG_SCSI_NETLINK is not set +CONFIG_SCSI_PROC_FS=y + +# +# SCSI support type (disk, tape, CD-ROM) +# +CONFIG_BLK_DEV_SD=y +# CONFIG_CHR_DEV_ST is not set +# CONFIG_CHR_DEV_OSST is not set +# CONFIG_BLK_DEV_SR is not set +# CONFIG_CHR_DEV_SG is not set +# CONFIG_CHR_DEV_SCH is not set + +# +# Some SCSI devices (e.g. CD jukebox) support multiple LUNs +# +# CONFIG_SCSI_MULTI_LUN is not set +# CONFIG_SCSI_CONSTANTS is not set +# CONFIG_SCSI_LOGGING is not set +# CONFIG_SCSI_SCAN_ASYNC is not set +CONFIG_SCSI_WAIT_SCAN=m + +# +# SCSI Transports +# +# CONFIG_SCSI_SPI_ATTRS is not set +# CONFIG_SCSI_FC_ATTRS is not set +# CONFIG_SCSI_ISCSI_ATTRS is not set +# CONFIG_SCSI_SAS_LIBSAS is not set +# CONFIG_SCSI_SRP_ATTRS is not set +CONFIG_SCSI_LOWLEVEL=y +# CONFIG_ISCSI_TCP is not set +# CONFIG_SCSI_DEBUG is not set +# CONFIG_ATA is not set +# CONFIG_MD is not set +CONFIG_NETDEVICES=y +# CONFIG_NETDEVICES_MULTIQUEUE is not set +# CONFIG_DUMMY is not set +# CONFIG_BONDING is not set +# CONFIG_MACVLAN is not set +# CONFIG_EQUALIZER is not set +# CONFIG_TUN is not set +# CONFIG_VETH is not set +# CONFIG_PHYLIB is not set +CONFIG_NET_ETHERNET=y +CONFIG_MII=y +# CONFIG_AX88796 is not set +# CONFIG_STNIC is not set +CONFIG_SMC91X=y +# CONFIG_IBM_NEW_EMAC_ZMII is not set +# CONFIG_IBM_NEW_EMAC_RGMII is not set +# CONFIG_IBM_NEW_EMAC_TAH is not set +# CONFIG_IBM_NEW_EMAC_EMAC4 is not set +# CONFIG_B44 is not set +# CONFIG_NETDEV_1000 is not set +# CONFIG_NETDEV_10000 is not set + +# +# Wireless LAN +# +# CONFIG_WLAN_PRE80211 is not set +# CONFIG_WLAN_80211 is not set +# CONFIG_WAN is not set +# CONFIG_PPP is not set +# CONFIG_SLIP is not set +# CONFIG_NETCONSOLE is not set +# CONFIG_NETPOLL is not set +# CONFIG_NET_POLL_CONTROLLER is not set +# CONFIG_ISDN is not set +# CONFIG_PHONE is not set + +# +# Input device support +# +CONFIG_INPUT=y +# CONFIG_INPUT_FF_MEMLESS is not set +# CONFIG_INPUT_POLLDEV is not set + +# +# Userland interfaces +# +# CONFIG_INPUT_MOUSEDEV is not set +# CONFIG_INPUT_JOYDEV is not set +# CONFIG_INPUT_EVDEV is not set +# CONFIG_INPUT_EVBUG is not set + +# +# Input Device Drivers +# +# CONFIG_INPUT_KEYBOARD is not set +# CONFIG_INPUT_MOUSE is not set +# CONFIG_INPUT_JOYSTICK is not set +# CONFIG_INPUT_TABLET is not set +# CONFIG_INPUT_TOUCHSCREEN is not set +# CONFIG_INPUT_MISC is not set + +# +# Hardware I/O ports +# +# CONFIG_SERIO is not set +# CONFIG_GAMEPORT is not set + +# +# Character devices +# +CONFIG_VT=y +CONFIG_VT_CONSOLE=y +CONFIG_HW_CONSOLE=y +CONFIG_VT_HW_CONSOLE_BINDING=y +# CONFIG_SERIAL_NONSTANDARD is not set + +# +# Serial drivers +# +# CONFIG_SERIAL_8250 is not set + +# +# Non-8250 serial port support +# +CONFIG_SERIAL_SH_SCI=y +CONFIG_SERIAL_SH_SCI_NR_UARTS=3 +CONFIG_SERIAL_SH_SCI_CONSOLE=y +CONFIG_SERIAL_CORE=y +CONFIG_SERIAL_CORE_CONSOLE=y +CONFIG_UNIX98_PTYS=y +CONFIG_LEGACY_PTYS=y +CONFIG_LEGACY_PTY_COUNT=256 +# CONFIG_IPMI_HANDLER is not set +CONFIG_HW_RANDOM=y +# CONFIG_R3964 is not set +# CONFIG_RAW_DRIVER is not set +# CONFIG_TCG_TPM is not set +# CONFIG_I2C is not set + +# +# SPI support +# +# CONFIG_SPI is not set +# CONFIG_SPI_MASTER is not set +# CONFIG_W1 is not set +# CONFIG_POWER_SUPPLY is not set +# CONFIG_HWMON is not set +# CONFIG_WATCHDOG is not set + +# +# Sonics Silicon Backplane +# +CONFIG_SSB_POSSIBLE=y +# CONFIG_SSB is not set + +# +# Multifunction device drivers +# +# CONFIG_MFD_SM501 is not set + +# +# Multimedia devices +# +# CONFIG_VIDEO_DEV is not set +# CONFIG_DVB_CORE is not set +# CONFIG_DAB is not set + +# +# Graphics support +# +# CONFIG_VGASTATE is not set +# CONFIG_VIDEO_OUTPUT_CONTROL is not set +# CONFIG_FB is not set +# CONFIG_BACKLIGHT_LCD_SUPPORT is not set + +# +# Display device support +# +# CONFIG_DISPLAY_SUPPORT is not set + +# +# Console display driver support +# +CONFIG_DUMMY_CONSOLE=y + +# +# Sound +# +# CONFIG_SOUND is not set +CONFIG_HID_SUPPORT=y +CONFIG_HID=y +# CONFIG_HID_DEBUG is not set +# CONFIG_HIDRAW is not set +CONFIG_USB_SUPPORT=y +CONFIG_USB_ARCH_HAS_HCD=y +# CONFIG_USB_ARCH_HAS_OHCI is not set +# CONFIG_USB_ARCH_HAS_EHCI is not set +# CONFIG_USB is not set + +# +# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support' +# +CONFIG_USB_GADGET=y +# CONFIG_USB_GADGET_DEBUG_FILES is not set +# CONFIG_USB_GADGET_DEBUG_FS is not set +CONFIG_USB_GADGET_SELECTED=y +# CONFIG_USB_GADGET_AMD5536UDC is not set +# CONFIG_USB_GADGET_ATMEL_USBA is not set +# CONFIG_USB_GADGET_FSL_USB2 is not set +# CONFIG_USB_GADGET_NET2280 is not set +# CONFIG_USB_GADGET_PXA2XX is not set +CONFIG_USB_GADGET_M66592=y +CONFIG_USB_M66592=y +CONFIG_SUPERH_BUILT_IN_M66592=y +# CONFIG_USB_GADGET_GOKU is not set +# CONFIG_USB_GADGET_LH7A40X is not set +# CONFIG_USB_GADGET_OMAP is not set +# CONFIG_USB_GADGET_S3C2410 is not set +# CONFIG_USB_GADGET_AT91 is not set +# CONFIG_USB_GADGET_DUMMY_HCD is not set +CONFIG_USB_GADGET_DUALSPEED=y +# CONFIG_USB_ZERO is not set +# CONFIG_USB_ETH is not set +# CONFIG_USB_GADGETFS is not set +# CONFIG_USB_FILE_STORAGE is not set +CONFIG_USB_G_SERIAL=y +# CONFIG_USB_MIDI_GADGET is not set +# CONFIG_USB_G_PRINTER is not set +# CONFIG_MMC is not set +# CONFIG_NEW_LEDS is not set +CONFIG_RTC_LIB=y +CONFIG_RTC_CLASS=y +CONFIG_RTC_HCTOSYS=y +CONFIG_RTC_HCTOSYS_DEVICE="rtc0" +# CONFIG_RTC_DEBUG is not set + +# +# RTC interfaces +# +CONFIG_RTC_INTF_SYSFS=y +CONFIG_RTC_INTF_PROC=y +CONFIG_RTC_INTF_DEV=y +# CONFIG_RTC_INTF_DEV_UIE_EMUL is not set +# CONFIG_RTC_DRV_TEST is not set + +# +# SPI RTC drivers +# + +# +# Platform RTC drivers +# +# CONFIG_RTC_DRV_DS1553 is not set +# CONFIG_RTC_DRV_STK17TA8 is not set +# CONFIG_RTC_DRV_DS1742 is not set +# CONFIG_RTC_DRV_M48T86 is not set +# CONFIG_RTC_DRV_M48T59 is not set +# CONFIG_RTC_DRV_V3020 is not set + +# +# on-CPU RTC drivers +# +CONFIG_RTC_DRV_SH=y + +# +# Userspace I/O +# +# CONFIG_UIO is not set + +# +# File systems +# +# CONFIG_EXT2_FS is not set +# CONFIG_EXT3_FS is not set +# CONFIG_EXT4DEV_FS is not set +# CONFIG_REISERFS_FS is not set +# CONFIG_JFS_FS is not set +# CONFIG_FS_POSIX_ACL is not set +# CONFIG_XFS_FS is not set +# CONFIG_GFS2_FS is not set +# CONFIG_OCFS2_FS is not set +# CONFIG_MINIX_FS is not set +# CONFIG_ROMFS_FS is not set +# CONFIG_INOTIFY is not set +# CONFIG_QUOTA is not set +# CONFIG_DNOTIFY is not set +# CONFIG_AUTOFS_FS is not set +# CONFIG_AUTOFS4_FS is not set +# CONFIG_FUSE_FS is not set + +# +# CD-ROM/DVD Filesystems +# +# CONFIG_ISO9660_FS is not set +# CONFIG_UDF_FS is not set + +# +# DOS/FAT/NT Filesystems +# +# CONFIG_MSDOS_FS is not set +# CONFIG_VFAT_FS is not set +# CONFIG_NTFS_FS is not set + +# +# Pseudo filesystems +# +CONFIG_PROC_FS=y +CONFIG_PROC_KCORE=y +CONFIG_PROC_SYSCTL=y +CONFIG_SYSFS=y +CONFIG_TMPFS=y +# CONFIG_TMPFS_POSIX_ACL is not set +# CONFIG_HUGETLBFS is not set +# CONFIG_HUGETLB_PAGE is not set +# CONFIG_CONFIGFS_FS is not set + +# +# Miscellaneous filesystems +# +# CONFIG_ADFS_FS is not set +# CONFIG_AFFS_FS is not set +# CONFIG_HFS_FS is not set +# CONFIG_HFSPLUS_FS is not set +# CONFIG_BEFS_FS is not set +# CONFIG_BFS_FS is not set +# CONFIG_EFS_FS is not set +# CONFIG_CRAMFS is not set +# CONFIG_VXFS_FS is not set +# CONFIG_HPFS_FS is not set +# CONFIG_QNX4FS_FS is not set +# CONFIG_SYSV_FS is not set +# CONFIG_UFS_FS is not set +# CONFIG_NETWORK_FILESYSTEMS is not set + +# +# Partition Types +# +# CONFIG_PARTITION_ADVANCED is not set +CONFIG_MSDOS_PARTITION=y +# CONFIG_NLS is not set +# CONFIG_DLM is not set + +# +# Kernel hacking +# +CONFIG_TRACE_IRQFLAGS_SUPPORT=y +# CONFIG_PRINTK_TIME is not set +CONFIG_ENABLE_WARN_DEPRECATED=y +CONFIG_ENABLE_MUST_CHECK=y +# CONFIG_MAGIC_SYSRQ is not set +# CONFIG_UNUSED_SYMBOLS is not set +CONFIG_DEBUG_FS=y +# CONFIG_HEADERS_CHECK is not set +# CONFIG_DEBUG_KERNEL is not set +# CONFIG_DEBUG_BUGVERBOSE is not set +# CONFIG_SAMPLES is not set +# CONFIG_SH_STANDARD_BIOS is not set +CONFIG_EARLY_SCIF_CONSOLE=y +CONFIG_EARLY_SCIF_CONSOLE_PORT=0xffe00000 +CONFIG_EARLY_PRINTK=y +# CONFIG_SH_KGDB is not set + +# +# Security options +# +# CONFIG_KEYS is not set +# CONFIG_SECURITY is not set +# CONFIG_SECURITY_FILE_CAPABILITIES is not set +CONFIG_CRYPTO=y +# CONFIG_CRYPTO_SEQIV is not set +# CONFIG_CRYPTO_MANAGER is not set +# CONFIG_CRYPTO_HMAC is not set +# CONFIG_CRYPTO_XCBC is not set +# CONFIG_CRYPTO_NULL is not set +# CONFIG_CRYPTO_MD4 is not set +# CONFIG_CRYPTO_MD5 is not set +# CONFIG_CRYPTO_SHA1 is not set +# CONFIG_CRYPTO_SHA256 is not set +# CONFIG_CRYPTO_SHA512 is not set +# CONFIG_CRYPTO_WP512 is not set +# CONFIG_CRYPTO_TGR192 is not set +# CONFIG_CRYPTO_GF128MUL is not set +# CONFIG_CRYPTO_ECB is not set +# CONFIG_CRYPTO_CBC is not set +# CONFIG_CRYPTO_PCBC is not set +# CONFIG_CRYPTO_LRW is not set +# CONFIG_CRYPTO_XTS is not set +# CONFIG_CRYPTO_CTR is not set +# CONFIG_CRYPTO_GCM is not set +# CONFIG_CRYPTO_CCM is not set +# CONFIG_CRYPTO_CRYPTD is not set +# CONFIG_CRYPTO_DES is not set +# CONFIG_CRYPTO_FCRYPT is not set +# CONFIG_CRYPTO_BLOWFISH is not set +# CONFIG_CRYPTO_TWOFISH is not set +# CONFIG_CRYPTO_SERPENT is not set +# CONFIG_CRYPTO_AES is not set +# CONFIG_CRYPTO_CAST5 is not set +# CONFIG_CRYPTO_CAST6 is not set +# CONFIG_CRYPTO_TEA is not set +# CONFIG_CRYPTO_ARC4 is not set +# CONFIG_CRYPTO_KHAZAD is not set +# CONFIG_CRYPTO_ANUBIS is not set +# CONFIG_CRYPTO_SEED is not set +# CONFIG_CRYPTO_SALSA20 is not set +# CONFIG_CRYPTO_DEFLATE is not set +# CONFIG_CRYPTO_MICHAEL_MIC is not set +# CONFIG_CRYPTO_CRC32C is not set +# CONFIG_CRYPTO_CAMELLIA is not set +# CONFIG_CRYPTO_TEST is not set +# CONFIG_CRYPTO_AUTHENC is not set +# CONFIG_CRYPTO_LZO is not set +CONFIG_CRYPTO_HW=y + +# +# Library routines +# +CONFIG_BITREVERSE=y +# CONFIG_CRC_CCITT is not set +# CONFIG_CRC16 is not set +# CONFIG_CRC_ITU_T is not set +CONFIG_CRC32=y +# CONFIG_CRC7 is not set +# CONFIG_LIBCRC32C is not set +CONFIG_PLIST=y +CONFIG_HAS_IOMEM=y +CONFIG_HAS_IOPORT=y +CONFIG_HAS_DMA=y diff --git a/arch/sh/configs/rts7751r2d1_defconfig b/arch/sh/configs/rts7751r2d1_defconfig index 2dc754e5b73..3a915fd436d 100644 --- a/arch/sh/configs/rts7751r2d1_defconfig +++ b/arch/sh/configs/rts7751r2d1_defconfig @@ -1,9 +1,10 @@ # # Automatically generated make config: don't edit -# Linux kernel version: 2.6.23-rc2 -# Tue Aug 14 18:04:44 2007 +# Linux kernel version: 2.6.24 +# Thu Feb 7 16:25:55 2008 # CONFIG_SUPERH=y +CONFIG_SUPERH32=y CONFIG_RWSEM_GENERIC_SPINLOCK=y CONFIG_GENERIC_BUG=y CONFIG_GENERIC_FIND_NEXT_BIT=y @@ -36,9 +37,14 @@ CONFIG_SYSVIPC_SYSCTL=y # CONFIG_BSD_PROCESS_ACCT is not set # CONFIG_TASKSTATS is not set # CONFIG_USER_NS is not set +# CONFIG_PID_NS is not set # CONFIG_AUDIT is not set # CONFIG_IKCONFIG is not set CONFIG_LOG_BUF_SHIFT=14 +# CONFIG_CGROUPS is not set +CONFIG_FAIR_GROUP_SCHED=y +CONFIG_FAIR_USER_SCHED=y +# CONFIG_FAIR_CGROUP_SCHED is not set CONFIG_SYSFS_DEPRECATED=y # CONFIG_RELAY is not set # CONFIG_BLK_DEV_INITRD is not set @@ -53,6 +59,7 @@ CONFIG_HOTPLUG=y CONFIG_PRINTK=y CONFIG_BUG=y CONFIG_ELF_CORE=y +CONFIG_COMPAT_BRK=y CONFIG_BASE_FULL=y CONFIG_FUTEX=y CONFIG_ANON_INODES=y @@ -65,6 +72,13 @@ CONFIG_VM_EVENT_COUNTERS=y CONFIG_SLAB=y # CONFIG_SLUB is not set # CONFIG_SLOB is not set +CONFIG_PROFILING=y +# CONFIG_MARKERS is not set +CONFIG_OPROFILE=y +CONFIG_HAVE_OPROFILE=y +# CONFIG_HAVE_KPROBES is not set +CONFIG_PROC_PAGE_MONITOR=y +CONFIG_SLABINFO=y CONFIG_RT_MUTEXES=y # CONFIG_TINY_SHMEM is not set CONFIG_BASE_SMALL=0 @@ -91,13 +105,17 @@ CONFIG_DEFAULT_AS=y # CONFIG_DEFAULT_CFQ is not set # CONFIG_DEFAULT_NOOP is not set CONFIG_DEFAULT_IOSCHED="anticipatory" +CONFIG_CLASSIC_RCU=y +# CONFIG_PREEMPT_RCU is not set # # System type # CONFIG_CPU_SH4=y # CONFIG_CPU_SUBTYPE_SH7619 is not set +# CONFIG_CPU_SUBTYPE_SH7203 is not set # CONFIG_CPU_SUBTYPE_SH7206 is not set +# CONFIG_CPU_SUBTYPE_SH7263 is not set # CONFIG_CPU_SUBTYPE_SH7705 is not set # CONFIG_CPU_SUBTYPE_SH7706 is not set # CONFIG_CPU_SUBTYPE_SH7707 is not set @@ -105,6 +123,8 @@ CONFIG_CPU_SH4=y # CONFIG_CPU_SUBTYPE_SH7709 is not set # CONFIG_CPU_SUBTYPE_SH7710 is not set # CONFIG_CPU_SUBTYPE_SH7712 is not set +# CONFIG_CPU_SUBTYPE_SH7720 is not set +# CONFIG_CPU_SUBTYPE_SH7721 is not set # CONFIG_CPU_SUBTYPE_SH7750 is not set # CONFIG_CPU_SUBTYPE_SH7091 is not set # CONFIG_CPU_SUBTYPE_SH7750R is not set @@ -113,14 +133,15 @@ CONFIG_CPU_SH4=y CONFIG_CPU_SUBTYPE_SH7751R=y # CONFIG_CPU_SUBTYPE_SH7760 is not set # CONFIG_CPU_SUBTYPE_SH4_202 is not set -# CONFIG_CPU_SUBTYPE_ST40STB1 is not set -# CONFIG_CPU_SUBTYPE_ST40GX1 is not set +# CONFIG_CPU_SUBTYPE_SH7763 is not set # CONFIG_CPU_SUBTYPE_SH7770 is not set # CONFIG_CPU_SUBTYPE_SH7780 is not set # CONFIG_CPU_SUBTYPE_SH7785 is not set # CONFIG_CPU_SUBTYPE_SHX3 is not set # CONFIG_CPU_SUBTYPE_SH7343 is not set # CONFIG_CPU_SUBTYPE_SH7722 is not set +# CONFIG_CPU_SUBTYPE_SH5_101 is not set +# CONFIG_CPU_SUBTYPE_SH5_103 is not set # # Memory management options @@ -130,6 +151,7 @@ CONFIG_MMU=y CONFIG_PAGE_OFFSET=0x80000000 CONFIG_MEMORY_START=0x0c000000 CONFIG_MEMORY_SIZE=0x04000000 +CONFIG_29BIT=y CONFIG_VSYSCALL=y CONFIG_ARCH_FLATMEM_ENABLE=y CONFIG_ARCH_SPARSEMEM_ENABLE=y @@ -147,6 +169,7 @@ CONFIG_FLATMEM_MANUAL=y CONFIG_FLATMEM=y CONFIG_FLAT_NODE_MEM_MAP=y CONFIG_SPARSEMEM_STATIC=y +# CONFIG_SPARSEMEM_VMEMMAP_ENABLE is not set CONFIG_SPLIT_PTLOCK_CPUS=4 # CONFIG_RESOURCES_64BIT is not set CONFIG_ZONE_DMA_FLAG=0 @@ -168,23 +191,22 @@ CONFIG_CPU_LITTLE_ENDIAN=y CONFIG_SH_FPU=y # CONFIG_SH_STORE_QUEUES is not set CONFIG_CPU_HAS_INTEVT=y -CONFIG_CPU_HAS_INTC_IRQ=y CONFIG_CPU_HAS_SR_RB=y CONFIG_CPU_HAS_PTEA=y +CONFIG_CPU_HAS_FPU=y # # Board support # # CONFIG_SH_7751_SYSTEMH is not set # CONFIG_SH_SECUREEDGE5410 is not set -# CONFIG_SH_HS7751RVOIP is not set CONFIG_SH_RTS7751R2D=y # CONFIG_SH_LANDISK is not set # CONFIG_SH_TITAN is not set # CONFIG_SH_LBOX_RE2 is not set # -# RTS7751R2D options +# RTS7751R2D Board Revision # # CONFIG_RTS7751R2D_PLUS is not set CONFIG_RTS7751R2D_1=y @@ -198,6 +220,7 @@ CONFIG_SH_PCLK_FREQ=60000000 # CONFIG_TICK_ONESHOT is not set # CONFIG_NO_HZ is not set # CONFIG_HIGH_RES_TIMERS is not set +CONFIG_GENERIC_CLOCKEVENTS_BUILD=y # # CPU Frequency scaling @@ -227,11 +250,15 @@ CONFIG_HZ_250=y # CONFIG_HZ_300 is not set # CONFIG_HZ_1000 is not set CONFIG_HZ=250 +# CONFIG_SCHED_HRTICK is not set # CONFIG_KEXEC is not set # CONFIG_CRASH_DUMP is not set CONFIG_PREEMPT_NONE=y # CONFIG_PREEMPT_VOLUNTARY is not set # CONFIG_PREEMPT is not set +CONFIG_RCU_TRACE=y +CONFIG_GUSA=y +# CONFIG_GUSA_RB is not set # # Boot options @@ -250,10 +277,7 @@ CONFIG_SH_PCIDMA_NONCOHERENT=y CONFIG_PCI_AUTO=y CONFIG_PCI_AUTO_UPDATE_RESOURCES=y # CONFIG_ARCH_SUPPORTS_MSI is not set - -# -# PCCARD (PCMCIA/CardBus) support -# +CONFIG_PCI_LEGACY=y # CONFIG_PCCARD is not set CONFIG_HOTPLUG_PCI=y # CONFIG_HOTPLUG_PCI_FAKE is not set @@ -281,6 +305,7 @@ CONFIG_XFRM=y # CONFIG_XFRM_USER is not set # CONFIG_XFRM_SUB_POLICY is not set # CONFIG_XFRM_MIGRATE is not set +# CONFIG_XFRM_STATISTICS is not set # CONFIG_NET_KEY is not set CONFIG_INET=y # CONFIG_IP_MULTICAST is not set @@ -299,6 +324,7 @@ CONFIG_IP_FIB_HASH=y CONFIG_INET_XFRM_MODE_TRANSPORT=y CONFIG_INET_XFRM_MODE_TUNNEL=y CONFIG_INET_XFRM_MODE_BEET=y +# CONFIG_INET_LRO is not set CONFIG_INET_DIAG=y CONFIG_INET_TCP_DIAG=y # CONFIG_TCP_CONG_ADVANCED is not set @@ -324,10 +350,6 @@ CONFIG_DEFAULT_TCP_CONG="cubic" # CONFIG_LAPB is not set # CONFIG_ECONET is not set # CONFIG_WAN_ROUTER is not set - -# -# QoS and/or fair queueing -# # CONFIG_NET_SCHED is not set # @@ -335,6 +357,7 @@ CONFIG_DEFAULT_TCP_CONG="cubic" # # CONFIG_NET_PKTGEN is not set # CONFIG_HAMRADIO is not set +# CONFIG_CAN is not set # CONFIG_IRDA is not set # CONFIG_BT is not set # CONFIG_AF_RXRPC is not set @@ -356,6 +379,7 @@ CONFIG_WIRELESS_EXT=y # # Generic Driver Options # +CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" CONFIG_STANDALONE=y CONFIG_PREVENT_FIRMWARE_BUILD=y CONFIG_FW_LOADER=m @@ -371,6 +395,7 @@ CONFIG_BLK_DEV=y # CONFIG_BLK_DEV_LOOP is not set # CONFIG_BLK_DEV_NBD is not set # CONFIG_BLK_DEV_SX8 is not set +# CONFIG_BLK_DEV_UB is not set CONFIG_BLK_DEV_RAM=y CONFIG_BLK_DEV_RAM_COUNT=16 CONFIG_BLK_DEV_RAM_SIZE=4096 @@ -420,6 +445,7 @@ CONFIG_SCSI_WAIT_SCAN=m # CONFIG_SCSI_FC_ATTRS is not set # CONFIG_SCSI_ISCSI_ATTRS is not set # CONFIG_SCSI_SAS_LIBSAS is not set +# CONFIG_SCSI_SRP_ATTRS is not set CONFIG_SCSI_LOWLEVEL=y # CONFIG_ISCSI_TCP is not set # CONFIG_BLK_DEV_3W_XXXX_RAID is not set @@ -493,7 +519,9 @@ CONFIG_ATA=y # CONFIG_PATA_MPIIX is not set # CONFIG_PATA_OLDPIIX is not set # CONFIG_PATA_NETCELL is not set +# CONFIG_PATA_NINJA32 is not set # CONFIG_PATA_NS87410 is not set +# CONFIG_PATA_NS87415 is not set # CONFIG_PATA_OPTI is not set # CONFIG_PATA_OPTIDMA is not set # CONFIG_PATA_PDC_OLD is not set @@ -508,14 +536,7 @@ CONFIG_ATA=y # CONFIG_PATA_WINBOND is not set CONFIG_PATA_PLATFORM=y # CONFIG_MD is not set - -# -# Fusion MPT device support -# # CONFIG_FUSION is not set -# CONFIG_FUSION_SPI is not set -# CONFIG_FUSION_FC is not set -# CONFIG_FUSION_SAS is not set # # IEEE 1394 (FireWire) support @@ -530,25 +551,31 @@ CONFIG_NETDEVICES=y # CONFIG_MACVLAN is not set # CONFIG_EQUALIZER is not set # CONFIG_TUN is not set +# CONFIG_VETH is not set # CONFIG_ARCNET is not set # CONFIG_PHYLIB is not set CONFIG_NET_ETHERNET=y CONFIG_MII=y +# CONFIG_AX88796 is not set # CONFIG_STNIC is not set # CONFIG_HAPPYMEAL is not set # CONFIG_SUNGEM is not set # CONFIG_CASSINI is not set # CONFIG_NET_VENDOR_3COM is not set # CONFIG_SMC91X is not set +# CONFIG_ENC28J60 is not set # CONFIG_NET_TULIP is not set # CONFIG_HP100 is not set +# CONFIG_IBM_NEW_EMAC_ZMII is not set +# CONFIG_IBM_NEW_EMAC_RGMII is not set +# CONFIG_IBM_NEW_EMAC_TAH is not set +# CONFIG_IBM_NEW_EMAC_EMAC4 is not set CONFIG_NET_PCI=y # CONFIG_PCNET32 is not set # CONFIG_AMD8111_ETH is not set # CONFIG_ADAPTEC_STARFIRE is not set # CONFIG_B44 is not set # CONFIG_FORCEDETH is not set -# CONFIG_DGRS is not set # CONFIG_EEPRO100 is not set # CONFIG_E100 is not set # CONFIG_FEALNX is not set @@ -560,6 +587,7 @@ CONFIG_8139TOO=y # CONFIG_8139TOO_TUNE_TWISTER is not set # CONFIG_8139TOO_8129 is not set # CONFIG_8139_OLD_RX_RESET is not set +# CONFIG_R6040 is not set # CONFIG_SIS900 is not set # CONFIG_EPIC100 is not set # CONFIG_SUNDANCE is not set @@ -570,6 +598,10 @@ CONFIG_NETDEV_1000=y # CONFIG_ACENIC is not set # CONFIG_DL2K is not set # CONFIG_E1000 is not set +# CONFIG_E1000E is not set +# CONFIG_E1000E_ENABLED is not set +# CONFIG_IP1000 is not set +# CONFIG_IGB is not set # CONFIG_NS83820 is not set # CONFIG_HAMACHI is not set # CONFIG_YELLOWFIN is not set @@ -577,6 +609,7 @@ CONFIG_NETDEV_1000=y # CONFIG_SIS190 is not set # CONFIG_SKGE is not set # CONFIG_SKY2 is not set +# CONFIG_SK98LIN is not set # CONFIG_VIA_VELOCITY is not set # CONFIG_TIGON3 is not set # CONFIG_BNX2 is not set @@ -585,11 +618,15 @@ CONFIG_NETDEV_1000=y CONFIG_NETDEV_10000=y # CONFIG_CHELSIO_T1 is not set # CONFIG_CHELSIO_T3 is not set +# CONFIG_IXGBE is not set # CONFIG_IXGB is not set # CONFIG_S2IO is not set # CONFIG_MYRI10GE is not set # CONFIG_NETXEN_NIC is not set +# CONFIG_NIU is not set # CONFIG_MLX4_CORE is not set +# CONFIG_TEHUTI is not set +# CONFIG_BNX2X is not set # CONFIG_TR is not set # @@ -597,13 +634,21 @@ CONFIG_NETDEV_10000=y # # CONFIG_WLAN_PRE80211 is not set # CONFIG_WLAN_80211 is not set + +# +# USB Network Adapters +# +# CONFIG_USB_CATC is not set +# CONFIG_USB_KAWETH is not set +# CONFIG_USB_PEGASUS is not set +# CONFIG_USB_RTL8150 is not set +# CONFIG_USB_USBNET is not set # CONFIG_WAN is not set # CONFIG_FDDI is not set # CONFIG_HIPPI is not set # CONFIG_PPP is not set # CONFIG_SLIP is not set # CONFIG_NET_FC 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 @@ -622,7 +667,6 @@ CONFIG_INPUT=y # # CONFIG_INPUT_MOUSEDEV is not set # CONFIG_INPUT_JOYDEV is not set -# CONFIG_INPUT_TSDEV is not set # CONFIG_INPUT_EVDEV is not set # CONFIG_INPUT_EVBUG is not set @@ -650,6 +694,7 @@ CONFIG_VT_CONSOLE=y CONFIG_HW_CONSOLE=y CONFIG_VT_HW_CONSOLE_BINDING=y # CONFIG_SERIAL_NONSTANDARD is not set +# CONFIG_NOZOMI is not set # # Serial drivers @@ -674,11 +719,9 @@ CONFIG_UNIX98_PTYS=y CONFIG_LEGACY_PTYS=y CONFIG_LEGACY_PTY_COUNT=256 # CONFIG_IPMI_HANDLER is not set -# CONFIG_WATCHDOG is not set CONFIG_HW_RANDOM=y # CONFIG_R3964 is not set # CONFIG_APPLICOM is not set -# CONFIG_DRM is not set # CONFIG_RAW_DRIVER is not set # CONFIG_TCG_TPM is not set CONFIG_DEVPORT=y @@ -687,16 +730,30 @@ CONFIG_DEVPORT=y # # SPI support # -# CONFIG_SPI is not set -# CONFIG_SPI_MASTER is not set +CONFIG_SPI=y +CONFIG_SPI_MASTER=y + +# +# SPI Master Controller Drivers +# +CONFIG_SPI_BITBANG=y +CONFIG_SPI_SH_SCI=y + +# +# SPI Protocol Masters +# +# CONFIG_SPI_AT25 is not set +# CONFIG_SPI_SPIDEV is not set +# CONFIG_SPI_TLE62X0 is not set # CONFIG_W1 is not set # CONFIG_POWER_SUPPLY is not set CONFIG_HWMON=y # CONFIG_HWMON_VID is not set -# CONFIG_SENSORS_ABITUGURU is not set -# CONFIG_SENSORS_ABITUGURU3 is not set +# CONFIG_SENSORS_I5K_AMB is not set # CONFIG_SENSORS_F71805F is not set +# CONFIG_SENSORS_F71882FG is not set # CONFIG_SENSORS_IT87 is not set +# CONFIG_SENSORS_LM70 is not set # CONFIG_SENSORS_PC87360 is not set # CONFIG_SENSORS_PC87427 is not set # CONFIG_SENSORS_SIS5595 is not set @@ -708,6 +765,13 @@ CONFIG_HWMON=y # CONFIG_SENSORS_W83627HF is not set # CONFIG_SENSORS_W83627EHF is not set # CONFIG_HWMON_DEBUG_CHIP is not set +# CONFIG_WATCHDOG is not set + +# +# Sonics Silicon Backplane +# +CONFIG_SSB_POSSIBLE=y +# CONFIG_SSB is not set # # Multifunction device drivers @@ -720,16 +784,12 @@ CONFIG_MFD_SM501=y # CONFIG_VIDEO_DEV is not set # CONFIG_DVB_CORE is not set CONFIG_DAB=y +# CONFIG_USB_DABUSB is not set # # Graphics support # -# CONFIG_BACKLIGHT_LCD_SUPPORT is not set - -# -# Display device support -# -# CONFIG_DISPLAY_SUPPORT is not set +# CONFIG_DRM is not set # CONFIG_VGASTATE is not set CONFIG_VIDEO_OUTPUT_CONTROL=m CONFIG_FB=y @@ -738,6 +798,7 @@ CONFIG_FB=y CONFIG_FB_CFB_FILLRECT=y CONFIG_FB_CFB_COPYAREA=y CONFIG_FB_CFB_IMAGEBLIT=y +# CONFIG_FB_CFB_REV_PIXELS_IN_BYTE is not set # CONFIG_FB_SYS_FILLRECT is not set # CONFIG_FB_SYS_COPYAREA is not set # CONFIG_FB_SYS_IMAGEBLIT is not set @@ -777,6 +838,12 @@ CONFIG_FB_DEFERRED_IO=y # CONFIG_FB_PM3 is not set CONFIG_FB_SM501=y # CONFIG_FB_VIRTUAL is not set +# CONFIG_BACKLIGHT_LCD_SUPPORT is not set + +# +# Display device support +# +# CONFIG_DISPLAY_SUPPORT is not set # # Console display driver support @@ -844,6 +911,7 @@ CONFIG_SND_AC97_CODEC=m # CONFIG_SND_BT87X is not set # CONFIG_SND_CA0106 is not set # CONFIG_SND_CMIPCI is not set +# CONFIG_SND_OXYGEN is not set # CONFIG_SND_CS4281 is not set # CONFIG_SND_CS46XX is not set # CONFIG_SND_DARLA20 is not set @@ -868,6 +936,7 @@ CONFIG_SND_AC97_CODEC=m # CONFIG_SND_HDA_INTEL is not set # CONFIG_SND_HDSP is not set # CONFIG_SND_HDSPM is not set +# CONFIG_SND_HIFIER is not set # CONFIG_SND_ICE1712 is not set # CONFIG_SND_ICE1724 is not set # CONFIG_SND_INTEL8X0 is not set @@ -885,16 +954,27 @@ CONFIG_SND_AC97_CODEC=m # CONFIG_SND_TRIDENT is not set # CONFIG_SND_VIA82XX is not set # CONFIG_SND_VIA82XX_MODEM is not set +# CONFIG_SND_VIRTUOSO is not set # CONFIG_SND_VX222 is not set CONFIG_SND_YMFPCI=m CONFIG_SND_YMFPCI_FIRMWARE_IN_KERNEL=y # CONFIG_SND_AC97_POWER_SAVE is not set # +# SPI devices +# + +# # SUPERH devices # # +# USB devices +# +# CONFIG_SND_USB_AUDIO is not set +# CONFIG_SND_USB_CAIAQ is not set + +# # System on Chip audio support # # CONFIG_SND_SOC is not set @@ -904,6 +984,10 @@ CONFIG_SND_YMFPCI_FIRMWARE_IN_KERNEL=y # # +# ALSA SoC audio for Freescale SOCs +# + +# # Open Sound System # CONFIG_SOUND_PRIME=m @@ -914,19 +998,104 @@ CONFIG_AC97_BUS=m CONFIG_HID_SUPPORT=y CONFIG_HID=y # CONFIG_HID_DEBUG is not set +# CONFIG_HIDRAW is not set + +# +# USB Input Devices +# +CONFIG_USB_HID=y +# CONFIG_USB_HIDINPUT_POWERBOOK is not set +# CONFIG_HID_FF is not set +# CONFIG_USB_HIDDEV is not set CONFIG_USB_SUPPORT=y CONFIG_USB_ARCH_HAS_HCD=y CONFIG_USB_ARCH_HAS_OHCI=y CONFIG_USB_ARCH_HAS_EHCI=y -# CONFIG_USB is not set +CONFIG_USB=y +# CONFIG_USB_DEBUG is not set +CONFIG_USB_ANNOUNCE_NEW_DEVICES=y + +# +# Miscellaneous USB options +# +# CONFIG_USB_DEVICEFS is not set +CONFIG_USB_DEVICE_CLASS=y +# CONFIG_USB_DYNAMIC_MINORS is not set +# CONFIG_USB_OTG is not set + +# +# USB Host Controller Drivers +# +# CONFIG_USB_EHCI_HCD is not set +# CONFIG_USB_ISP116X_HCD is not set +CONFIG_USB_OHCI_HCD=y +# CONFIG_USB_OHCI_BIG_ENDIAN_DESC is not set +# CONFIG_USB_OHCI_BIG_ENDIAN_MMIO is not set +CONFIG_USB_OHCI_LITTLE_ENDIAN=y +# CONFIG_USB_UHCI_HCD is not set +# CONFIG_USB_SL811_HCD is not set +# CONFIG_USB_R8A66597_HCD is not set + +# +# USB Device Class drivers +# +# CONFIG_USB_ACM is not set +# CONFIG_USB_PRINTER is not set # # NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support' # # -# USB Gadget Support +# may also be needed; see USB_STORAGE Help for more information +# +CONFIG_USB_STORAGE=y +# CONFIG_USB_STORAGE_DEBUG is not set +# CONFIG_USB_STORAGE_DATAFAB is not set +# CONFIG_USB_STORAGE_FREECOM is not set +# CONFIG_USB_STORAGE_ISD200 is not set +# CONFIG_USB_STORAGE_DPCM is not set +# CONFIG_USB_STORAGE_USBAT is not set +# CONFIG_USB_STORAGE_SDDR09 is not set +# CONFIG_USB_STORAGE_SDDR55 is not set +# CONFIG_USB_STORAGE_JUMPSHOT is not set +# CONFIG_USB_STORAGE_ALAUDA is not set +# CONFIG_USB_STORAGE_KARMA is not set +CONFIG_USB_LIBUSUAL=y + +# +# USB Imaging devices +# +# CONFIG_USB_MDC800 is not set +# CONFIG_USB_MICROTEK is not set +# CONFIG_USB_MON is not set + +# +# USB port drivers +# +# CONFIG_USB_SERIAL is not set + +# +# USB Miscellaneous drivers # +# CONFIG_USB_EMI62 is not set +# CONFIG_USB_EMI26 is not set +# CONFIG_USB_ADUTUX is not set +# CONFIG_USB_AUERSWALD is not set +# CONFIG_USB_RIO500 is not set +# CONFIG_USB_LEGOTOWER is not set +# CONFIG_USB_LCD is not set +# CONFIG_USB_BERRY_CHARGE is not set +# CONFIG_USB_LED is not set +# CONFIG_USB_CYPRESS_CY7C63 is not set +# CONFIG_USB_CYTHERM is not set +# CONFIG_USB_PHIDGET is not set +# CONFIG_USB_IDMOUSE is not set +# CONFIG_USB_FTDI_ELAN is not set +# CONFIG_USB_APPLEDISPLAY is not set +# CONFIG_USB_LD is not set +# CONFIG_USB_TRANCEVIBRATOR is not set +# CONFIG_USB_IOWARRIOR is not set # CONFIG_USB_GADGET is not set # CONFIG_MMC is not set # CONFIG_NEW_LEDS is not set @@ -949,13 +1118,17 @@ CONFIG_RTC_INTF_DEV=y # # SPI RTC drivers # +# CONFIG_RTC_DRV_MAX6902 is not set +CONFIG_RTC_DRV_R9701=y +# CONFIG_RTC_DRV_RS5C348 is not set # # Platform RTC drivers # +# CONFIG_RTC_DRV_DS1511 is not set # CONFIG_RTC_DRV_DS1553 is not set -# CONFIG_RTC_DRV_STK17TA8 is not set # CONFIG_RTC_DRV_DS1742 is not set +# CONFIG_RTC_DRV_STK17TA8 is not set # CONFIG_RTC_DRV_M48T86 is not set # CONFIG_RTC_DRV_M48T59 is not set # CONFIG_RTC_DRV_V3020 is not set @@ -963,20 +1136,7 @@ CONFIG_RTC_INTF_DEV=y # # on-CPU RTC drivers # -CONFIG_RTC_DRV_SH=y - -# -# DMA Engine support -# -# CONFIG_DMA_ENGINE is not set - -# -# DMA Clients -# - -# -# DMA Devices -# +# CONFIG_RTC_DRV_SH is not set # # Userspace I/O @@ -1034,7 +1194,6 @@ CONFIG_TMPFS=y # CONFIG_TMPFS_POSIX_ACL is not set # CONFIG_HUGETLBFS is not set # CONFIG_HUGETLB_PAGE is not set -CONFIG_RAMFS=y # CONFIG_CONFIGFS_FS is not set # @@ -1053,10 +1212,7 @@ CONFIG_RAMFS=y # CONFIG_QNX4FS_FS is not set # CONFIG_SYSV_FS is not set # CONFIG_UFS_FS is not set - -# -# Network File Systems -# +CONFIG_NETWORK_FILESYSTEMS=y # CONFIG_NFS_FS is not set # CONFIG_NFSD is not set # CONFIG_SMB_FS is not set @@ -1070,10 +1226,6 @@ CONFIG_RAMFS=y # # CONFIG_PARTITION_ADVANCED is not set CONFIG_MSDOS_PARTITION=y - -# -# Native Language Support -# CONFIG_NLS=y CONFIG_NLS_DEFAULT="iso8859-1" # CONFIG_NLS_CODEPAGE_437 is not set @@ -1114,30 +1266,22 @@ CONFIG_NLS_CODEPAGE_932=y # CONFIG_NLS_KOI8_R is not set # CONFIG_NLS_KOI8_U is not set # CONFIG_NLS_UTF8 is not set - -# -# Distributed Lock Manager -# # CONFIG_DLM is not set # -# Profiling support -# -CONFIG_PROFILING=y -CONFIG_OPROFILE=y - -# # Kernel hacking # CONFIG_TRACE_IRQFLAGS_SUPPORT=y # CONFIG_PRINTK_TIME is not set +CONFIG_ENABLE_WARN_DEPRECATED=y CONFIG_ENABLE_MUST_CHECK=y # CONFIG_MAGIC_SYSRQ is not set # CONFIG_UNUSED_SYMBOLS is not set -# CONFIG_DEBUG_FS is not set +CONFIG_DEBUG_FS=y # CONFIG_HEADERS_CHECK is not set # CONFIG_DEBUG_KERNEL is not set # CONFIG_DEBUG_BUGVERBOSE is not set +# CONFIG_SAMPLES is not set # CONFIG_SH_STANDARD_BIOS is not set CONFIG_EARLY_SCIF_CONSOLE=y CONFIG_EARLY_SCIF_CONSOLE_PORT=0xffe80000 @@ -1149,7 +1293,53 @@ CONFIG_EARLY_PRINTK=y # # CONFIG_KEYS is not set # CONFIG_SECURITY is not set -# CONFIG_CRYPTO is not set +# CONFIG_SECURITY_FILE_CAPABILITIES is not set +CONFIG_CRYPTO=y +# CONFIG_CRYPTO_SEQIV is not set +# CONFIG_CRYPTO_MANAGER is not set +# CONFIG_CRYPTO_HMAC is not set +# CONFIG_CRYPTO_XCBC is not set +# CONFIG_CRYPTO_NULL is not set +# CONFIG_CRYPTO_MD4 is not set +# CONFIG_CRYPTO_MD5 is not set +# CONFIG_CRYPTO_SHA1 is not set +# CONFIG_CRYPTO_SHA256 is not set +# CONFIG_CRYPTO_SHA512 is not set +# CONFIG_CRYPTO_WP512 is not set +# CONFIG_CRYPTO_TGR192 is not set +# CONFIG_CRYPTO_GF128MUL is not set +# CONFIG_CRYPTO_ECB is not set +# CONFIG_CRYPTO_CBC is not set +# CONFIG_CRYPTO_PCBC is not set +# CONFIG_CRYPTO_LRW is not set +# CONFIG_CRYPTO_XTS is not set +# CONFIG_CRYPTO_CTR is not set +# CONFIG_CRYPTO_GCM is not set +# CONFIG_CRYPTO_CCM is not set +# CONFIG_CRYPTO_CRYPTD is not set +# CONFIG_CRYPTO_DES is not set +# CONFIG_CRYPTO_FCRYPT is not set +# CONFIG_CRYPTO_BLOWFISH is not set +# CONFIG_CRYPTO_TWOFISH is not set +# CONFIG_CRYPTO_SERPENT is not set +# CONFIG_CRYPTO_AES is not set +# CONFIG_CRYPTO_CAST5 is not set +# CONFIG_CRYPTO_CAST6 is not set +# CONFIG_CRYPTO_TEA is not set +# CONFIG_CRYPTO_ARC4 is not set +# CONFIG_CRYPTO_KHAZAD is not set +# CONFIG_CRYPTO_ANUBIS is not set +# CONFIG_CRYPTO_SEED is not set +# CONFIG_CRYPTO_SALSA20 is not set +# CONFIG_CRYPTO_DEFLATE is not set +# CONFIG_CRYPTO_MICHAEL_MIC is not set +# CONFIG_CRYPTO_CRC32C is not set +# CONFIG_CRYPTO_CAMELLIA is not set +# CONFIG_CRYPTO_TEST is not set +# CONFIG_CRYPTO_AUTHENC is not set +# CONFIG_CRYPTO_LZO is not set +CONFIG_CRYPTO_HW=y +# CONFIG_CRYPTO_DEV_HIFN_795X is not set # # Library routines diff --git a/arch/sh/configs/rts7751r2dplus_defconfig b/arch/sh/configs/rts7751r2dplus_defconfig index 4ff5a752dcd..0a6d3b9e648 100644 --- a/arch/sh/configs/rts7751r2dplus_defconfig +++ b/arch/sh/configs/rts7751r2dplus_defconfig @@ -1,9 +1,10 @@ # # Automatically generated make config: don't edit -# Linux kernel version: 2.6.23-rc2 -# Tue Aug 14 16:33:08 2007 +# Linux kernel version: 2.6.24 +# Thu Feb 7 16:17:47 2008 # CONFIG_SUPERH=y +CONFIG_SUPERH32=y CONFIG_RWSEM_GENERIC_SPINLOCK=y CONFIG_GENERIC_BUG=y CONFIG_GENERIC_FIND_NEXT_BIT=y @@ -36,9 +37,14 @@ CONFIG_SYSVIPC_SYSCTL=y # CONFIG_BSD_PROCESS_ACCT is not set # CONFIG_TASKSTATS is not set # CONFIG_USER_NS is not set +# CONFIG_PID_NS is not set # CONFIG_AUDIT is not set # CONFIG_IKCONFIG is not set CONFIG_LOG_BUF_SHIFT=14 +# CONFIG_CGROUPS is not set +CONFIG_FAIR_GROUP_SCHED=y +CONFIG_FAIR_USER_SCHED=y +# CONFIG_FAIR_CGROUP_SCHED is not set CONFIG_SYSFS_DEPRECATED=y # CONFIG_RELAY is not set # CONFIG_BLK_DEV_INITRD is not set @@ -53,6 +59,7 @@ CONFIG_HOTPLUG=y CONFIG_PRINTK=y CONFIG_BUG=y CONFIG_ELF_CORE=y +CONFIG_COMPAT_BRK=y CONFIG_BASE_FULL=y CONFIG_FUTEX=y CONFIG_ANON_INODES=y @@ -65,6 +72,13 @@ CONFIG_VM_EVENT_COUNTERS=y CONFIG_SLAB=y # CONFIG_SLUB is not set # CONFIG_SLOB is not set +CONFIG_PROFILING=y +# CONFIG_MARKERS is not set +CONFIG_OPROFILE=y +CONFIG_HAVE_OPROFILE=y +# CONFIG_HAVE_KPROBES is not set +CONFIG_PROC_PAGE_MONITOR=y +CONFIG_SLABINFO=y CONFIG_RT_MUTEXES=y # CONFIG_TINY_SHMEM is not set CONFIG_BASE_SMALL=0 @@ -91,13 +105,17 @@ CONFIG_DEFAULT_AS=y # CONFIG_DEFAULT_CFQ is not set # CONFIG_DEFAULT_NOOP is not set CONFIG_DEFAULT_IOSCHED="anticipatory" +CONFIG_CLASSIC_RCU=y +# CONFIG_PREEMPT_RCU is not set # # System type # CONFIG_CPU_SH4=y # CONFIG_CPU_SUBTYPE_SH7619 is not set +# CONFIG_CPU_SUBTYPE_SH7203 is not set # CONFIG_CPU_SUBTYPE_SH7206 is not set +# CONFIG_CPU_SUBTYPE_SH7263 is not set # CONFIG_CPU_SUBTYPE_SH7705 is not set # CONFIG_CPU_SUBTYPE_SH7706 is not set # CONFIG_CPU_SUBTYPE_SH7707 is not set @@ -105,6 +123,8 @@ CONFIG_CPU_SH4=y # CONFIG_CPU_SUBTYPE_SH7709 is not set # CONFIG_CPU_SUBTYPE_SH7710 is not set # CONFIG_CPU_SUBTYPE_SH7712 is not set +# CONFIG_CPU_SUBTYPE_SH7720 is not set +# CONFIG_CPU_SUBTYPE_SH7721 is not set # CONFIG_CPU_SUBTYPE_SH7750 is not set # CONFIG_CPU_SUBTYPE_SH7091 is not set # CONFIG_CPU_SUBTYPE_SH7750R is not set @@ -113,14 +133,15 @@ CONFIG_CPU_SH4=y CONFIG_CPU_SUBTYPE_SH7751R=y # CONFIG_CPU_SUBTYPE_SH7760 is not set # CONFIG_CPU_SUBTYPE_SH4_202 is not set -# CONFIG_CPU_SUBTYPE_ST40STB1 is not set -# CONFIG_CPU_SUBTYPE_ST40GX1 is not set +# CONFIG_CPU_SUBTYPE_SH7763 is not set # CONFIG_CPU_SUBTYPE_SH7770 is not set # CONFIG_CPU_SUBTYPE_SH7780 is not set # CONFIG_CPU_SUBTYPE_SH7785 is not set # CONFIG_CPU_SUBTYPE_SHX3 is not set # CONFIG_CPU_SUBTYPE_SH7343 is not set # CONFIG_CPU_SUBTYPE_SH7722 is not set +# CONFIG_CPU_SUBTYPE_SH5_101 is not set +# CONFIG_CPU_SUBTYPE_SH5_103 is not set # # Memory management options @@ -130,6 +151,7 @@ CONFIG_MMU=y CONFIG_PAGE_OFFSET=0x80000000 CONFIG_MEMORY_START=0x0c000000 CONFIG_MEMORY_SIZE=0x04000000 +CONFIG_29BIT=y CONFIG_VSYSCALL=y CONFIG_ARCH_FLATMEM_ENABLE=y CONFIG_ARCH_SPARSEMEM_ENABLE=y @@ -147,6 +169,7 @@ CONFIG_FLATMEM_MANUAL=y CONFIG_FLATMEM=y CONFIG_FLAT_NODE_MEM_MAP=y CONFIG_SPARSEMEM_STATIC=y +# CONFIG_SPARSEMEM_VMEMMAP_ENABLE is not set CONFIG_SPLIT_PTLOCK_CPUS=4 # CONFIG_RESOURCES_64BIT is not set CONFIG_ZONE_DMA_FLAG=0 @@ -168,23 +191,22 @@ CONFIG_CPU_LITTLE_ENDIAN=y CONFIG_SH_FPU=y # CONFIG_SH_STORE_QUEUES is not set CONFIG_CPU_HAS_INTEVT=y -CONFIG_CPU_HAS_INTC_IRQ=y CONFIG_CPU_HAS_SR_RB=y CONFIG_CPU_HAS_PTEA=y +CONFIG_CPU_HAS_FPU=y # # Board support # # CONFIG_SH_7751_SYSTEMH is not set # CONFIG_SH_SECUREEDGE5410 is not set -# CONFIG_SH_HS7751RVOIP is not set CONFIG_SH_RTS7751R2D=y # CONFIG_SH_LANDISK is not set # CONFIG_SH_TITAN is not set # CONFIG_SH_LBOX_RE2 is not set # -# RTS7751R2D options +# RTS7751R2D Board Revision # CONFIG_RTS7751R2D_PLUS=y # CONFIG_RTS7751R2D_1 is not set @@ -198,6 +220,7 @@ CONFIG_SH_PCLK_FREQ=60000000 # CONFIG_TICK_ONESHOT is not set # CONFIG_NO_HZ is not set # CONFIG_HIGH_RES_TIMERS is not set +CONFIG_GENERIC_CLOCKEVENTS_BUILD=y # # CPU Frequency scaling @@ -227,11 +250,15 @@ CONFIG_HZ_250=y # CONFIG_HZ_300 is not set # CONFIG_HZ_1000 is not set CONFIG_HZ=250 +# CONFIG_SCHED_HRTICK is not set # CONFIG_KEXEC is not set # CONFIG_CRASH_DUMP is not set CONFIG_PREEMPT_NONE=y # CONFIG_PREEMPT_VOLUNTARY is not set # CONFIG_PREEMPT is not set +CONFIG_RCU_TRACE=y +CONFIG_GUSA=y +# CONFIG_GUSA_RB is not set # # Boot options @@ -250,10 +277,7 @@ CONFIG_SH_PCIDMA_NONCOHERENT=y CONFIG_PCI_AUTO=y CONFIG_PCI_AUTO_UPDATE_RESOURCES=y # CONFIG_ARCH_SUPPORTS_MSI is not set - -# -# PCCARD (PCMCIA/CardBus) support -# +CONFIG_PCI_LEGACY=y # CONFIG_PCCARD is not set CONFIG_HOTPLUG_PCI=y # CONFIG_HOTPLUG_PCI_FAKE is not set @@ -281,6 +305,7 @@ CONFIG_XFRM=y # CONFIG_XFRM_USER is not set # CONFIG_XFRM_SUB_POLICY is not set # CONFIG_XFRM_MIGRATE is not set +# CONFIG_XFRM_STATISTICS is not set # CONFIG_NET_KEY is not set CONFIG_INET=y # CONFIG_IP_MULTICAST is not set @@ -299,6 +324,7 @@ CONFIG_IP_FIB_HASH=y CONFIG_INET_XFRM_MODE_TRANSPORT=y CONFIG_INET_XFRM_MODE_TUNNEL=y CONFIG_INET_XFRM_MODE_BEET=y +# CONFIG_INET_LRO is not set CONFIG_INET_DIAG=y CONFIG_INET_TCP_DIAG=y # CONFIG_TCP_CONG_ADVANCED is not set @@ -324,10 +350,6 @@ CONFIG_DEFAULT_TCP_CONG="cubic" # CONFIG_LAPB is not set # CONFIG_ECONET is not set # CONFIG_WAN_ROUTER is not set - -# -# QoS and/or fair queueing -# # CONFIG_NET_SCHED is not set # @@ -335,6 +357,7 @@ CONFIG_DEFAULT_TCP_CONG="cubic" # # CONFIG_NET_PKTGEN is not set # CONFIG_HAMRADIO is not set +# CONFIG_CAN is not set # CONFIG_IRDA is not set # CONFIG_BT is not set # CONFIG_AF_RXRPC is not set @@ -356,6 +379,7 @@ CONFIG_WIRELESS_EXT=y # # Generic Driver Options # +CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" CONFIG_STANDALONE=y CONFIG_PREVENT_FIRMWARE_BUILD=y CONFIG_FW_LOADER=m @@ -371,6 +395,7 @@ CONFIG_BLK_DEV=y # CONFIG_BLK_DEV_LOOP is not set # CONFIG_BLK_DEV_NBD is not set # CONFIG_BLK_DEV_SX8 is not set +# CONFIG_BLK_DEV_UB is not set CONFIG_BLK_DEV_RAM=y CONFIG_BLK_DEV_RAM_COUNT=16 CONFIG_BLK_DEV_RAM_SIZE=4096 @@ -420,6 +445,7 @@ CONFIG_SCSI_WAIT_SCAN=m # CONFIG_SCSI_FC_ATTRS is not set # CONFIG_SCSI_ISCSI_ATTRS is not set # CONFIG_SCSI_SAS_LIBSAS is not set +# CONFIG_SCSI_SRP_ATTRS is not set CONFIG_SCSI_LOWLEVEL=y # CONFIG_ISCSI_TCP is not set # CONFIG_BLK_DEV_3W_XXXX_RAID is not set @@ -493,7 +519,9 @@ CONFIG_ATA=y # CONFIG_PATA_MPIIX is not set # CONFIG_PATA_OLDPIIX is not set # CONFIG_PATA_NETCELL is not set +# CONFIG_PATA_NINJA32 is not set # CONFIG_PATA_NS87410 is not set +# CONFIG_PATA_NS87415 is not set # CONFIG_PATA_OPTI is not set # CONFIG_PATA_OPTIDMA is not set # CONFIG_PATA_PDC_OLD is not set @@ -508,14 +536,7 @@ CONFIG_ATA=y # CONFIG_PATA_WINBOND is not set CONFIG_PATA_PLATFORM=y # CONFIG_MD is not set - -# -# Fusion MPT device support -# # CONFIG_FUSION is not set -# CONFIG_FUSION_SPI is not set -# CONFIG_FUSION_FC is not set -# CONFIG_FUSION_SAS is not set # # IEEE 1394 (FireWire) support @@ -530,25 +551,31 @@ CONFIG_NETDEVICES=y # CONFIG_MACVLAN is not set # CONFIG_EQUALIZER is not set # CONFIG_TUN is not set +# CONFIG_VETH is not set # CONFIG_ARCNET is not set # CONFIG_PHYLIB is not set CONFIG_NET_ETHERNET=y CONFIG_MII=y +# CONFIG_AX88796 is not set # CONFIG_STNIC is not set # CONFIG_HAPPYMEAL is not set # CONFIG_SUNGEM is not set # CONFIG_CASSINI is not set # CONFIG_NET_VENDOR_3COM is not set # CONFIG_SMC91X is not set +# CONFIG_ENC28J60 is not set # CONFIG_NET_TULIP is not set # CONFIG_HP100 is not set +# CONFIG_IBM_NEW_EMAC_ZMII is not set +# CONFIG_IBM_NEW_EMAC_RGMII is not set +# CONFIG_IBM_NEW_EMAC_TAH is not set +# CONFIG_IBM_NEW_EMAC_EMAC4 is not set CONFIG_NET_PCI=y # CONFIG_PCNET32 is not set # CONFIG_AMD8111_ETH is not set # CONFIG_ADAPTEC_STARFIRE is not set # CONFIG_B44 is not set # CONFIG_FORCEDETH is not set -# CONFIG_DGRS is not set # CONFIG_EEPRO100 is not set # CONFIG_E100 is not set # CONFIG_FEALNX is not set @@ -560,6 +587,7 @@ CONFIG_8139TOO=y # CONFIG_8139TOO_TUNE_TWISTER is not set # CONFIG_8139TOO_8129 is not set # CONFIG_8139_OLD_RX_RESET is not set +# CONFIG_R6040 is not set # CONFIG_SIS900 is not set # CONFIG_EPIC100 is not set # CONFIG_SUNDANCE is not set @@ -570,6 +598,10 @@ CONFIG_NETDEV_1000=y # CONFIG_ACENIC is not set # CONFIG_DL2K is not set # CONFIG_E1000 is not set +# CONFIG_E1000E is not set +# CONFIG_E1000E_ENABLED is not set +# CONFIG_IP1000 is not set +# CONFIG_IGB is not set # CONFIG_NS83820 is not set # CONFIG_HAMACHI is not set # CONFIG_YELLOWFIN is not set @@ -577,6 +609,7 @@ CONFIG_NETDEV_1000=y # CONFIG_SIS190 is not set # CONFIG_SKGE is not set # CONFIG_SKY2 is not set +# CONFIG_SK98LIN is not set # CONFIG_VIA_VELOCITY is not set # CONFIG_TIGON3 is not set # CONFIG_BNX2 is not set @@ -585,11 +618,15 @@ CONFIG_NETDEV_1000=y CONFIG_NETDEV_10000=y # CONFIG_CHELSIO_T1 is not set # CONFIG_CHELSIO_T3 is not set +# CONFIG_IXGBE is not set # CONFIG_IXGB is not set # CONFIG_S2IO is not set # CONFIG_MYRI10GE is not set # CONFIG_NETXEN_NIC is not set +# CONFIG_NIU is not set # CONFIG_MLX4_CORE is not set +# CONFIG_TEHUTI is not set +# CONFIG_BNX2X is not set # CONFIG_TR is not set # @@ -597,13 +634,21 @@ CONFIG_NETDEV_10000=y # # CONFIG_WLAN_PRE80211 is not set # CONFIG_WLAN_80211 is not set + +# +# USB Network Adapters +# +# CONFIG_USB_CATC is not set +# CONFIG_USB_KAWETH is not set +# CONFIG_USB_PEGASUS is not set +# CONFIG_USB_RTL8150 is not set +# CONFIG_USB_USBNET is not set # CONFIG_WAN is not set # CONFIG_FDDI is not set # CONFIG_HIPPI is not set # CONFIG_PPP is not set # CONFIG_SLIP is not set # CONFIG_NET_FC 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 @@ -622,7 +667,6 @@ CONFIG_INPUT=y # # CONFIG_INPUT_MOUSEDEV is not set # CONFIG_INPUT_JOYDEV is not set -# CONFIG_INPUT_TSDEV is not set # CONFIG_INPUT_EVDEV is not set # CONFIG_INPUT_EVBUG is not set @@ -650,6 +694,7 @@ CONFIG_VT_CONSOLE=y CONFIG_HW_CONSOLE=y CONFIG_VT_HW_CONSOLE_BINDING=y # CONFIG_SERIAL_NONSTANDARD is not set +# CONFIG_NOZOMI is not set # # Serial drivers @@ -674,11 +719,9 @@ CONFIG_UNIX98_PTYS=y CONFIG_LEGACY_PTYS=y CONFIG_LEGACY_PTY_COUNT=256 # CONFIG_IPMI_HANDLER is not set -# CONFIG_WATCHDOG is not set CONFIG_HW_RANDOM=y # CONFIG_R3964 is not set # CONFIG_APPLICOM is not set -# CONFIG_DRM is not set # CONFIG_RAW_DRIVER is not set # CONFIG_TCG_TPM is not set CONFIG_DEVPORT=y @@ -687,16 +730,30 @@ CONFIG_DEVPORT=y # # SPI support # -# CONFIG_SPI is not set -# CONFIG_SPI_MASTER is not set +CONFIG_SPI=y +CONFIG_SPI_MASTER=y + +# +# SPI Master Controller Drivers +# +CONFIG_SPI_BITBANG=y +CONFIG_SPI_SH_SCI=y + +# +# SPI Protocol Masters +# +# CONFIG_SPI_AT25 is not set +# CONFIG_SPI_SPIDEV is not set +# CONFIG_SPI_TLE62X0 is not set # CONFIG_W1 is not set # CONFIG_POWER_SUPPLY is not set CONFIG_HWMON=y # CONFIG_HWMON_VID is not set -# CONFIG_SENSORS_ABITUGURU is not set -# CONFIG_SENSORS_ABITUGURU3 is not set +# CONFIG_SENSORS_I5K_AMB is not set # CONFIG_SENSORS_F71805F is not set +# CONFIG_SENSORS_F71882FG is not set # CONFIG_SENSORS_IT87 is not set +# CONFIG_SENSORS_LM70 is not set # CONFIG_SENSORS_PC87360 is not set # CONFIG_SENSORS_PC87427 is not set # CONFIG_SENSORS_SIS5595 is not set @@ -708,6 +765,13 @@ CONFIG_HWMON=y # CONFIG_SENSORS_W83627HF is not set # CONFIG_SENSORS_W83627EHF is not set # CONFIG_HWMON_DEBUG_CHIP is not set +# CONFIG_WATCHDOG is not set + +# +# Sonics Silicon Backplane +# +CONFIG_SSB_POSSIBLE=y +# CONFIG_SSB is not set # # Multifunction device drivers @@ -720,16 +784,12 @@ CONFIG_MFD_SM501=y # CONFIG_VIDEO_DEV is not set # CONFIG_DVB_CORE is not set CONFIG_DAB=y +# CONFIG_USB_DABUSB is not set # # Graphics support # -# CONFIG_BACKLIGHT_LCD_SUPPORT is not set - -# -# Display device support -# -# CONFIG_DISPLAY_SUPPORT is not set +# CONFIG_DRM is not set # CONFIG_VGASTATE is not set CONFIG_VIDEO_OUTPUT_CONTROL=m CONFIG_FB=y @@ -738,6 +798,7 @@ CONFIG_FB=y CONFIG_FB_CFB_FILLRECT=y CONFIG_FB_CFB_COPYAREA=y CONFIG_FB_CFB_IMAGEBLIT=y +# CONFIG_FB_CFB_REV_PIXELS_IN_BYTE is not set # CONFIG_FB_SYS_FILLRECT is not set # CONFIG_FB_SYS_COPYAREA is not set # CONFIG_FB_SYS_IMAGEBLIT is not set @@ -777,6 +838,12 @@ CONFIG_FB_DEFERRED_IO=y # CONFIG_FB_PM3 is not set CONFIG_FB_SM501=y # CONFIG_FB_VIRTUAL is not set +# CONFIG_BACKLIGHT_LCD_SUPPORT is not set + +# +# Display device support +# +# CONFIG_DISPLAY_SUPPORT is not set # # Console display driver support @@ -844,6 +911,7 @@ CONFIG_SND_AC97_CODEC=m # CONFIG_SND_BT87X is not set # CONFIG_SND_CA0106 is not set # CONFIG_SND_CMIPCI is not set +# CONFIG_SND_OXYGEN is not set # CONFIG_SND_CS4281 is not set # CONFIG_SND_CS46XX is not set # CONFIG_SND_DARLA20 is not set @@ -868,6 +936,7 @@ CONFIG_SND_AC97_CODEC=m # CONFIG_SND_HDA_INTEL is not set # CONFIG_SND_HDSP is not set # CONFIG_SND_HDSPM is not set +# CONFIG_SND_HIFIER is not set # CONFIG_SND_ICE1712 is not set # CONFIG_SND_ICE1724 is not set # CONFIG_SND_INTEL8X0 is not set @@ -885,16 +954,27 @@ CONFIG_SND_AC97_CODEC=m # CONFIG_SND_TRIDENT is not set # CONFIG_SND_VIA82XX is not set # CONFIG_SND_VIA82XX_MODEM is not set +# CONFIG_SND_VIRTUOSO is not set # CONFIG_SND_VX222 is not set CONFIG_SND_YMFPCI=m CONFIG_SND_YMFPCI_FIRMWARE_IN_KERNEL=y # CONFIG_SND_AC97_POWER_SAVE is not set # +# SPI devices +# + +# # SUPERH devices # # +# USB devices +# +# CONFIG_SND_USB_AUDIO is not set +# CONFIG_SND_USB_CAIAQ is not set + +# # System on Chip audio support # # CONFIG_SND_SOC is not set @@ -904,6 +984,10 @@ CONFIG_SND_YMFPCI_FIRMWARE_IN_KERNEL=y # # +# ALSA SoC audio for Freescale SOCs +# + +# # Open Sound System # CONFIG_SOUND_PRIME=m @@ -914,19 +998,104 @@ CONFIG_AC97_BUS=m CONFIG_HID_SUPPORT=y CONFIG_HID=y # CONFIG_HID_DEBUG is not set +# CONFIG_HIDRAW is not set + +# +# USB Input Devices +# +CONFIG_USB_HID=y +# CONFIG_USB_HIDINPUT_POWERBOOK is not set +# CONFIG_HID_FF is not set +# CONFIG_USB_HIDDEV is not set CONFIG_USB_SUPPORT=y CONFIG_USB_ARCH_HAS_HCD=y CONFIG_USB_ARCH_HAS_OHCI=y CONFIG_USB_ARCH_HAS_EHCI=y -# CONFIG_USB is not set +CONFIG_USB=y +# CONFIG_USB_DEBUG is not set +CONFIG_USB_ANNOUNCE_NEW_DEVICES=y + +# +# Miscellaneous USB options +# +# CONFIG_USB_DEVICEFS is not set +CONFIG_USB_DEVICE_CLASS=y +# CONFIG_USB_DYNAMIC_MINORS is not set +# CONFIG_USB_OTG is not set + +# +# USB Host Controller Drivers +# +# CONFIG_USB_EHCI_HCD is not set +# CONFIG_USB_ISP116X_HCD is not set +CONFIG_USB_OHCI_HCD=y +# CONFIG_USB_OHCI_BIG_ENDIAN_DESC is not set +# CONFIG_USB_OHCI_BIG_ENDIAN_MMIO is not set +CONFIG_USB_OHCI_LITTLE_ENDIAN=y +# CONFIG_USB_UHCI_HCD is not set +# CONFIG_USB_SL811_HCD is not set +# CONFIG_USB_R8A66597_HCD is not set + +# +# USB Device Class drivers +# +# CONFIG_USB_ACM is not set +# CONFIG_USB_PRINTER is not set # # NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support' # # -# USB Gadget Support +# may also be needed; see USB_STORAGE Help for more information +# +CONFIG_USB_STORAGE=y +# CONFIG_USB_STORAGE_DEBUG is not set +# CONFIG_USB_STORAGE_DATAFAB is not set +# CONFIG_USB_STORAGE_FREECOM is not set +# CONFIG_USB_STORAGE_ISD200 is not set +# CONFIG_USB_STORAGE_DPCM is not set +# CONFIG_USB_STORAGE_USBAT is not set +# CONFIG_USB_STORAGE_SDDR09 is not set +# CONFIG_USB_STORAGE_SDDR55 is not set +# CONFIG_USB_STORAGE_JUMPSHOT is not set +# CONFIG_USB_STORAGE_ALAUDA is not set +# CONFIG_USB_STORAGE_KARMA is not set +CONFIG_USB_LIBUSUAL=y + +# +# USB Imaging devices +# +# CONFIG_USB_MDC800 is not set +# CONFIG_USB_MICROTEK is not set +# CONFIG_USB_MON is not set + +# +# USB port drivers +# +# CONFIG_USB_SERIAL is not set + +# +# USB Miscellaneous drivers # +# CONFIG_USB_EMI62 is not set +# CONFIG_USB_EMI26 is not set +# CONFIG_USB_ADUTUX is not set +# CONFIG_USB_AUERSWALD is not set +# CONFIG_USB_RIO500 is not set +# CONFIG_USB_LEGOTOWER is not set +# CONFIG_USB_LCD is not set +# CONFIG_USB_BERRY_CHARGE is not set +# CONFIG_USB_LED is not set +# CONFIG_USB_CYPRESS_CY7C63 is not set +# CONFIG_USB_CYTHERM is not set +# CONFIG_USB_PHIDGET is not set +# CONFIG_USB_IDMOUSE is not set +# CONFIG_USB_FTDI_ELAN is not set +# CONFIG_USB_APPLEDISPLAY is not set +# CONFIG_USB_LD is not set +# CONFIG_USB_TRANCEVIBRATOR is not set +# CONFIG_USB_IOWARRIOR is not set # CONFIG_USB_GADGET is not set # CONFIG_MMC is not set # CONFIG_NEW_LEDS is not set @@ -949,13 +1118,17 @@ CONFIG_RTC_INTF_DEV=y # # SPI RTC drivers # +# CONFIG_RTC_DRV_MAX6902 is not set +CONFIG_RTC_DRV_R9701=y +# CONFIG_RTC_DRV_RS5C348 is not set # # Platform RTC drivers # +# CONFIG_RTC_DRV_DS1511 is not set # CONFIG_RTC_DRV_DS1553 is not set -# CONFIG_RTC_DRV_STK17TA8 is not set # CONFIG_RTC_DRV_DS1742 is not set +# CONFIG_RTC_DRV_STK17TA8 is not set # CONFIG_RTC_DRV_M48T86 is not set # CONFIG_RTC_DRV_M48T59 is not set # CONFIG_RTC_DRV_V3020 is not set @@ -963,20 +1136,7 @@ CONFIG_RTC_INTF_DEV=y # # on-CPU RTC drivers # -CONFIG_RTC_DRV_SH=y - -# -# DMA Engine support -# -# CONFIG_DMA_ENGINE is not set - -# -# DMA Clients -# - -# -# DMA Devices -# +# CONFIG_RTC_DRV_SH is not set # # Userspace I/O @@ -1034,7 +1194,6 @@ CONFIG_TMPFS=y # CONFIG_TMPFS_POSIX_ACL is not set # CONFIG_HUGETLBFS is not set # CONFIG_HUGETLB_PAGE is not set -CONFIG_RAMFS=y # CONFIG_CONFIGFS_FS is not set # @@ -1053,10 +1212,7 @@ CONFIG_RAMFS=y # CONFIG_QNX4FS_FS is not set # CONFIG_SYSV_FS is not set # CONFIG_UFS_FS is not set - -# -# Network File Systems -# +CONFIG_NETWORK_FILESYSTEMS=y # CONFIG_NFS_FS is not set # CONFIG_NFSD is not set # CONFIG_SMB_FS is not set @@ -1070,10 +1226,6 @@ CONFIG_RAMFS=y # # CONFIG_PARTITION_ADVANCED is not set CONFIG_MSDOS_PARTITION=y - -# -# Native Language Support -# CONFIG_NLS=y CONFIG_NLS_DEFAULT="iso8859-1" # CONFIG_NLS_CODEPAGE_437 is not set @@ -1114,30 +1266,22 @@ CONFIG_NLS_CODEPAGE_932=y # CONFIG_NLS_KOI8_R is not set # CONFIG_NLS_KOI8_U is not set # CONFIG_NLS_UTF8 is not set - -# -# Distributed Lock Manager -# # CONFIG_DLM is not set # -# Profiling support -# -CONFIG_PROFILING=y -CONFIG_OPROFILE=y - -# # Kernel hacking # CONFIG_TRACE_IRQFLAGS_SUPPORT=y # CONFIG_PRINTK_TIME is not set +CONFIG_ENABLE_WARN_DEPRECATED=y CONFIG_ENABLE_MUST_CHECK=y # CONFIG_MAGIC_SYSRQ is not set # CONFIG_UNUSED_SYMBOLS is not set -# CONFIG_DEBUG_FS is not set +CONFIG_DEBUG_FS=y # CONFIG_HEADERS_CHECK is not set # CONFIG_DEBUG_KERNEL is not set # CONFIG_DEBUG_BUGVERBOSE is not set +# CONFIG_SAMPLES is not set # CONFIG_SH_STANDARD_BIOS is not set CONFIG_EARLY_SCIF_CONSOLE=y CONFIG_EARLY_SCIF_CONSOLE_PORT=0xffe80000 @@ -1149,7 +1293,53 @@ CONFIG_EARLY_PRINTK=y # # CONFIG_KEYS is not set # CONFIG_SECURITY is not set -# CONFIG_CRYPTO is not set +# CONFIG_SECURITY_FILE_CAPABILITIES is not set +CONFIG_CRYPTO=y +# CONFIG_CRYPTO_SEQIV is not set +# CONFIG_CRYPTO_MANAGER is not set +# CONFIG_CRYPTO_HMAC is not set +# CONFIG_CRYPTO_XCBC is not set +# CONFIG_CRYPTO_NULL is not set +# CONFIG_CRYPTO_MD4 is not set +# CONFIG_CRYPTO_MD5 is not set +# CONFIG_CRYPTO_SHA1 is not set +# CONFIG_CRYPTO_SHA256 is not set +# CONFIG_CRYPTO_SHA512 is not set +# CONFIG_CRYPTO_WP512 is not set +# CONFIG_CRYPTO_TGR192 is not set +# CONFIG_CRYPTO_GF128MUL is not set +# CONFIG_CRYPTO_ECB is not set +# CONFIG_CRYPTO_CBC is not set +# CONFIG_CRYPTO_PCBC is not set +# CONFIG_CRYPTO_LRW is not set +# CONFIG_CRYPTO_XTS is not set +# CONFIG_CRYPTO_CTR is not set +# CONFIG_CRYPTO_GCM is not set +# CONFIG_CRYPTO_CCM is not set +# CONFIG_CRYPTO_CRYPTD is not set +# CONFIG_CRYPTO_DES is not set +# CONFIG_CRYPTO_FCRYPT is not set +# CONFIG_CRYPTO_BLOWFISH is not set +# CONFIG_CRYPTO_TWOFISH is not set +# CONFIG_CRYPTO_SERPENT is not set +# CONFIG_CRYPTO_AES is not set +# CONFIG_CRYPTO_CAST5 is not set +# CONFIG_CRYPTO_CAST6 is not set +# CONFIG_CRYPTO_TEA is not set +# CONFIG_CRYPTO_ARC4 is not set +# CONFIG_CRYPTO_KHAZAD is not set +# CONFIG_CRYPTO_ANUBIS is not set +# CONFIG_CRYPTO_SEED is not set +# CONFIG_CRYPTO_SALSA20 is not set +# CONFIG_CRYPTO_DEFLATE is not set +# CONFIG_CRYPTO_MICHAEL_MIC is not set +# CONFIG_CRYPTO_CRC32C is not set +# CONFIG_CRYPTO_CAMELLIA is not set +# CONFIG_CRYPTO_TEST is not set +# CONFIG_CRYPTO_AUTHENC is not set +# CONFIG_CRYPTO_LZO is not set +CONFIG_CRYPTO_HW=y +# CONFIG_CRYPTO_DEV_HIFN_795X is not set # # Library routines diff --git a/arch/sh/configs/se7705_defconfig b/arch/sh/configs/se7705_defconfig index 87ae5c1f862..84717d85486 100644 --- a/arch/sh/configs/se7705_defconfig +++ b/arch/sh/configs/se7705_defconfig @@ -231,7 +231,6 @@ CONFIG_CPU_LITTLE_ENDIAN=y # CONFIG_SH_DSP is not set # CONFIG_SH_ADC is not set CONFIG_CPU_HAS_INTEVT=y -CONFIG_CPU_HAS_PINT_IRQ=y CONFIG_CPU_HAS_IPR_IRQ=y CONFIG_CPU_HAS_SR_RB=y diff --git a/arch/sh/drivers/dma/dma-api.c b/arch/sh/drivers/dma/dma-api.c index 76ed816d9a2..727126e907e 100644 --- a/arch/sh/drivers/dma/dma-api.c +++ b/arch/sh/drivers/dma/dma-api.c @@ -350,7 +350,7 @@ int register_dmac(struct dma_info *info) BUG_ON((info->flags & DMAC_CHANNELS_CONFIGURED) && !info->channels); - info->pdev = platform_device_register_simple((char *)info->name, -1, + info->pdev = platform_device_register_simple(info->name, -1, NULL, 0); if (IS_ERR(info->pdev)) return PTR_ERR(info->pdev); diff --git a/arch/sh/drivers/pci/fixups-lboxre2.c b/arch/sh/drivers/pci/fixups-lboxre2.c index 40b19bdfb89..1c1d41255ec 100644 --- a/arch/sh/drivers/pci/fixups-lboxre2.c +++ b/arch/sh/drivers/pci/fixups-lboxre2.c @@ -18,7 +18,7 @@ int pci_fixup_pcic(void) { unsigned long bcr1, mcr; - bcr1 = inl(SH7751_BCR1); + bcr1 = ctrl_inl(SH7751_BCR1); bcr1 |= 0x40080000; /* Enable Bit 19 BREQEN, set PCIC to slave */ pci_write_reg(bcr1, SH4_PCIBCR1); @@ -28,7 +28,7 @@ int pci_fixup_pcic(void) pci_write_reg(0xfb900047, SH7751_PCICONF1); pci_write_reg(0xab000001, SH7751_PCICONF4); - mcr = inl(SH7751_MCR); + mcr = ctrl_inl(SH7751_MCR); mcr = (mcr & PCIMCR_MRSET_OFF) & PCIMCR_RFSH_OFF; pci_write_reg(mcr, SH4_PCIMCR); diff --git a/arch/sh/drivers/pci/fixups-rts7751r2d.c b/arch/sh/drivers/pci/fixups-rts7751r2d.c index e72ceb560d5..904bce8768d 100644 --- a/arch/sh/drivers/pci/fixups-rts7751r2d.c +++ b/arch/sh/drivers/pci/fixups-rts7751r2d.c @@ -19,7 +19,7 @@ int pci_fixup_pcic(void) { unsigned long bcr1, mcr; - bcr1 = inl(SH7751_BCR1); + bcr1 = ctrl_inl(SH7751_BCR1); bcr1 |= 0x40080000; /* Enable Bit 19 BREQEN, set PCIC to slave */ pci_write_reg(bcr1, SH4_PCIBCR1); @@ -30,7 +30,7 @@ int pci_fixup_pcic(void) pci_write_reg(0xfb900047, SH7751_PCICONF1); pci_write_reg(0xab000001, SH7751_PCICONF4); - mcr = inl(SH7751_MCR); + mcr = ctrl_inl(SH7751_MCR); mcr = (mcr & PCIMCR_MRSET_OFF) & PCIMCR_RFSH_OFF; pci_write_reg(mcr, SH4_PCIMCR); diff --git a/arch/sh/drivers/pci/ops-dreamcast.c b/arch/sh/drivers/pci/ops-dreamcast.c index e1284fc6936..0dac87b1962 100644 --- a/arch/sh/drivers/pci/ops-dreamcast.c +++ b/arch/sh/drivers/pci/ops-dreamcast.c @@ -83,9 +83,9 @@ static int gapspci_read(struct pci_bus *bus, unsigned int devfn, int where, int return PCIBIOS_DEVICE_NOT_FOUND; switch (size) { - case 1: *val = inb(GAPSPCI_BBA_CONFIG+where); break; - case 2: *val = inw(GAPSPCI_BBA_CONFIG+where); break; - case 4: *val = inl(GAPSPCI_BBA_CONFIG+where); break; + case 1: *val = ctrl_inb(GAPSPCI_BBA_CONFIG+where); break; + case 2: *val = ctrl_inw(GAPSPCI_BBA_CONFIG+where); break; + case 4: *val = ctrl_inl(GAPSPCI_BBA_CONFIG+where); break; } return PCIBIOS_SUCCESSFUL; @@ -97,9 +97,9 @@ static int gapspci_write(struct pci_bus *bus, unsigned int devfn, int where, int return PCIBIOS_DEVICE_NOT_FOUND; switch (size) { - case 1: outb(( u8)val, GAPSPCI_BBA_CONFIG+where); break; - case 2: outw((u16)val, GAPSPCI_BBA_CONFIG+where); break; - case 4: outl((u32)val, GAPSPCI_BBA_CONFIG+where); break; + case 1: ctrl_outb(( u8)val, GAPSPCI_BBA_CONFIG+where); break; + case 2: ctrl_outw((u16)val, GAPSPCI_BBA_CONFIG+where); break; + case 4: ctrl_outl((u32)val, GAPSPCI_BBA_CONFIG+where); break; } return PCIBIOS_SUCCESSFUL; @@ -127,36 +127,36 @@ int __init gapspci_init(void) */ for (i=0; i<16; i++) - idbuf[i] = inb(GAPSPCI_REGS+i); + idbuf[i] = ctrl_inb(GAPSPCI_REGS+i); if (strncmp(idbuf, "GAPSPCI_BRIDGE_2", 16)) return -ENODEV; - outl(0x5a14a501, GAPSPCI_REGS+0x18); + ctrl_outl(0x5a14a501, GAPSPCI_REGS+0x18); for (i=0; i<1000000; i++) ; - if (inl(GAPSPCI_REGS+0x18) != 1) + if (ctrl_inl(GAPSPCI_REGS+0x18) != 1) return -EINVAL; - outl(0x01000000, GAPSPCI_REGS+0x20); - outl(0x01000000, GAPSPCI_REGS+0x24); + ctrl_outl(0x01000000, GAPSPCI_REGS+0x20); + ctrl_outl(0x01000000, GAPSPCI_REGS+0x24); - outl(GAPSPCI_DMA_BASE, GAPSPCI_REGS+0x28); - outl(GAPSPCI_DMA_BASE+GAPSPCI_DMA_SIZE, GAPSPCI_REGS+0x2c); + ctrl_outl(GAPSPCI_DMA_BASE, GAPSPCI_REGS+0x28); + ctrl_outl(GAPSPCI_DMA_BASE+GAPSPCI_DMA_SIZE, GAPSPCI_REGS+0x2c); - outl(1, GAPSPCI_REGS+0x14); - outl(1, GAPSPCI_REGS+0x34); + ctrl_outl(1, GAPSPCI_REGS+0x14); + ctrl_outl(1, GAPSPCI_REGS+0x34); /* Setting Broadband Adapter */ - outw(0xf900, GAPSPCI_BBA_CONFIG+0x06); - outl(0x00000000, GAPSPCI_BBA_CONFIG+0x30); - outb(0x00, GAPSPCI_BBA_CONFIG+0x3c); - outb(0xf0, GAPSPCI_BBA_CONFIG+0x0d); - outw(0x0006, GAPSPCI_BBA_CONFIG+0x04); - outl(0x00002001, GAPSPCI_BBA_CONFIG+0x10); - outl(0x01000000, GAPSPCI_BBA_CONFIG+0x14); + ctrl_outw(0xf900, GAPSPCI_BBA_CONFIG+0x06); + ctrl_outl(0x00000000, GAPSPCI_BBA_CONFIG+0x30); + ctrl_outb(0x00, GAPSPCI_BBA_CONFIG+0x3c); + ctrl_outb(0xf0, GAPSPCI_BBA_CONFIG+0x0d); + ctrl_outw(0x0006, GAPSPCI_BBA_CONFIG+0x04); + ctrl_outl(0x00002001, GAPSPCI_BBA_CONFIG+0x10); + ctrl_outl(0x01000000, GAPSPCI_BBA_CONFIG+0x14); return 0; } diff --git a/arch/sh/drivers/pci/ops-rts7751r2d.c b/arch/sh/drivers/pci/ops-rts7751r2d.c index ec8430c8d2d..b3fa3e2ef18 100644 --- a/arch/sh/drivers/pci/ops-rts7751r2d.c +++ b/arch/sh/drivers/pci/ops-rts7751r2d.c @@ -33,7 +33,7 @@ int __init pcibios_map_platform_irq(struct pci_dev *pdev, u8 slot, u8 pin) static struct resource sh7751_io_resource = { .name = "SH7751_IO", .start = 0x4000, - .end = 0x4000 + SH7751_PCI_IO_SIZE - 1, + .end = SH7751_PCI_IO_SIZE - 1, .flags = IORESOURCE_IO }; @@ -68,6 +68,7 @@ static struct sh4_pci_address_map sh7751_pci_map = { int __init pcibios_init_platform(void) { + __set_io_port_base(SH7751_PCI_IO_BASE); return sh7751_pcic_init(&sh7751_pci_map); } diff --git a/arch/sh/drivers/pci/pci-sh4.h b/arch/sh/drivers/pci/pci-sh4.h index 4925c79ea95..07e29506080 100644 --- a/arch/sh/drivers/pci/pci-sh4.h +++ b/arch/sh/drivers/pci/pci-sh4.h @@ -172,11 +172,11 @@ struct sh4_pci_address_map { static inline void pci_write_reg(unsigned long val, unsigned long reg) { - outl(val, PCI_REG(reg)); + ctrl_outl(val, PCI_REG(reg)); } static inline unsigned long pci_read_reg(unsigned long reg) { - return inl(PCI_REG(reg)); + return ctrl_inl(PCI_REG(reg)); } #endif /* __PCI_SH4_H */ diff --git a/arch/sh/drivers/pci/pci-sh7751.c b/arch/sh/drivers/pci/pci-sh7751.c index 1aca7fe5783..3065eb184f0 100644 --- a/arch/sh/drivers/pci/pci-sh7751.c +++ b/arch/sh/drivers/pci/pci-sh7751.c @@ -58,7 +58,7 @@ static int __init __area_sdram_check(unsigned int area) { u32 word; - word = inl(SH7751_BCR1); + word = ctrl_inl(SH7751_BCR1); /* check BCR for SDRAM in area */ if (((word >> area) & 1) == 0) { printk("PCI: Area %d is not configured for SDRAM. BCR1=0x%x\n", @@ -67,7 +67,7 @@ static int __init __area_sdram_check(unsigned int area) } pci_write_reg(word, SH4_PCIBCR1); - word = (u16)inw(SH7751_BCR2); + word = (u16)ctrl_inw(SH7751_BCR2); /* check BCR2 for 32bit SDRAM interface*/ if (((word >> (area << 1)) & 0x3) != 0x3) { printk("PCI: Area %d is not 32 bit SDRAM. BCR2=0x%x\n", @@ -85,9 +85,9 @@ int __init sh7751_pcic_init(struct sh4_pci_address_map *map) u32 word; /* Set the BCR's to enable PCI access */ - reg = inl(SH7751_BCR1); + reg = ctrl_inl(SH7751_BCR1); reg |= 0x80000; - outl(reg, SH7751_BCR1); + ctrl_outl(reg, SH7751_BCR1); /* Turn the clocks back on (not done in reset)*/ pci_write_reg(0, SH4_PCICLKR); @@ -179,13 +179,13 @@ int __init sh7751_pcic_init(struct sh4_pci_address_map *map) return 0; /* configure the wait control registers */ - word = inl(SH7751_WCR1); + word = ctrl_inl(SH7751_WCR1); pci_write_reg(word, SH4_PCIWCR1); - word = inl(SH7751_WCR2); + word = ctrl_inl(SH7751_WCR2); pci_write_reg(word, SH4_PCIWCR2); - word = inl(SH7751_WCR3); + word = ctrl_inl(SH7751_WCR3); pci_write_reg(word, SH4_PCIWCR3); - word = inl(SH7751_MCR); + word = ctrl_inl(SH7751_MCR); pci_write_reg(word, SH4_PCIMCR); /* NOTE: I'm ignoring the PCI error IRQs for now.. diff --git a/arch/sh/drivers/pci/pci-sh7780.c b/arch/sh/drivers/pci/pci-sh7780.c index 7d797f4de5e..b2a2bfa3c1b 100644 --- a/arch/sh/drivers/pci/pci-sh7780.c +++ b/arch/sh/drivers/pci/pci-sh7780.c @@ -52,7 +52,7 @@ static int __init sh7780_pci_init(void) pr_debug("PCI: Starting intialization.\n"); - outl(0x00000001, SH7780_PCI_VCR2); /* Enable PCIC */ + ctrl_outl(0x00000001, SH7780_PCI_VCR2); /* Enable PCIC */ /* check for SH7780/SH7780R hardware */ id = pci_read_reg(SH7780_PCIVID); diff --git a/arch/sh/kernel/Makefile_32 b/arch/sh/kernel/Makefile_32 index c8928983105..62bf373266f 100644 --- a/arch/sh/kernel/Makefile_32 +++ b/arch/sh/kernel/Makefile_32 @@ -22,5 +22,6 @@ obj-$(CONFIG_CRASH_DUMP) += crash_dump.o obj-$(CONFIG_PM) += pm.o obj-$(CONFIG_STACKTRACE) += stacktrace.o obj-$(CONFIG_BINFMT_ELF) += dump_task.o +obj-$(CONFIG_IO_TRAPPED) += io_trapped.o EXTRA_CFLAGS += -Werror diff --git a/arch/sh/kernel/Makefile_64 b/arch/sh/kernel/Makefile_64 index 1ef21cc087f..e01283d49cb 100644 --- a/arch/sh/kernel/Makefile_64 +++ b/arch/sh/kernel/Makefile_64 @@ -18,5 +18,6 @@ obj-$(CONFIG_CRASH_DUMP) += crash_dump.o obj-$(CONFIG_PM) += pm.o obj-$(CONFIG_STACKTRACE) += stacktrace.o obj-$(CONFIG_BINFMT_ELF) += dump_task.o +obj-$(CONFIG_IO_TRAPPED) += io_trapped.o EXTRA_CFLAGS += -Werror diff --git a/arch/sh/kernel/cpu/irq/Makefile b/arch/sh/kernel/cpu/irq/Makefile index cc1836e47a5..462a8f6dfee 100644 --- a/arch/sh/kernel/cpu/irq/Makefile +++ b/arch/sh/kernel/cpu/irq/Makefile @@ -6,4 +6,3 @@ obj-y += intc.o obj-$(CONFIG_SUPERH32) += imask.o obj-$(CONFIG_CPU_SH5) += intc-sh5.o obj-$(CONFIG_CPU_HAS_IPR_IRQ) += ipr.o -obj-$(CONFIG_CPU_HAS_MASKREG_IRQ) += maskreg.o diff --git a/arch/sh/kernel/cpu/irq/intc-sh5.c b/arch/sh/kernel/cpu/irq/intc-sh5.c index 43ee7a9a4f0..d6e0e2bdaad 100644 --- a/arch/sh/kernel/cpu/irq/intc-sh5.c +++ b/arch/sh/kernel/cpu/irq/intc-sh5.c @@ -75,21 +75,6 @@ int intc_evt_to_irq[(0xE20/0x20)+1] = { -1, -1 /* 0xE00 - 0xE20 */ }; -/* - * Opposite mapper. - */ -static int IRQ_to_vectorN[NR_INTC_IRQS] = { - 0x12, 0x15, 0x18, 0x1B, 0x40, 0x41, 0x42, 0x43, /* 0- 7 */ - -1, -1, -1, -1, 0x50, 0x51, 0x52, 0x53, /* 8-15 */ - 0x54, 0x55, 0x32, 0x33, 0x34, 0x35, 0x36, -1, /* 16-23 */ - -1, -1, -1, -1, -1, -1, -1, -1, /* 24-31 */ - 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x38, /* 32-39 */ - 0x39, 0x3A, 0x3B, -1, -1, -1, -1, -1, /* 40-47 */ - -1, -1, -1, -1, -1, -1, -1, -1, /* 48-55 */ - -1, -1, -1, -1, -1, -1, -1, 0x2B, /* 56-63 */ - -}; - static unsigned long intc_virt; static unsigned int startup_intc_irq(unsigned int irq); @@ -176,6 +161,18 @@ void make_intc_irq(unsigned int irq) } #if defined(CONFIG_PROC_FS) && defined(CONFIG_SYSCTL) +static int IRQ_to_vectorN[NR_INTC_IRQS] = { + 0x12, 0x15, 0x18, 0x1B, 0x40, 0x41, 0x42, 0x43, /* 0- 7 */ + -1, -1, -1, -1, 0x50, 0x51, 0x52, 0x53, /* 8-15 */ + 0x54, 0x55, 0x32, 0x33, 0x34, 0x35, 0x36, -1, /* 16-23 */ + -1, -1, -1, -1, -1, -1, -1, -1, /* 24-31 */ + 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x38, /* 32-39 */ + 0x39, 0x3A, 0x3B, -1, -1, -1, -1, -1, /* 40-47 */ + -1, -1, -1, -1, -1, -1, -1, -1, /* 48-55 */ + -1, -1, -1, -1, -1, -1, -1, 0x2B, /* 56-63 */ + +}; + int intc_irq_describe(char* p, int irq) { if (irq < NR_INTC_IRQS) diff --git a/arch/sh/kernel/cpu/irq/maskreg.c b/arch/sh/kernel/cpu/irq/maskreg.c deleted file mode 100644 index 978992e367a..00000000000 --- a/arch/sh/kernel/cpu/irq/maskreg.c +++ /dev/null @@ -1,93 +0,0 @@ -/* - * Interrupt handling for Simple external interrupt mask register - * - * Copyright (C) 2001 A&D Co., Ltd. <http://www.aandd.co.jp> - * - * This is for the machine which have single 16 bit register - * for masking external IRQ individually. - * Each bit of the register is for masking each interrupt. - * - * This file may be copied or modified under the terms of the GNU - * General Public License. See linux/COPYING for more information. - */ -#include <linux/kernel.h> -#include <linux/init.h> -#include <linux/irq.h> -#include <asm/system.h> -#include <asm/io.h> - -/* address of external interrupt mask register */ -unsigned long irq_mask_register; - -/* forward declaration */ -static unsigned int startup_maskreg_irq(unsigned int irq); -static void shutdown_maskreg_irq(unsigned int irq); -static void enable_maskreg_irq(unsigned int irq); -static void disable_maskreg_irq(unsigned int irq); -static void mask_and_ack_maskreg(unsigned int); -static void end_maskreg_irq(unsigned int irq); - -/* hw_interrupt_type */ -static struct hw_interrupt_type maskreg_irq_type = { - .typename = "Mask Register", - .startup = startup_maskreg_irq, - .shutdown = shutdown_maskreg_irq, - .enable = enable_maskreg_irq, - .disable = disable_maskreg_irq, - .ack = mask_and_ack_maskreg, - .end = end_maskreg_irq -}; - -/* actual implementation */ -static unsigned int startup_maskreg_irq(unsigned int irq) -{ - enable_maskreg_irq(irq); - return 0; /* never anything pending */ -} - -static void shutdown_maskreg_irq(unsigned int irq) -{ - disable_maskreg_irq(irq); -} - -static void disable_maskreg_irq(unsigned int irq) -{ - unsigned short val, mask = 0x01 << irq; - - BUG_ON(!irq_mask_register); - - /* Set "irq"th bit */ - val = ctrl_inw(irq_mask_register); - val |= mask; - ctrl_outw(val, irq_mask_register); -} - -static void enable_maskreg_irq(unsigned int irq) -{ - unsigned short val, mask = ~(0x01 << irq); - - BUG_ON(!irq_mask_register); - - /* Clear "irq"th bit */ - val = ctrl_inw(irq_mask_register); - val &= mask; - ctrl_outw(val, irq_mask_register); -} - -static void mask_and_ack_maskreg(unsigned int irq) -{ - disable_maskreg_irq(irq); -} - -static void end_maskreg_irq(unsigned int irq) -{ - if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS))) - enable_maskreg_irq(irq); -} - -void make_maskreg_irq(unsigned int irq) -{ - disable_irq_nosync(irq); - irq_desc[irq].handler = &maskreg_irq_type; - disable_maskreg_irq(irq); -} diff --git a/arch/sh/kernel/cpu/sh4/probe.c b/arch/sh/kernel/cpu/sh4/probe.c index f2b9238cda0..9e89984c4f1 100644 --- a/arch/sh/kernel/cpu/sh4/probe.c +++ b/arch/sh/kernel/cpu/sh4/probe.c @@ -126,12 +126,18 @@ int __init detect_cpu_and_cache_system(void) CPU_HAS_LLSC; break; case 0x3008: - if (prr == 0xa0) { + if (prr == 0xa0 || prr == 0xa1) { boot_cpu_data.type = CPU_SH7722; boot_cpu_data.icache.ways = 4; boot_cpu_data.dcache.ways = 4; boot_cpu_data.flags |= CPU_HAS_LLSC; } + else if (prr == 0x70) { + boot_cpu_data.type = CPU_SH7366; + boot_cpu_data.icache.ways = 4; + boot_cpu_data.dcache.ways = 4; + boot_cpu_data.flags |= CPU_HAS_LLSC; + } break; case 0x4000: /* 1st cut */ case 0x4001: /* 2nd cut */ diff --git a/arch/sh/kernel/cpu/sh4a/Makefile b/arch/sh/kernel/cpu/sh4a/Makefile index 08ac6387bf1..5d890ac8e79 100644 --- a/arch/sh/kernel/cpu/sh4a/Makefile +++ b/arch/sh/kernel/cpu/sh4a/Makefile @@ -9,6 +9,7 @@ obj-$(CONFIG_CPU_SUBTYPE_SH7780) += setup-sh7780.o obj-$(CONFIG_CPU_SUBTYPE_SH7785) += setup-sh7785.o obj-$(CONFIG_CPU_SUBTYPE_SH7343) += setup-sh7343.o obj-$(CONFIG_CPU_SUBTYPE_SH7722) += setup-sh7722.o +obj-$(CONFIG_CPU_SUBTYPE_SH7366) += setup-sh7366.o obj-$(CONFIG_CPU_SUBTYPE_SHX3) += setup-shx3.o # SMP setup @@ -21,6 +22,7 @@ clock-$(CONFIG_CPU_SUBTYPE_SH7780) := clock-sh7780.o clock-$(CONFIG_CPU_SUBTYPE_SH7785) := clock-sh7785.o clock-$(CONFIG_CPU_SUBTYPE_SH7343) := clock-sh7343.o clock-$(CONFIG_CPU_SUBTYPE_SH7722) := clock-sh7722.o +clock-$(CONFIG_CPU_SUBTYPE_SH7366) := clock-sh7722.o clock-$(CONFIG_CPU_SUBTYPE_SHX3) := clock-shx3.o obj-y += $(clock-y) diff --git a/arch/sh/kernel/cpu/sh4a/clock-sh7722.c b/arch/sh/kernel/cpu/sh4a/clock-sh7722.c index a0fd8bb21f7..299138ebe16 100644 --- a/arch/sh/kernel/cpu/sh4a/clock-sh7722.c +++ b/arch/sh/kernel/cpu/sh4a/clock-sh7722.c @@ -1,7 +1,7 @@ /* * arch/sh/kernel/cpu/sh4a/clock-sh7722.c * - * SH7722 support for the clock framework + * SH7722 & SH7366 support for the clock framework * * Copyright (c) 2006-2007 Nomad Global Solutions Inc * Based on code for sh7343 by Paul Mundt @@ -417,15 +417,19 @@ static int sh7722_siu_which(struct clk *clk) return 0; if (!strcmp(clk->name, "siu_b_clk")) return 1; +#if defined(CONFIG_CPU_SUBTYPE_SH7722) if (!strcmp(clk->name, "irda_clk")) return 2; +#endif return -EINVAL; } static unsigned long sh7722_siu_regs[] = { [0] = SCLKACR, [1] = SCLKBCR, +#if defined(CONFIG_CPU_SUBTYPE_SH7722) [2] = IrDACLKCR, +#endif }; static int sh7722_siu_start_stop(struct clk *clk, int enable) @@ -571,10 +575,12 @@ static struct clk sh7722_siu_b_clock = { .ops = &sh7722_siu_clk_ops, }; +#if defined(CONFIG_CPU_SUBTYPE_SH7722) static struct clk sh7722_irda_clock = { .name = "irda_clk", .ops = &sh7722_siu_clk_ops, }; +#endif static struct clk sh7722_video_clock = { .name = "video_clk", @@ -588,7 +594,9 @@ static struct clk *sh7722_clocks[] = { &sh7722_sdram_clock, &sh7722_siu_a_clock, &sh7722_siu_b_clock, +#if defined(CONFIG_CPU_SUBTYPE_SH7722) &sh7722_irda_clock, +#endif &sh7722_video_clock, }; diff --git a/arch/sh/kernel/cpu/sh4a/setup-sh7366.c b/arch/sh/kernel/cpu/sh4a/setup-sh7366.c new file mode 100644 index 00000000000..967e8b69a2f --- /dev/null +++ b/arch/sh/kernel/cpu/sh4a/setup-sh7366.c @@ -0,0 +1,177 @@ +/* + * SH7366 Setup + * + * Copyright (C) 2008 Renesas Solutions + * + * Based on linux/arch/sh/kernel/cpu/sh4a/setup-sh7722.c + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + */ +#include <linux/platform_device.h> +#include <linux/init.h> +#include <linux/serial.h> +#include <asm/sci.h> + +static struct plat_sci_port sci_platform_data[] = { + { + .mapbase = 0xffe00000, + .flags = UPF_BOOT_AUTOCONF, + .type = PORT_SCIF, + .irqs = { 80, 80, 80, 80 }, + }, { + .flags = 0, + } +}; + +static struct platform_device sci_device = { + .name = "sh-sci", + .id = -1, + .dev = { + .platform_data = sci_platform_data, + }, +}; + +static struct platform_device *sh7366_devices[] __initdata = { + &sci_device, +}; + +static int __init sh7366_devices_setup(void) +{ + return platform_add_devices(sh7366_devices, + ARRAY_SIZE(sh7366_devices)); +} +__initcall(sh7366_devices_setup); + +enum { + UNUSED=0, + + /* interrupt sources */ + IRQ0, IRQ1, IRQ2, IRQ3, IRQ4, IRQ5, IRQ6, IRQ7, + ICB, + DMAC0, DMAC1, DMAC2, DMAC3, + VIO_CEUI, VIO_BEUI, VIO_VEUI, VOU, + MFI, VPU, USB, + MMC_MMC1I, MMC_MMC2I, MMC_MMC3I, + DMAC4, DMAC5, DMAC_DADERR, + SCIF, SCIFA1, SCIFA2, + DENC, MSIOF, + FLCTL_FLSTEI, FLCTL_FLENDI, FLCTL_FLTREQ0I, FLCTL_FLTREQ1I, + I2C_ALI, I2C_TACKI, I2C_WAITI, I2C_DTEI, + SDHI0, SDHI1, SDHI2, SDHI3, + CMT, TSIF, SIU, + TMU0, TMU1, TMU2, + VEU2, LCDC, + + /* interrupt groups */ + + DMAC0123, VIOVOU, MMC, DMAC45, FLCTL, I2C, SDHI, +}; + +static struct intc_vect vectors[] __initdata = { + INTC_VECT(IRQ0, 0x600), INTC_VECT(IRQ1, 0x620), + INTC_VECT(IRQ2, 0x640), INTC_VECT(IRQ3, 0x660), + INTC_VECT(IRQ4, 0x680), INTC_VECT(IRQ5, 0x6a0), + INTC_VECT(IRQ6, 0x6c0), INTC_VECT(IRQ7, 0x6e0), + INTC_VECT(ICB, 0x700), + INTC_VECT(DMAC0, 0x800), INTC_VECT(DMAC1, 0x820), + INTC_VECT(DMAC2, 0x840), INTC_VECT(DMAC3, 0x860), + INTC_VECT(VIO_CEUI, 0x880), INTC_VECT(VIO_BEUI, 0x8a0), + INTC_VECT(VIO_VEUI, 0x8c0), INTC_VECT(VOU, 0x8e0), + INTC_VECT(MFI, 0x900), INTC_VECT(VPU, 0x980), INTC_VECT(USB, 0xa20), + INTC_VECT(MMC_MMC1I, 0xb00), INTC_VECT(MMC_MMC2I, 0xb20), + INTC_VECT(MMC_MMC3I, 0xb40), + INTC_VECT(DMAC4, 0xb80), INTC_VECT(DMAC5, 0xba0), + INTC_VECT(DMAC_DADERR, 0xbc0), + INTC_VECT(SCIF, 0xc00), INTC_VECT(SCIFA1, 0xc20), + INTC_VECT(SCIFA2, 0xc40), + INTC_VECT(DENC, 0xc60), INTC_VECT(MSIOF, 0xc80), + INTC_VECT(FLCTL_FLSTEI, 0xd80), INTC_VECT(FLCTL_FLENDI, 0xda0), + INTC_VECT(FLCTL_FLTREQ0I, 0xdc0), INTC_VECT(FLCTL_FLTREQ1I, 0xde0), + INTC_VECT(I2C_ALI, 0xe00), INTC_VECT(I2C_TACKI, 0xe20), + INTC_VECT(I2C_WAITI, 0xe40), INTC_VECT(I2C_DTEI, 0xe60), + INTC_VECT(SDHI0, 0xe80), INTC_VECT(SDHI1, 0xea0), + INTC_VECT(SDHI2, 0xec0), INTC_VECT(SDHI3, 0xee0), + INTC_VECT(CMT, 0xf00), INTC_VECT(TSIF, 0xf20), + INTC_VECT(SIU, 0xf80), + INTC_VECT(TMU0, 0x400), INTC_VECT(TMU1, 0x420), + INTC_VECT(TMU2, 0x440), + INTC_VECT(VEU2, 0x580), INTC_VECT(LCDC, 0x580), +}; + +static struct intc_group groups[] __initdata = { + INTC_GROUP(DMAC0123, DMAC0, DMAC1, DMAC2, DMAC3), + INTC_GROUP(VIOVOU, VIO_CEUI, VIO_BEUI, VIO_VEUI, VOU), + INTC_GROUP(MMC, MMC_MMC1I, MMC_MMC2I, MMC_MMC3I), + INTC_GROUP(DMAC45, DMAC4, DMAC5, DMAC_DADERR), + INTC_GROUP(FLCTL, FLCTL_FLSTEI, FLCTL_FLENDI, + FLCTL_FLTREQ0I, FLCTL_FLTREQ1I), + INTC_GROUP(I2C, I2C_ALI, I2C_TACKI, I2C_WAITI, I2C_DTEI), + INTC_GROUP(SDHI, SDHI0, SDHI1, SDHI2, SDHI3), +}; + +static struct intc_mask_reg mask_registers[] __initdata = { + { 0xa4080080, 0xa40800c0, 8, /* IMR0 / IMCR0 */ + { } }, + { 0xa4080084, 0xa40800c4, 8, /* IMR1 / IMCR1 */ + { VOU, VIO_VEUI, VIO_BEUI, VIO_CEUI, DMAC3, DMAC2, DMAC1, DMAC0 } }, + { 0xa4080088, 0xa40800c8, 8, /* IMR2 / IMCR2 */ + { 0, 0, 0, VPU, 0, 0, 0, MFI } }, + { 0xa408008c, 0xa40800cc, 8, /* IMR3 / IMCR3 */ + { 0, 0, 0, ICB } }, + { 0xa4080090, 0xa40800d0, 8, /* IMR4 / IMCR4 */ + { 0, TMU2, TMU1, TMU0, VEU2, 0, 0, LCDC } }, + { 0xa4080094, 0xa40800d4, 8, /* IMR5 / IMCR5 */ + { 0, DMAC_DADERR, DMAC5, DMAC4, DENC, SCIFA2, SCIFA1, SCIF } }, + { 0xa4080098, 0xa40800d8, 8, /* IMR6 / IMCR6 */ + { 0, 0, 0, 0, 0, 0, 0, MSIOF } }, + { 0xa408009c, 0xa40800dc, 8, /* IMR7 / IMCR7 */ + { I2C_DTEI, I2C_WAITI, I2C_TACKI, I2C_ALI, + FLCTL_FLTREQ1I, FLCTL_FLTREQ0I, FLCTL_FLENDI, FLCTL_FLSTEI } }, + { 0xa40800a0, 0xa40800e0, 8, /* IMR8 / IMCR8 */ + { SDHI3, SDHI2, SDHI1, SDHI0, 0, 0, 0, SIU } }, + { 0xa40800a4, 0xa40800e4, 8, /* IMR9 / IMCR9 */ + { 0, 0, 0, CMT, 0, USB, } }, + { 0xa40800a8, 0xa40800e8, 8, /* IMR10 / IMCR10 */ + { 0, MMC_MMC3I, MMC_MMC2I, MMC_MMC1I } }, + { 0xa40800ac, 0xa40800ec, 8, /* IMR11 / IMCR11 */ + { 0, 0, 0, 0, 0, 0, 0, TSIF } }, + { 0xa4140044, 0xa4140064, 8, /* INTMSK00 / INTMSKCLR00 */ + { IRQ0, IRQ1, IRQ2, IRQ3, IRQ4, IRQ5, IRQ6, IRQ7 } }, +}; + +static struct intc_prio_reg prio_registers[] __initdata = { + { 0xa4080000, 0, 16, 4, /* IPRA */ { TMU0, TMU1, TMU2 } }, + { 0xa4080004, 0, 16, 4, /* IPRB */ { VEU2, LCDC, ICB } }, + { 0xa4080008, 0, 16, 4, /* IPRC */ { } }, + { 0xa408000c, 0, 16, 4, /* IPRD */ { } }, + { 0xa4080010, 0, 16, 4, /* IPRE */ { DMAC0123, VIOVOU, MFI, VPU } }, + { 0xa4080014, 0, 16, 4, /* IPRF */ { 0, DMAC45, USB, CMT } }, + { 0xa4080018, 0, 16, 4, /* IPRG */ { SCIF, SCIFA1, SCIFA2, DENC } }, + { 0xa408001c, 0, 16, 4, /* IPRH */ { MSIOF, 0, FLCTL, I2C } }, + { 0xa4080020, 0, 16, 4, /* IPRI */ { 0, 0, TSIF, } }, + { 0xa4080024, 0, 16, 4, /* IPRJ */ { 0, 0, SIU } }, + { 0xa4080028, 0, 16, 4, /* IPRK */ { 0, MMC, 0, SDHI } }, + { 0xa408002c, 0, 16, 4, /* IPRL */ { } }, + { 0xa4140010, 0, 32, 4, /* INTPRI00 */ + { IRQ0, IRQ1, IRQ2, IRQ3, IRQ4, IRQ5, IRQ6, IRQ7 } }, +}; + +static struct intc_sense_reg sense_registers[] __initdata = { + { 0xa414001c, 16, 2, /* ICR1 */ + { IRQ0, IRQ1, IRQ2, IRQ3, IRQ4, IRQ5, IRQ6, IRQ7 } }, +}; + +static DECLARE_INTC_DESC(intc_desc, "sh7366", vectors, groups, + mask_registers, prio_registers, sense_registers); + +void __init plat_irq_setup(void) +{ + register_intc_controller(&intc_desc); +} + +void __init plat_mem_setup(void) +{ + /* TODO: Register Node 1 */ +} diff --git a/arch/sh/kernel/cpu/sh5/probe.c b/arch/sh/kernel/cpu/sh5/probe.c index 15d167fd0ae..31f8cb0f637 100644 --- a/arch/sh/kernel/cpu/sh5/probe.c +++ b/arch/sh/kernel/cpu/sh5/probe.c @@ -20,19 +20,18 @@ int __init detect_cpu_and_cache_system(void) { unsigned long long cir; - /* Do peeks in real mode to avoid having to set up a mapping for the - WPC registers. On SH5-101 cut2, such a mapping would be exposed to - an address translation erratum which would make it hard to set up - correctly. */ + /* + * Do peeks in real mode to avoid having to set up a mapping for + * the WPC registers. On SH5-101 cut2, such a mapping would be + * exposed to an address translation erratum which would make it + * hard to set up correctly. + */ cir = peek_real_address_q(0x0d000008); - if ((cir & 0xffff) == 0x5103) { + if ((cir & 0xffff) == 0x5103) boot_cpu_data.type = CPU_SH5_103; - } else if (((cir >> 32) & 0xffff) == 0x51e2) { + else if (((cir >> 32) & 0xffff) == 0x51e2) /* CPU.VCR aliased at CIR address on SH5-101 */ boot_cpu_data.type = CPU_SH5_101; - } else { - boot_cpu_data.type = CPU_SH_NONE; - } /* * First, setup some sane values for the I-cache. @@ -40,37 +39,33 @@ int __init detect_cpu_and_cache_system(void) boot_cpu_data.icache.ways = 4; boot_cpu_data.icache.sets = 256; boot_cpu_data.icache.linesz = L1_CACHE_BYTES; + boot_cpu_data.icache.way_incr = (1 << 13); + boot_cpu_data.icache.entry_shift = 5; + boot_cpu_data.icache.way_size = boot_cpu_data.icache.sets * + boot_cpu_data.icache.linesz; + boot_cpu_data.icache.entry_mask = 0x1fe0; + boot_cpu_data.icache.flags = 0; -#if 0 /* - * FIXME: This can probably be cleaned up a bit as well.. for example, - * do we really need the way shift _and_ the way_step_shift ?? Judging - * by the existing code, I would guess no.. is there any valid reason - * why we need to be tracking this around? + * Next, setup some sane values for the D-cache. + * + * On the SH5, these are pretty consistent with the I-cache settings, + * so we just copy over the existing definitions.. these can be fixed + * up later, especially if we add runtime CPU probing. + * + * Though in the meantime it saves us from having to duplicate all of + * the above definitions.. */ - boot_cpu_data.icache.way_shift = 13; - boot_cpu_data.icache.entry_shift = 5; - boot_cpu_data.icache.set_shift = 4; - boot_cpu_data.icache.way_step_shift = 16; - boot_cpu_data.icache.asid_shift = 2; + boot_cpu_data.dcache = boot_cpu_data.icache; /* - * way offset = cache size / associativity, so just don't factor in - * associativity in the first place.. + * Setup any cache-related flags here */ - boot_cpu_data.icache.way_ofs = boot_cpu_data.icache.sets * - boot_cpu_data.icache.linesz; - - boot_cpu_data.icache.asid_mask = 0x3fc; - boot_cpu_data.icache.idx_mask = 0x1fe0; - boot_cpu_data.icache.epn_mask = 0xffffe000; +#if defined(CONFIG_CACHE_WRITETHROUGH) + set_bit(SH_CACHE_MODE_WT, &(boot_cpu_data.dcache.flags)); +#elif defined(CONFIG_CACHE_WRITEBACK) + set_bit(SH_CACHE_MODE_WB, &(boot_cpu_data.dcache.flags)); #endif - boot_cpu_data.icache.flags = 0; - - /* A trivial starting point.. */ - memcpy(&boot_cpu_data.dcache, - &boot_cpu_data.icache, sizeof(struct cache_info)); - return 0; } diff --git a/arch/sh/kernel/io.c b/arch/sh/kernel/io.c index 71c9fde2fd9..2b899122990 100644 --- a/arch/sh/kernel/io.c +++ b/arch/sh/kernel/io.c @@ -63,7 +63,13 @@ EXPORT_SYMBOL(memset_io); void __iomem *ioport_map(unsigned long port, unsigned int nr) { - return sh_mv.mv_ioport_map(port, nr); + void __iomem *ret; + + ret = __ioport_map_trapped(port, nr); + if (ret) + return ret; + + return __ioport_map(port, nr); } EXPORT_SYMBOL(ioport_map); diff --git a/arch/sh/kernel/io_generic.c b/arch/sh/kernel/io_generic.c index 771ea423044..db769449f5a 100644 --- a/arch/sh/kernel/io_generic.c +++ b/arch/sh/kernel/io_generic.c @@ -33,17 +33,17 @@ static inline void delay(void) u8 generic_inb(unsigned long port) { - return ctrl_inb((unsigned long __force)ioport_map(port, 1)); + return ctrl_inb((unsigned long __force)__ioport_map(port, 1)); } u16 generic_inw(unsigned long port) { - return ctrl_inw((unsigned long __force)ioport_map(port, 2)); + return ctrl_inw((unsigned long __force)__ioport_map(port, 2)); } u32 generic_inl(unsigned long port) { - return ctrl_inl((unsigned long __force)ioport_map(port, 4)); + return ctrl_inl((unsigned long __force)__ioport_map(port, 4)); } u8 generic_inb_p(unsigned long port) @@ -81,7 +81,7 @@ void generic_insb(unsigned long port, void *dst, unsigned long count) volatile u8 *port_addr; u8 *buf = dst; - port_addr = (volatile u8 *)ioport_map(port, 1); + port_addr = (volatile u8 *)__ioport_map(port, 1); while (count--) *buf++ = *port_addr; } @@ -91,7 +91,7 @@ void generic_insw(unsigned long port, void *dst, unsigned long count) volatile u16 *port_addr; u16 *buf = dst; - port_addr = (volatile u16 *)ioport_map(port, 2); + port_addr = (volatile u16 *)__ioport_map(port, 2); while (count--) *buf++ = *port_addr; @@ -103,7 +103,7 @@ void generic_insl(unsigned long port, void *dst, unsigned long count) volatile u32 *port_addr; u32 *buf = dst; - port_addr = (volatile u32 *)ioport_map(port, 4); + port_addr = (volatile u32 *)__ioport_map(port, 4); while (count--) *buf++ = *port_addr; @@ -112,17 +112,17 @@ void generic_insl(unsigned long port, void *dst, unsigned long count) void generic_outb(u8 b, unsigned long port) { - ctrl_outb(b, (unsigned long __force)ioport_map(port, 1)); + ctrl_outb(b, (unsigned long __force)__ioport_map(port, 1)); } void generic_outw(u16 b, unsigned long port) { - ctrl_outw(b, (unsigned long __force)ioport_map(port, 2)); + ctrl_outw(b, (unsigned long __force)__ioport_map(port, 2)); } void generic_outl(u32 b, unsigned long port) { - ctrl_outl(b, (unsigned long __force)ioport_map(port, 4)); + ctrl_outl(b, (unsigned long __force)__ioport_map(port, 4)); } void generic_outb_p(u8 b, unsigned long port) @@ -153,7 +153,7 @@ void generic_outsb(unsigned long port, const void *src, unsigned long count) volatile u8 *port_addr; const u8 *buf = src; - port_addr = (volatile u8 __force *)ioport_map(port, 1); + port_addr = (volatile u8 __force *)__ioport_map(port, 1); while (count--) *port_addr = *buf++; @@ -164,7 +164,7 @@ void generic_outsw(unsigned long port, const void *src, unsigned long count) volatile u16 *port_addr; const u16 *buf = src; - port_addr = (volatile u16 __force *)ioport_map(port, 2); + port_addr = (volatile u16 __force *)__ioport_map(port, 2); while (count--) *port_addr = *buf++; @@ -177,7 +177,7 @@ void generic_outsl(unsigned long port, const void *src, unsigned long count) volatile u32 *port_addr; const u32 *buf = src; - port_addr = (volatile u32 __force *)ioport_map(port, 4); + port_addr = (volatile u32 __force *)__ioport_map(port, 4); while (count--) *port_addr = *buf++; diff --git a/arch/sh/kernel/io_trapped.c b/arch/sh/kernel/io_trapped.c new file mode 100644 index 00000000000..86a665d9220 --- /dev/null +++ b/arch/sh/kernel/io_trapped.c @@ -0,0 +1,276 @@ +/* + * Trapped io support + * + * Copyright (C) 2008 Magnus Damm + * + * Intercept io operations by trapping. + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + */ +#include <linux/kernel.h> +#include <linux/mm.h> +#include <linux/bitops.h> +#include <linux/vmalloc.h> +#include <linux/module.h> +#include <asm/system.h> +#include <asm/mmu_context.h> +#include <asm/uaccess.h> +#include <asm/io.h> +#include <asm/io_trapped.h> + +#define TRAPPED_PAGES_MAX 16 + +#ifdef CONFIG_HAS_IOPORT +LIST_HEAD(trapped_io); +EXPORT_SYMBOL_GPL(trapped_io); +#endif +#ifdef CONFIG_HAS_IOMEM +LIST_HEAD(trapped_mem); +EXPORT_SYMBOL_GPL(trapped_mem); +#endif +static DEFINE_SPINLOCK(trapped_lock); + +int __init register_trapped_io(struct trapped_io *tiop) +{ + struct resource *res; + unsigned long len = 0, flags = 0; + struct page *pages[TRAPPED_PAGES_MAX]; + int k, n; + + /* structure must be page aligned */ + if ((unsigned long)tiop & (PAGE_SIZE - 1)) + goto bad; + + for (k = 0; k < tiop->num_resources; k++) { + res = tiop->resource + k; + len += roundup((res->end - res->start) + 1, PAGE_SIZE); + flags |= res->flags; + } + + /* support IORESOURCE_IO _or_ MEM, not both */ + if (hweight_long(flags) != 1) + goto bad; + + n = len >> PAGE_SHIFT; + + if (n >= TRAPPED_PAGES_MAX) + goto bad; + + for (k = 0; k < n; k++) + pages[k] = virt_to_page(tiop); + + tiop->virt_base = vmap(pages, n, VM_MAP, PAGE_NONE); + if (!tiop->virt_base) + goto bad; + + len = 0; + for (k = 0; k < tiop->num_resources; k++) { + res = tiop->resource + k; + pr_info("trapped io 0x%08lx overrides %s 0x%08lx\n", + (unsigned long)(tiop->virt_base + len), + res->flags & IORESOURCE_IO ? "io" : "mmio", + (unsigned long)res->start); + len += roundup((res->end - res->start) + 1, PAGE_SIZE); + } + + tiop->magic = IO_TRAPPED_MAGIC; + INIT_LIST_HEAD(&tiop->list); + spin_lock_irq(&trapped_lock); + if (flags & IORESOURCE_IO) + list_add(&tiop->list, &trapped_io); + if (flags & IORESOURCE_MEM) + list_add(&tiop->list, &trapped_mem); + spin_unlock_irq(&trapped_lock); + + return 0; + bad: + pr_warning("unable to install trapped io filter\n"); + return -1; +} +EXPORT_SYMBOL_GPL(register_trapped_io); + +void __iomem *match_trapped_io_handler(struct list_head *list, + unsigned long offset, + unsigned long size) +{ + unsigned long voffs; + struct trapped_io *tiop; + struct resource *res; + int k, len; + + spin_lock_irq(&trapped_lock); + list_for_each_entry(tiop, list, list) { + voffs = 0; + for (k = 0; k < tiop->num_resources; k++) { + res = tiop->resource + k; + if (res->start == offset) { + spin_unlock_irq(&trapped_lock); + return tiop->virt_base + voffs; + } + + len = (res->end - res->start) + 1; + voffs += roundup(len, PAGE_SIZE); + } + } + spin_unlock_irq(&trapped_lock); + return NULL; +} +EXPORT_SYMBOL_GPL(match_trapped_io_handler); + +static struct trapped_io *lookup_tiop(unsigned long address) +{ + pgd_t *pgd_k; + pud_t *pud_k; + pmd_t *pmd_k; + pte_t *pte_k; + pte_t entry; + + pgd_k = swapper_pg_dir + pgd_index(address); + if (!pgd_present(*pgd_k)) + return NULL; + + pud_k = pud_offset(pgd_k, address); + if (!pud_present(*pud_k)) + return NULL; + + pmd_k = pmd_offset(pud_k, address); + if (!pmd_present(*pmd_k)) + return NULL; + + pte_k = pte_offset_kernel(pmd_k, address); + entry = *pte_k; + + return pfn_to_kaddr(pte_pfn(entry)); +} + +static unsigned long lookup_address(struct trapped_io *tiop, + unsigned long address) +{ + struct resource *res; + unsigned long vaddr = (unsigned long)tiop->virt_base; + unsigned long len; + int k; + + for (k = 0; k < tiop->num_resources; k++) { + res = tiop->resource + k; + len = roundup((res->end - res->start) + 1, PAGE_SIZE); + if (address < (vaddr + len)) + return res->start + (address - vaddr); + vaddr += len; + } + return 0; +} + +static unsigned long long copy_word(unsigned long src_addr, int src_len, + unsigned long dst_addr, int dst_len) +{ + unsigned long long tmp = 0; + + switch (src_len) { + case 1: + tmp = ctrl_inb(src_addr); + break; + case 2: + tmp = ctrl_inw(src_addr); + break; + case 4: + tmp = ctrl_inl(src_addr); + break; + case 8: + tmp = ctrl_inq(src_addr); + break; + } + + switch (dst_len) { + case 1: + ctrl_outb(tmp, dst_addr); + break; + case 2: + ctrl_outw(tmp, dst_addr); + break; + case 4: + ctrl_outl(tmp, dst_addr); + break; + case 8: + ctrl_outq(tmp, dst_addr); + break; + } + + return tmp; +} + +static unsigned long from_device(void *dst, const void *src, unsigned long cnt) +{ + struct trapped_io *tiop; + unsigned long src_addr = (unsigned long)src; + unsigned long long tmp; + + pr_debug("trapped io read 0x%08lx (%ld)\n", src_addr, cnt); + tiop = lookup_tiop(src_addr); + WARN_ON(!tiop || (tiop->magic != IO_TRAPPED_MAGIC)); + + src_addr = lookup_address(tiop, src_addr); + if (!src_addr) + return cnt; + + tmp = copy_word(src_addr, + max_t(unsigned long, cnt, + (tiop->minimum_bus_width / 8)), + (unsigned long)dst, cnt); + + pr_debug("trapped io read 0x%08lx -> 0x%08llx\n", src_addr, tmp); + return 0; +} + +static unsigned long to_device(void *dst, const void *src, unsigned long cnt) +{ + struct trapped_io *tiop; + unsigned long dst_addr = (unsigned long)dst; + unsigned long long tmp; + + pr_debug("trapped io write 0x%08lx (%ld)\n", dst_addr, cnt); + tiop = lookup_tiop(dst_addr); + WARN_ON(!tiop || (tiop->magic != IO_TRAPPED_MAGIC)); + + dst_addr = lookup_address(tiop, dst_addr); + if (!dst_addr) + return cnt; + + tmp = copy_word((unsigned long)src, cnt, + dst_addr, max_t(unsigned long, cnt, + (tiop->minimum_bus_width / 8))); + + pr_debug("trapped io write 0x%08lx -> 0x%08llx\n", dst_addr, tmp); + return 0; +} + +static struct mem_access trapped_io_access = { + from_device, + to_device, +}; + +int handle_trapped_io(struct pt_regs *regs, unsigned long address) +{ + mm_segment_t oldfs; + opcode_t instruction; + int tmp; + + if (!lookup_tiop(address)) + return 0; + + WARN_ON(user_mode(regs)); + + oldfs = get_fs(); + set_fs(KERNEL_DS); + if (copy_from_user(&instruction, (void *)(regs->pc), + sizeof(instruction))) { + set_fs(oldfs); + return 0; + } + + tmp = handle_unaligned_access(instruction, regs, &trapped_io_access); + set_fs(oldfs); + return tmp == 0; +} diff --git a/arch/sh/kernel/irq.c b/arch/sh/kernel/irq.c index 0586bc62ad9..9bf19b00696 100644 --- a/arch/sh/kernel/irq.c +++ b/arch/sh/kernel/irq.c @@ -248,9 +248,6 @@ asmlinkage void do_softirq(void) void __init init_IRQ(void) { -#ifdef CONFIG_CPU_HAS_PINT_IRQ - init_IRQ_pint(); -#endif plat_irq_setup(); /* Perform the machine specific initialisation */ diff --git a/arch/sh/kernel/process_64.c b/arch/sh/kernel/process_64.c index cff3b7dc9c5..046999b1d1a 100644 --- a/arch/sh/kernel/process_64.c +++ b/arch/sh/kernel/process_64.c @@ -623,6 +623,7 @@ extern void interruptible_sleep_on(wait_queue_head_t *q); #define mid_sched ((unsigned long) interruptible_sleep_on) +#ifdef CONFIG_FRAME_POINTER static int in_sh64_switch_to(unsigned long pc) { extern char __sh64_switch_to_end; @@ -631,12 +632,10 @@ static int in_sh64_switch_to(unsigned long pc) return (pc >= (unsigned long) sh64_switch_to) && (pc < (unsigned long) &__sh64_switch_to_end); } +#endif unsigned long get_wchan(struct task_struct *p) { - unsigned long schedule_fp; - unsigned long sh64_switch_to_fp; - unsigned long schedule_caller_pc; unsigned long pc; if (!p || p == current || p->state == TASK_RUNNING) @@ -649,6 +648,10 @@ unsigned long get_wchan(struct task_struct *p) #ifdef CONFIG_FRAME_POINTER if (in_sh64_switch_to(pc)) { + unsigned long schedule_fp; + unsigned long sh64_switch_to_fp; + unsigned long schedule_caller_pc; + sh64_switch_to_fp = (long) p->thread.sp; /* r14 is saved at offset 4 in the sh64_switch_to frame */ schedule_fp = *(unsigned long *) (long)(sh64_switch_to_fp + 4); diff --git a/arch/sh/kernel/ptrace_32.c b/arch/sh/kernel/ptrace_32.c index ce0664a58b4..fddb547f3c2 100644 --- a/arch/sh/kernel/ptrace_32.c +++ b/arch/sh/kernel/ptrace_32.c @@ -220,7 +220,7 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data) dp = ((unsigned long) child) + THREAD_SIZE - sizeof(struct pt_dspregs); if (*((int *) (dp - 4)) == SR_FD) { - copy_to_user(addr, (void *) dp, + copy_to_user((void *)addr, (void *) dp, sizeof(struct pt_dspregs)); ret = 0; } @@ -234,7 +234,7 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data) dp = ((unsigned long) child) + THREAD_SIZE - sizeof(struct pt_dspregs); if (*((int *) (dp - 4)) == SR_FD) { - copy_from_user((void *) dp, addr, + copy_from_user((void *) dp, (void *)addr, sizeof(struct pt_dspregs)); ret = 0; } diff --git a/arch/sh/kernel/setup.c b/arch/sh/kernel/setup.c index 18a5baf2cba..ff4f54a47c0 100644 --- a/arch/sh/kernel/setup.c +++ b/arch/sh/kernel/setup.c @@ -333,7 +333,7 @@ static const char *cpu_name[] = { [CPU_SH7343] = "SH7343", [CPU_SH7785] = "SH7785", [CPU_SH7722] = "SH7722", [CPU_SHX3] = "SH-X3", [CPU_SH5_101] = "SH5-101", [CPU_SH5_103] = "SH5-103", - [CPU_SH_NONE] = "Unknown" + [CPU_SH7366] = "SH7366", [CPU_SH_NONE] = "Unknown" }; const char *get_cpu_subtype(struct sh_cpuinfo *c) diff --git a/arch/sh/kernel/syscalls_32.S b/arch/sh/kernel/syscalls_32.S index 719e127a7c0..a46cc3a4114 100644 --- a/arch/sh/kernel/syscalls_32.S +++ b/arch/sh/kernel/syscalls_32.S @@ -338,6 +338,8 @@ ENTRY(sys_call_table) .long sys_epoll_pwait .long sys_utimensat /* 320 */ .long sys_signalfd - .long sys_ni_syscall + .long sys_timerfd_create .long sys_eventfd .long sys_fallocate + .long sys_timerfd_settime /* 325 */ + .long sys_timerfd_gettime diff --git a/arch/sh/kernel/syscalls_64.S b/arch/sh/kernel/syscalls_64.S index 12c7340356a..d5d7843aad9 100644 --- a/arch/sh/kernel/syscalls_64.S +++ b/arch/sh/kernel/syscalls_64.S @@ -376,6 +376,8 @@ sys_call_table: .long sys_epoll_pwait .long sys_utimensat .long sys_signalfd - .long sys_ni_syscall /* 350 */ + .long sys_timerfd_create /* 350 */ .long sys_eventfd .long sys_fallocate + .long sys_timerfd_settime + .long sys_timerfd_gettime diff --git a/arch/sh/kernel/time_32.c b/arch/sh/kernel/time_32.c index 2bc04bfee73..7281342c044 100644 --- a/arch/sh/kernel/time_32.c +++ b/arch/sh/kernel/time_32.c @@ -120,10 +120,6 @@ static long last_rtc_update; */ void handle_timer_tick(void) { - do_timer(1); -#ifndef CONFIG_SMP - update_process_times(user_mode(get_irq_regs())); -#endif if (current->pid) profile_tick(CPU_PROFILING); @@ -133,6 +129,16 @@ void handle_timer_tick(void) #endif /* + * Here we are in the timer irq handler. We just have irqs locally + * disabled but we don't know if the timer_bh is running on the other + * CPU. We need to avoid to SMP race with it. NOTE: we don' t need + * the irq version of write_lock because as just said we have irq + * locally disabled. -arca + */ + write_seqlock(&xtime_lock); + do_timer(1); + + /* * If we have an externally synchronized Linux clock, then update * RTC clock accordingly every ~11 minutes. Set_rtc_mmss() has to be * called as close as possible to 500 ms before the new second starts. @@ -147,6 +153,11 @@ void handle_timer_tick(void) /* do it again in 60s */ last_rtc_update = xtime.tv_sec - 600; } + write_sequnlock(&xtime_lock); + +#ifndef CONFIG_SMP + update_process_times(user_mode(get_irq_regs())); +#endif } #endif /* !CONFIG_GENERIC_CLOCKEVENTS */ diff --git a/arch/sh/kernel/time_64.c b/arch/sh/kernel/time_64.c index f819ba38a6c..898977ee203 100644 --- a/arch/sh/kernel/time_64.c +++ b/arch/sh/kernel/time_64.c @@ -229,15 +229,22 @@ static long last_rtc_update; static inline void do_timer_interrupt(void) { unsigned long long current_ctc; + + if (current->pid) + profile_tick(CPU_PROFILING); + + /* + * Here we are in the timer irq handler. We just have irqs locally + * disabled but we don't know if the timer_bh is running on the other + * CPU. We need to avoid to SMP race with it. NOTE: we don' t need + * the irq version of write_lock because as just said we have irq + * locally disabled. -arca + */ + write_lock(&xtime_lock); asm ("getcon cr62, %0" : "=r" (current_ctc)); ctc_last_interrupt = (unsigned long) current_ctc; do_timer(1); -#ifndef CONFIG_SMP - update_process_times(user_mode(get_irq_regs())); -#endif - if (current->pid) - profile_tick(CPU_PROFILING); #ifdef CONFIG_HEARTBEAT if (sh_mv.mv_heartbeat != NULL) @@ -259,6 +266,11 @@ static inline void do_timer_interrupt(void) /* do it again in 60 s */ last_rtc_update = xtime.tv_sec - 600; } + write_unlock(&xtime_lock); + +#ifndef CONFIG_SMP + update_process_times(user_mode(get_irq_regs())); +#endif } /* @@ -275,16 +287,7 @@ static irqreturn_t timer_interrupt(int irq, void *dev_id) timer_status &= ~0x100; ctrl_outw(timer_status, TMU0_TCR); - /* - * Here we are in the timer irq handler. We just have irqs locally - * disabled but we don't know if the timer_bh is running on the other - * CPU. We need to avoid to SMP race with it. NOTE: we don' t need - * the irq version of write_lock because as just said we have irq - * locally disabled. -arca - */ - write_lock(&xtime_lock); do_timer_interrupt(); - write_unlock(&xtime_lock); return IRQ_HANDLED; } diff --git a/arch/sh/kernel/timers/timer-cmt.c b/arch/sh/kernel/timers/timer-cmt.c index 499e07beebe..71312324b5d 100644 --- a/arch/sh/kernel/timers/timer-cmt.c +++ b/arch/sh/kernel/timers/timer-cmt.c @@ -100,16 +100,7 @@ static irqreturn_t cmt_timer_interrupt(int irq, void *dev_id) timer_status &= ~0x80; ctrl_outw(timer_status, CMT_CMCSR_0); - /* - * Here we are in the timer irq handler. We just have irqs locally - * disabled but we don't know if the timer_bh is running on the other - * CPU. We need to avoid to SMP race with it. NOTE: we don' t need - * the irq version of write_lock because as just said we have irq - * locally disabled. -arca - */ - write_seqlock(&xtime_lock); handle_timer_tick(); - write_sequnlock(&xtime_lock); return IRQ_HANDLED; } diff --git a/arch/sh/kernel/timers/timer-mtu2.c b/arch/sh/kernel/timers/timer-mtu2.c index b7499a2a918..ade9d6eb29f 100644 --- a/arch/sh/kernel/timers/timer-mtu2.c +++ b/arch/sh/kernel/timers/timer-mtu2.c @@ -100,9 +100,7 @@ static irqreturn_t mtu2_timer_interrupt(int irq, void *dev_id) ctrl_outb(timer_status, MTU2_TSR_1); /* Do timer tick */ - write_seqlock(&xtime_lock); handle_timer_tick(); - write_sequnlock(&xtime_lock); return IRQ_HANDLED; } @@ -156,7 +154,6 @@ static int mtu2_timer_stop(void) static int mtu2_timer_init(void) { - u8 tmp; unsigned long interval; setup_irq(CONFIG_SH_TIMER_IRQ, &mtu2_irq); diff --git a/arch/sh/kernel/traps_32.c b/arch/sh/kernel/traps_32.c index 2e58f7a6b74..baa4fa368dc 100644 --- a/arch/sh/kernel/traps_32.c +++ b/arch/sh/kernel/traps_32.c @@ -147,6 +147,36 @@ static int die_if_no_fixup(const char * str, struct pt_regs * regs, long err) return -EFAULT; } +static inline void sign_extend(unsigned int count, unsigned char *dst) +{ +#ifdef __LITTLE_ENDIAN__ + if ((count == 1) && dst[0] & 0x80) { + dst[1] = 0xff; + dst[2] = 0xff; + dst[3] = 0xff; + } + if ((count == 2) && dst[1] & 0x80) { + dst[2] = 0xff; + dst[3] = 0xff; + } +#else + if ((count == 1) && dst[3] & 0x80) { + dst[2] = 0xff; + dst[1] = 0xff; + dst[0] = 0xff; + } + if ((count == 2) && dst[2] & 0x80) { + dst[1] = 0xff; + dst[0] = 0xff; + } +#endif +} + +static struct mem_access user_mem_access = { + copy_from_user, + copy_to_user, +}; + /* * handle an instruction that does an unaligned memory access by emulating the * desired behaviour @@ -154,7 +184,8 @@ static int die_if_no_fixup(const char * str, struct pt_regs * regs, long err) * (if that instruction is in a branch delay slot) * - return 0 if emulation okay, -EFAULT on existential error */ -static int handle_unaligned_ins(u16 instruction, struct pt_regs *regs) +static int handle_unaligned_ins(opcode_t instruction, struct pt_regs *regs, + struct mem_access *ma) { int ret, index, count; unsigned long *rm, *rn; @@ -178,25 +209,13 @@ static int handle_unaligned_ins(u16 instruction, struct pt_regs *regs) dst = (unsigned char*) rn; *(unsigned long*)dst = 0; -#ifdef __LITTLE_ENDIAN__ - if (copy_from_user(dst, src, count)) - goto fetch_fault; - - if ((count == 2) && dst[1] & 0x80) { - dst[2] = 0xff; - dst[3] = 0xff; - } -#else +#if !defined(__LITTLE_ENDIAN__) dst += 4-count; - - if (__copy_user(dst, src, count)) +#endif + if (ma->from(dst, src, count)) goto fetch_fault; - if ((count == 2) && dst[2] & 0x80) { - dst[0] = 0xff; - dst[1] = 0xff; - } -#endif + sign_extend(count, dst); } else { /* to memory */ src = (unsigned char*) rm; @@ -206,7 +225,7 @@ static int handle_unaligned_ins(u16 instruction, struct pt_regs *regs) dst = (unsigned char*) *rn; dst += regs->regs[0]; - if (copy_to_user(dst, src, count)) + if (ma->to(dst, src, count)) goto fetch_fault; } ret = 0; @@ -217,7 +236,7 @@ static int handle_unaligned_ins(u16 instruction, struct pt_regs *regs) dst = (unsigned char*) *rn; dst += (instruction&0x000F)<<2; - if (copy_to_user(dst,src,4)) + if (ma->to(dst, src, 4)) goto fetch_fault; ret = 0; break; @@ -230,7 +249,7 @@ static int handle_unaligned_ins(u16 instruction, struct pt_regs *regs) #if !defined(__LITTLE_ENDIAN__) src += 4-count; #endif - if (copy_to_user(dst, src, count)) + if (ma->to(dst, src, count)) goto fetch_fault; ret = 0; break; @@ -241,7 +260,7 @@ static int handle_unaligned_ins(u16 instruction, struct pt_regs *regs) dst = (unsigned char*) rn; *(unsigned long*)dst = 0; - if (copy_from_user(dst,src,4)) + if (ma->from(dst, src, 4)) goto fetch_fault; ret = 0; break; @@ -253,25 +272,12 @@ static int handle_unaligned_ins(u16 instruction, struct pt_regs *regs) dst = (unsigned char*) rn; *(unsigned long*)dst = 0; -#ifdef __LITTLE_ENDIAN__ - if (copy_from_user(dst, src, count)) - goto fetch_fault; - - if ((count == 2) && dst[1] & 0x80) { - dst[2] = 0xff; - dst[3] = 0xff; - } -#else +#if !defined(__LITTLE_ENDIAN__) dst += 4-count; - - if (copy_from_user(dst, src, count)) - goto fetch_fault; - - if ((count == 2) && dst[2] & 0x80) { - dst[0] = 0xff; - dst[1] = 0xff; - } #endif + if (ma->from(dst, src, count)) + goto fetch_fault; + sign_extend(count, dst); ret = 0; break; @@ -285,7 +291,7 @@ static int handle_unaligned_ins(u16 instruction, struct pt_regs *regs) dst = (unsigned char*) *rm; /* called Rn in the spec */ dst += (instruction&0x000F)<<1; - if (copy_to_user(dst, src, 2)) + if (ma->to(dst, src, 2)) goto fetch_fault; ret = 0; break; @@ -299,21 +305,9 @@ static int handle_unaligned_ins(u16 instruction, struct pt_regs *regs) #if !defined(__LITTLE_ENDIAN__) dst += 2; #endif - - if (copy_from_user(dst, src, 2)) + if (ma->from(dst, src, 2)) goto fetch_fault; - -#ifdef __LITTLE_ENDIAN__ - if (dst[1] & 0x80) { - dst[2] = 0xff; - dst[3] = 0xff; - } -#else - if (dst[2] & 0x80) { - dst[0] = 0xff; - dst[1] = 0xff; - } -#endif + sign_extend(2, dst); ret = 0; break; } @@ -332,11 +326,14 @@ static int handle_unaligned_ins(u16 instruction, struct pt_regs *regs) * emulate the instruction in the delay slot * - fetches the instruction from PC+2 */ -static inline int handle_unaligned_delayslot(struct pt_regs *regs) +static inline int handle_delayslot(struct pt_regs *regs, + opcode_t old_instruction, + struct mem_access *ma) { - u16 instruction; + opcode_t instruction; + void *addr = (void *)(regs->pc + instruction_size(old_instruction)); - if (copy_from_user(&instruction, (u16 *)(regs->pc+2), 2)) { + if (copy_from_user(&instruction, addr, sizeof(instruction))) { /* the instruction-fetch faulted */ if (user_mode(regs)) return -EFAULT; @@ -346,7 +343,7 @@ static inline int handle_unaligned_delayslot(struct pt_regs *regs) regs, 0); } - return handle_unaligned_ins(instruction,regs); + return handle_unaligned_ins(instruction, regs, ma); } /* @@ -369,10 +366,11 @@ static inline int handle_unaligned_delayslot(struct pt_regs *regs) * XXX: SH-2A needs this too, but it needs an overhaul thanks to mixed 32-bit * opcodes.. */ -#ifndef CONFIG_CPU_SH2A + static int handle_unaligned_notify_count = 10; -static int handle_unaligned_access(u16 instruction, struct pt_regs *regs) +int handle_unaligned_access(opcode_t instruction, struct pt_regs *regs, + struct mem_access *ma) { u_int rm; int ret, index; @@ -387,7 +385,7 @@ static int handle_unaligned_access(u16 instruction, struct pt_regs *regs) printk(KERN_NOTICE "Fixing up unaligned userspace access " "in \"%s\" pid=%d pc=0x%p ins=0x%04hx\n", current->comm, task_pid_nr(current), - (u16 *)regs->pc, instruction); + (void *)regs->pc, instruction); } ret = -EFAULT; @@ -395,19 +393,19 @@ static int handle_unaligned_access(u16 instruction, struct pt_regs *regs) case 0x0000: if (instruction==0x000B) { /* rts */ - ret = handle_unaligned_delayslot(regs); + ret = handle_delayslot(regs, instruction, ma); if (ret==0) regs->pc = regs->pr; } else if ((instruction&0x00FF)==0x0023) { /* braf @Rm */ - ret = handle_unaligned_delayslot(regs); + ret = handle_delayslot(regs, instruction, ma); if (ret==0) regs->pc += rm + 4; } else if ((instruction&0x00FF)==0x0003) { /* bsrf @Rm */ - ret = handle_unaligned_delayslot(regs); + ret = handle_delayslot(regs, instruction, ma); if (ret==0) { regs->pr = regs->pc + 4; regs->pc += rm + 4; @@ -428,13 +426,13 @@ static int handle_unaligned_access(u16 instruction, struct pt_regs *regs) case 0x4000: if ((instruction&0x00FF)==0x002B) { /* jmp @Rm */ - ret = handle_unaligned_delayslot(regs); + ret = handle_delayslot(regs, instruction, ma); if (ret==0) regs->pc = rm; } else if ((instruction&0x00FF)==0x000B) { /* jsr @Rm */ - ret = handle_unaligned_delayslot(regs); + ret = handle_delayslot(regs, instruction, ma); if (ret==0) { regs->pr = regs->pc + 4; regs->pc = rm; @@ -461,7 +459,7 @@ static int handle_unaligned_access(u16 instruction, struct pt_regs *regs) case 0x0B00: /* bf lab - no delayslot*/ break; case 0x0F00: /* bf/s lab */ - ret = handle_unaligned_delayslot(regs); + ret = handle_delayslot(regs, instruction, ma); if (ret==0) { #if defined(CONFIG_CPU_SH4) || defined(CONFIG_SH7705_CACHE_32KB) if ((regs->sr & 0x00000001) != 0) @@ -474,7 +472,7 @@ static int handle_unaligned_access(u16 instruction, struct pt_regs *regs) case 0x0900: /* bt lab - no delayslot */ break; case 0x0D00: /* bt/s lab */ - ret = handle_unaligned_delayslot(regs); + ret = handle_delayslot(regs, instruction, ma); if (ret==0) { #if defined(CONFIG_CPU_SH4) || defined(CONFIG_SH7705_CACHE_32KB) if ((regs->sr & 0x00000001) == 0) @@ -488,13 +486,13 @@ static int handle_unaligned_access(u16 instruction, struct pt_regs *regs) break; case 0xA000: /* bra label */ - ret = handle_unaligned_delayslot(regs); + ret = handle_delayslot(regs, instruction, ma); if (ret==0) regs->pc += SH_PC_12BIT_OFFSET(instruction); break; case 0xB000: /* bsr label */ - ret = handle_unaligned_delayslot(regs); + ret = handle_delayslot(regs, instruction, ma); if (ret==0) { regs->pr = regs->pc + 4; regs->pc += SH_PC_12BIT_OFFSET(instruction); @@ -505,12 +503,11 @@ static int handle_unaligned_access(u16 instruction, struct pt_regs *regs) /* handle non-delay-slot instruction */ simple: - ret = handle_unaligned_ins(instruction,regs); + ret = handle_unaligned_ins(instruction, regs, ma); if (ret==0) regs->pc += instruction_size(instruction); return ret; } -#endif /* CONFIG_CPU_SH2A */ #ifdef CONFIG_CPU_HAS_SR_RB #define lookup_exception_vector(x) \ @@ -538,10 +535,8 @@ asmlinkage void do_address_error(struct pt_regs *regs, unsigned long error_code = 0; mm_segment_t oldfs; siginfo_t info; -#ifndef CONFIG_CPU_SH2A - u16 instruction; + opcode_t instruction; int tmp; -#endif /* Intentional ifdef */ #ifdef CONFIG_CPU_HAS_SR_RB @@ -561,9 +556,9 @@ asmlinkage void do_address_error(struct pt_regs *regs, goto uspace_segv; } -#ifndef CONFIG_CPU_SH2A set_fs(USER_DS); - if (copy_from_user(&instruction, (u16 *)(regs->pc), 2)) { + if (copy_from_user(&instruction, (void *)(regs->pc), + sizeof(instruction))) { /* Argh. Fault on the instruction itself. This should never happen non-SMP */ @@ -571,13 +566,12 @@ asmlinkage void do_address_error(struct pt_regs *regs, goto uspace_segv; } - tmp = handle_unaligned_access(instruction, regs); + tmp = handle_unaligned_access(instruction, regs, + &user_mem_access); set_fs(oldfs); if (tmp==0) return; /* sorted */ -#endif - uspace_segv: printk(KERN_NOTICE "Sending SIGBUS to \"%s\" due to unaligned " "access (PC %lx PR %lx)\n", current->comm, regs->pc, @@ -592,9 +586,9 @@ uspace_segv: if (regs->pc & 1) die("unaligned program counter", regs, error_code); -#ifndef CONFIG_CPU_SH2A set_fs(KERNEL_DS); - if (copy_from_user(&instruction, (u16 *)(regs->pc), 2)) { + if (copy_from_user(&instruction, (void *)(regs->pc), + sizeof(instruction))) { /* Argh. Fault on the instruction itself. This should never happen non-SMP */ @@ -602,14 +596,8 @@ uspace_segv: die("insn faulting in do_address_error", regs, 0); } - handle_unaligned_access(instruction, regs); + handle_unaligned_access(instruction, regs, &user_mem_access); set_fs(oldfs); -#else - printk(KERN_NOTICE "Killing process \"%s\" due to unaligned " - "access\n", current->comm); - - force_sig(SIGSEGV, current); -#endif } } diff --git a/arch/sh/kernel/traps_64.c b/arch/sh/kernel/traps_64.c index c0b3c6f6edb..a55ac81d795 100644 --- a/arch/sh/kernel/traps_64.c +++ b/arch/sh/kernel/traps_64.c @@ -630,7 +630,7 @@ static int misaligned_fpu_load(struct pt_regs *regs, current->thread.fpu.hard.fp_regs[destreg] = buflo; current->thread.fpu.hard.fp_regs[destreg+1] = bufhi; } else { -#if defined(CONFIG_LITTLE_ENDIAN) +#if defined(CONFIG_CPU_LITTLE_ENDIAN) current->thread.fpu.hard.fp_regs[destreg] = bufhi; current->thread.fpu.hard.fp_regs[destreg+1] = buflo; #else @@ -700,7 +700,7 @@ static int misaligned_fpu_store(struct pt_regs *regs, buflo = current->thread.fpu.hard.fp_regs[srcreg]; bufhi = current->thread.fpu.hard.fp_regs[srcreg+1]; } else { -#if defined(CONFIG_LITTLE_ENDIAN) +#if defined(CONFIG_CPU_LITTLE_ENDIAN) bufhi = current->thread.fpu.hard.fp_regs[srcreg]; buflo = current->thread.fpu.hard.fp_regs[srcreg+1]; #else diff --git a/arch/sh/kernel/vmlinux_64.lds.S b/arch/sh/kernel/vmlinux_64.lds.S index 3f1bd6392bb..d1e177009a4 100644 --- a/arch/sh/kernel/vmlinux_64.lds.S +++ b/arch/sh/kernel/vmlinux_64.lds.S @@ -51,7 +51,7 @@ SECTIONS KPROBES_TEXT *(.fixup) *(.gnu.warning) -#ifdef CONFIG_LITTLE_ENDIAN +#ifdef CONFIG_CPU_LITTLE_ENDIAN } = 0x6ff0fff0 #else } = 0xf0fff06f diff --git a/arch/sh/mm/cache-sh5.c b/arch/sh/mm/cache-sh5.c index 4617e3aeee7..3877321fced 100644 --- a/arch/sh/mm/cache-sh5.c +++ b/arch/sh/mm/cache-sh5.c @@ -1,10 +1,10 @@ /* * arch/sh/mm/cache-sh5.c * - * Original version Copyright (C) 2000, 2001 Paolo Alberelli - * Second version Copyright (C) benedict.gaster@superh.com 2002 - * Third version Copyright Richard.Curnow@superh.com 2003 - * Hacks to third version Copyright (C) 2003 Paul Mundt + * Copyright (C) 2000, 2001 Paolo Alberelli + * Copyright (C) 2002 Benedict Gaster + * Copyright (C) 2003 Richard Curnow + * Copyright (C) 2003 - 2008 Paul Mundt * * This file is subject to the terms and conditions of the GNU General Public * License. See the file "COPYING" in the main directory of this archive @@ -13,101 +13,20 @@ #include <linux/init.h> #include <linux/mman.h> #include <linux/mm.h> -#include <linux/threads.h> -#include <asm/page.h> -#include <asm/pgtable.h> +#include <asm/tlb.h> #include <asm/processor.h> #include <asm/cache.h> -#include <asm/tlb.h> -#include <asm/io.h> +#include <asm/pgalloc.h> #include <asm/uaccess.h> #include <asm/mmu_context.h> -#include <asm/pgalloc.h> /* for flush_itlb_range */ - -#include <linux/proc_fs.h> - -/* This function is in entry.S */ -extern unsigned long switch_and_save_asid(unsigned long new_asid); /* Wired TLB entry for the D-cache */ static unsigned long long dtlb_cache_slot; -/** - * sh64_cache_init() - * - * This is pretty much just a straightforward clone of the SH - * detect_cpu_and_cache_system(). - * - * This function is responsible for setting up all of the cache - * info dynamically as well as taking care of CPU probing and - * setting up the relevant subtype data. - * - * FIXME: For the time being, we only really support the SH5-101 - * out of the box, and don't support dynamic probing for things - * like the SH5-103 or even cut2 of the SH5-101. Implement this - * later! - */ -int __init sh64_cache_init(void) +void __init p3_cache_init(void) { - /* - * First, setup some sane values for the I-cache. - */ - cpu_data->icache.ways = 4; - cpu_data->icache.sets = 256; - cpu_data->icache.linesz = L1_CACHE_BYTES; - - /* - * FIXME: This can probably be cleaned up a bit as well.. for example, - * do we really need the way shift _and_ the way_step_shift ?? Judging - * by the existing code, I would guess no.. is there any valid reason - * why we need to be tracking this around? - */ - cpu_data->icache.way_shift = 13; - cpu_data->icache.entry_shift = 5; - cpu_data->icache.set_shift = 4; - cpu_data->icache.way_step_shift = 16; - cpu_data->icache.asid_shift = 2; - - /* - * way offset = cache size / associativity, so just don't factor in - * associativity in the first place.. - */ - cpu_data->icache.way_ofs = cpu_data->icache.sets * - cpu_data->icache.linesz; - - cpu_data->icache.asid_mask = 0x3fc; - cpu_data->icache.idx_mask = 0x1fe0; - cpu_data->icache.epn_mask = 0xffffe000; - cpu_data->icache.flags = 0; - - /* - * Next, setup some sane values for the D-cache. - * - * On the SH5, these are pretty consistent with the I-cache settings, - * so we just copy over the existing definitions.. these can be fixed - * up later, especially if we add runtime CPU probing. - * - * Though in the meantime it saves us from having to duplicate all of - * the above definitions.. - */ - cpu_data->dcache = cpu_data->icache; - - /* - * Setup any cache-related flags here - */ -#if defined(CONFIG_DCACHE_WRITE_THROUGH) - set_bit(SH_CACHE_MODE_WT, &(cpu_data->dcache.flags)); -#elif defined(CONFIG_DCACHE_WRITE_BACK) - set_bit(SH_CACHE_MODE_WB, &(cpu_data->dcache.flags)); -#endif - - /* - * We also need to reserve a slot for the D-cache in the DTLB, so we - * do this now .. - */ - dtlb_cache_slot = sh64_get_wired_dtlb_entry(); - - return 0; + /* Reserve a slot for dcache colouring in the DTLB */ + dtlb_cache_slot = sh64_get_wired_dtlb_entry(); } #ifdef CONFIG_DCACHE_DISABLED @@ -116,73 +35,48 @@ int __init sh64_cache_init(void) #define sh64_dcache_purge_user_range(mm, start, end) do { } while (0) #define sh64_dcache_purge_phy_page(paddr) do { } while (0) #define sh64_dcache_purge_virt_page(mm, eaddr) do { } while (0) -#define sh64_dcache_purge_kernel_range(start, end) do { } while (0) -#define sh64_dcache_wback_current_user_range(start, end) do { } while (0) #endif -/*##########################################################################*/ - -/* From here onwards, a rewrite of the implementation, - by Richard.Curnow@superh.com. - - The major changes in this compared to the old version are; - 1. use more selective purging through OCBP instead of using ALLOCO to purge - by natural replacement. This avoids purging out unrelated cache lines - that happen to be in the same set. - 2. exploit the APIs copy_user_page and clear_user_page better - 3. be more selective about I-cache purging, in particular use invalidate_all - more sparingly. - - */ - -/*########################################################################## - SUPPORT FUNCTIONS - ##########################################################################*/ - -/****************************************************************************/ -/* The following group of functions deal with mapping and unmapping a temporary - page into the DTLB slot that have been set aside for our exclusive use. */ -/* In order to accomplish this, we use the generic interface for adding and - removing a wired slot entry as defined in arch/sh/mm/tlb-sh5.c */ -/****************************************************************************/ - -static unsigned long slot_own_flags; - -static inline void sh64_setup_dtlb_cache_slot(unsigned long eaddr, unsigned long asid, unsigned long paddr) +/* + * The following group of functions deal with mapping and unmapping a + * temporary page into a DTLB slot that has been set aside for exclusive + * use. + */ +static inline void +sh64_setup_dtlb_cache_slot(unsigned long eaddr, unsigned long asid, + unsigned long paddr) { - local_irq_save(slot_own_flags); + local_irq_disable(); sh64_setup_tlb_slot(dtlb_cache_slot, eaddr, asid, paddr); } static inline void sh64_teardown_dtlb_cache_slot(void) { sh64_teardown_tlb_slot(dtlb_cache_slot); - local_irq_restore(slot_own_flags); + local_irq_enable(); } -/****************************************************************************/ - #ifndef CONFIG_ICACHE_DISABLED - -static void __inline__ sh64_icache_inv_all(void) +static inline void sh64_icache_inv_all(void) { unsigned long long addr, flag, data; unsigned int flags; - addr=ICCR0; - flag=ICCR0_ICI; - data=0; + addr = ICCR0; + flag = ICCR0_ICI; + data = 0; /* Make this a critical section for safety (probably not strictly necessary.) */ local_irq_save(flags); /* Without %1 it gets unexplicably wrong */ - asm volatile("getcfg %3, 0, %0\n\t" - "or %0, %2, %0\n\t" - "putcfg %3, 0, %0\n\t" - "synci" - : "=&r" (data) - : "0" (data), "r" (flag), "r" (addr)); + __asm__ __volatile__ ( + "getcfg %3, 0, %0\n\t" + "or %0, %2, %0\n\t" + "putcfg %3, 0, %0\n\t" + "synci" + : "=&r" (data) + : "0" (data), "r" (flag), "r" (addr)); local_irq_restore(flags); } @@ -193,20 +87,12 @@ static void sh64_icache_inv_kernel_range(unsigned long start, unsigned long end) * the addresses lie in the kernel superpage. */ unsigned long long ullend, addr, aligned_start; -#if (NEFF == 32) aligned_start = (unsigned long long)(signed long long)(signed long) start; -#else -#error "NEFF != 32" -#endif - aligned_start &= L1_CACHE_ALIGN_MASK; - addr = aligned_start; -#if (NEFF == 32) + addr = L1_CACHE_ALIGN(aligned_start); ullend = (unsigned long long) (signed long long) (signed long) end; -#else -#error "NEFF != 32" -#endif + while (addr <= ullend) { - asm __volatile__ ("icbi %0, 0" : : "r" (addr)); + __asm__ __volatile__ ("icbi %0, 0" : : "r" (addr)); addr += L1_CACHE_BYTES; } } @@ -215,7 +101,7 @@ static void sh64_icache_inv_user_page(struct vm_area_struct *vma, unsigned long { /* If we get called, we know that vma->vm_flags contains VM_EXEC. Also, eaddr is page-aligned. */ - + unsigned int cpu = smp_processor_id(); unsigned long long addr, end_addr; unsigned long flags = 0; unsigned long running_asid, vma_asid; @@ -237,17 +123,17 @@ static void sh64_icache_inv_user_page(struct vm_area_struct *vma, unsigned long */ running_asid = get_asid(); - vma_asid = (vma->vm_mm->context & MMU_CONTEXT_ASID_MASK); + vma_asid = cpu_asid(cpu, vma->vm_mm); if (running_asid != vma_asid) { local_irq_save(flags); switch_and_save_asid(vma_asid); } while (addr < end_addr) { /* Worth unrolling a little */ - asm __volatile__("icbi %0, 0" : : "r" (addr)); - asm __volatile__("icbi %0, 32" : : "r" (addr)); - asm __volatile__("icbi %0, 64" : : "r" (addr)); - asm __volatile__("icbi %0, 96" : : "r" (addr)); + __asm__ __volatile__("icbi %0, 0" : : "r" (addr)); + __asm__ __volatile__("icbi %0, 32" : : "r" (addr)); + __asm__ __volatile__("icbi %0, 64" : : "r" (addr)); + __asm__ __volatile__("icbi %0, 96" : : "r" (addr)); addr += 128; } if (running_asid != vma_asid) { @@ -256,8 +142,6 @@ static void sh64_icache_inv_user_page(struct vm_area_struct *vma, unsigned long } } -/****************************************************************************/ - static void sh64_icache_inv_user_page_range(struct mm_struct *mm, unsigned long start, unsigned long end) { @@ -275,10 +159,10 @@ static void sh64_icache_inv_user_page_range(struct mm_struct *mm, possible with the D-cache. Just assume 64 for now as a working figure. */ - int n_pages; - if (!mm) return; + if (!mm) + return; n_pages = ((end - start) >> PAGE_SHIFT); if (n_pages >= 64) { @@ -290,7 +174,7 @@ static void sh64_icache_inv_user_page_range(struct mm_struct *mm, unsigned long mm_asid, current_asid; unsigned long long flags = 0ULL; - mm_asid = mm->context & MMU_CONTEXT_ASID_MASK; + mm_asid = cpu_asid(smp_processor_id(), mm); current_asid = get_asid(); if (mm_asid != current_asid) { @@ -322,6 +206,7 @@ static void sh64_icache_inv_user_page_range(struct mm_struct *mm, } aligned_start = vma->vm_end; /* Skip to start of next region */ } + if (mm_asid != current_asid) { switch_and_save_asid(current_asid); local_irq_restore(flags); @@ -329,47 +214,46 @@ static void sh64_icache_inv_user_page_range(struct mm_struct *mm, } } +/* + * Invalidate a small range of user context I-cache, not necessarily page + * (or even cache-line) aligned. + * + * Since this is used inside ptrace, the ASID in the mm context typically + * won't match current_asid. We'll have to switch ASID to do this. For + * safety, and given that the range will be small, do all this under cli. + * + * Note, there is a hazard that the ASID in mm->context is no longer + * actually associated with mm, i.e. if the mm->context has started a new + * cycle since mm was last active. However, this is just a performance + * issue: all that happens is that we invalidate lines belonging to + * another mm, so the owning process has to refill them when that mm goes + * live again. mm itself can't have any cache entries because there will + * have been a flush_cache_all when the new mm->context cycle started. + */ static void sh64_icache_inv_user_small_range(struct mm_struct *mm, unsigned long start, int len) { - - /* Invalidate a small range of user context I-cache, not necessarily - page (or even cache-line) aligned. */ - unsigned long long eaddr = start; unsigned long long eaddr_end = start + len; unsigned long current_asid, mm_asid; unsigned long long flags; unsigned long long epage_start; - /* Since this is used inside ptrace, the ASID in the mm context - typically won't match current_asid. We'll have to switch ASID to do - this. For safety, and given that the range will be small, do all - this under cli. - - Note, there is a hazard that the ASID in mm->context is no longer - actually associated with mm, i.e. if the mm->context has started a - new cycle since mm was last active. However, this is just a - performance issue: all that happens is that we invalidate lines - belonging to another mm, so the owning process has to refill them - when that mm goes live again. mm itself can't have any cache - entries because there will have been a flush_cache_all when the new - mm->context cycle started. */ - - /* Align to start of cache line. Otherwise, suppose len==8 and start - was at 32N+28 : the last 4 bytes wouldn't get invalidated. */ - eaddr = start & L1_CACHE_ALIGN_MASK; + /* + * Align to start of cache line. Otherwise, suppose len==8 and + * start was at 32N+28 : the last 4 bytes wouldn't get invalidated. + */ + eaddr = L1_CACHE_ALIGN(start); eaddr_end = start + len; + mm_asid = cpu_asid(smp_processor_id(), mm); local_irq_save(flags); - mm_asid = mm->context & MMU_CONTEXT_ASID_MASK; current_asid = switch_and_save_asid(mm_asid); epage_start = eaddr & PAGE_MASK; - while (eaddr < eaddr_end) - { - asm __volatile__("icbi %0, 0" : : "r" (eaddr)); + while (eaddr < eaddr_end) { + __asm__ __volatile__("icbi %0, 0" : : "r" (eaddr)); eaddr += L1_CACHE_BYTES; } switch_and_save_asid(current_asid); @@ -394,30 +278,24 @@ static void sh64_icache_inv_current_user_range(unsigned long start, unsigned lon been recycled since we were last active in which case we might just invalidate another processes I-cache entries : no worries, just a performance drop for him. */ - aligned_start = start & L1_CACHE_ALIGN_MASK; + aligned_start = L1_CACHE_ALIGN(start); addr = aligned_start; while (addr < ull_end) { - asm __volatile__ ("icbi %0, 0" : : "r" (addr)); - asm __volatile__ ("nop"); - asm __volatile__ ("nop"); + __asm__ __volatile__ ("icbi %0, 0" : : "r" (addr)); + __asm__ __volatile__ ("nop"); + __asm__ __volatile__ ("nop"); addr += L1_CACHE_BYTES; } } - #endif /* !CONFIG_ICACHE_DISABLED */ -/****************************************************************************/ - #ifndef CONFIG_DCACHE_DISABLED - /* Buffer used as the target of alloco instructions to purge data from cache sets by natural eviction. -- RPC */ -#define DUMMY_ALLOCO_AREA_SIZE L1_CACHE_SIZE_BYTES + (1024 * 4) +#define DUMMY_ALLOCO_AREA_SIZE ((L1_CACHE_BYTES << 10) + (1024 * 4)) static unsigned char dummy_alloco_area[DUMMY_ALLOCO_AREA_SIZE] __cacheline_aligned = { 0, }; -/****************************************************************************/ - -static void __inline__ sh64_dcache_purge_sets(int sets_to_purge_base, int n_sets) +static void inline sh64_dcache_purge_sets(int sets_to_purge_base, int n_sets) { /* Purge all ways in a particular block of sets, specified by the base set number and number of sets. Can handle wrap-around, if that's @@ -428,102 +306,86 @@ static void __inline__ sh64_dcache_purge_sets(int sets_to_purge_base, int n_sets int j; int set_offset; - dummy_buffer_base_set = ((int)&dummy_alloco_area & cpu_data->dcache.idx_mask) >> cpu_data->dcache.entry_shift; + dummy_buffer_base_set = ((int)&dummy_alloco_area & + cpu_data->dcache.entry_mask) >> + cpu_data->dcache.entry_shift; set_offset = sets_to_purge_base - dummy_buffer_base_set; - for (j=0; j<n_sets; j++, set_offset++) { + for (j = 0; j < n_sets; j++, set_offset++) { set_offset &= (cpu_data->dcache.sets - 1); - eaddr0 = (unsigned long long)dummy_alloco_area + (set_offset << cpu_data->dcache.entry_shift); - - /* Do one alloco which hits the required set per cache way. For - write-back mode, this will purge the #ways resident lines. There's - little point unrolling this loop because the allocos stall more if - they're too close together. */ - eaddr1 = eaddr0 + cpu_data->dcache.way_ofs * cpu_data->dcache.ways; - for (eaddr=eaddr0; eaddr<eaddr1; eaddr+=cpu_data->dcache.way_ofs) { - asm __volatile__ ("alloco %0, 0" : : "r" (eaddr)); - asm __volatile__ ("synco"); /* TAKum03020 */ + eaddr0 = (unsigned long long)dummy_alloco_area + + (set_offset << cpu_data->dcache.entry_shift); + + /* + * Do one alloco which hits the required set per cache + * way. For write-back mode, this will purge the #ways + * resident lines. There's little point unrolling this + * loop because the allocos stall more if they're too + * close together. + */ + eaddr1 = eaddr0 + cpu_data->dcache.way_size * + cpu_data->dcache.ways; + + for (eaddr = eaddr0; eaddr < eaddr1; + eaddr += cpu_data->dcache.way_size) { + __asm__ __volatile__ ("alloco %0, 0" : : "r" (eaddr)); + __asm__ __volatile__ ("synco"); /* TAKum03020 */ } - eaddr1 = eaddr0 + cpu_data->dcache.way_ofs * cpu_data->dcache.ways; - for (eaddr=eaddr0; eaddr<eaddr1; eaddr+=cpu_data->dcache.way_ofs) { - /* Load from each address. Required because alloco is a NOP if - the cache is write-through. Write-through is a config option. */ + eaddr1 = eaddr0 + cpu_data->dcache.way_size * + cpu_data->dcache.ways; + + for (eaddr = eaddr0; eaddr < eaddr1; + eaddr += cpu_data->dcache.way_size) { + /* + * Load from each address. Required because + * alloco is a NOP if the cache is write-through. + */ if (test_bit(SH_CACHE_MODE_WT, &(cpu_data->dcache.flags))) - *(volatile unsigned char *)(int)eaddr; + ctrl_inb(eaddr); } } - /* Don't use OCBI to invalidate the lines. That costs cycles directly. - If the dummy block is just left resident, it will naturally get - evicted as required. */ - - return; + /* + * Don't use OCBI to invalidate the lines. That costs cycles + * directly. If the dummy block is just left resident, it will + * naturally get evicted as required. + */ } -/****************************************************************************/ - +/* + * Purge the entire contents of the dcache. The most efficient way to + * achieve this is to use alloco instructions on a region of unused + * memory equal in size to the cache, thereby causing the current + * contents to be discarded by natural eviction. The alternative, namely + * reading every tag, setting up a mapping for the corresponding page and + * doing an OCBP for the line, would be much more expensive. + */ static void sh64_dcache_purge_all(void) { - /* Purge the entire contents of the dcache. The most efficient way to - achieve this is to use alloco instructions on a region of unused - memory equal in size to the cache, thereby causing the current - contents to be discarded by natural eviction. The alternative, - namely reading every tag, setting up a mapping for the corresponding - page and doing an OCBP for the line, would be much more expensive. - */ sh64_dcache_purge_sets(0, cpu_data->dcache.sets); - - return; - } -/****************************************************************************/ - -static void sh64_dcache_purge_kernel_range(unsigned long start, unsigned long end) -{ - /* Purge the range of addresses [start,end] from the D-cache. The - addresses lie in the superpage mapping. There's no harm if we - overpurge at either end - just a small performance loss. */ - unsigned long long ullend, addr, aligned_start; -#if (NEFF == 32) - aligned_start = (unsigned long long)(signed long long)(signed long) start; -#else -#error "NEFF != 32" -#endif - aligned_start &= L1_CACHE_ALIGN_MASK; - addr = aligned_start; -#if (NEFF == 32) - ullend = (unsigned long long) (signed long long) (signed long) end; -#else -#error "NEFF != 32" -#endif - while (addr <= ullend) { - asm __volatile__ ("ocbp %0, 0" : : "r" (addr)); - addr += L1_CACHE_BYTES; - } - return; -} /* Assumes this address (+ (2**n_synbits) pages up from it) aren't used for anything else in the kernel */ #define MAGIC_PAGE0_START 0xffffffffec000000ULL -static void sh64_dcache_purge_coloured_phy_page(unsigned long paddr, unsigned long eaddr) +/* Purge the physical page 'paddr' from the cache. It's known that any + * cache lines requiring attention have the same page colour as the the + * address 'eaddr'. + * + * This relies on the fact that the D-cache matches on physical tags when + * no virtual tag matches. So we create an alias for the original page + * and purge through that. (Alternatively, we could have done this by + * switching ASID to match the original mapping and purged through that, + * but that involves ASID switching cost + probably a TLBMISS + refill + * anyway.) + */ +static void sh64_dcache_purge_coloured_phy_page(unsigned long paddr, + unsigned long eaddr) { - /* Purge the physical page 'paddr' from the cache. It's known that any - cache lines requiring attention have the same page colour as the the - address 'eaddr'. - - This relies on the fact that the D-cache matches on physical tags - when no virtual tag matches. So we create an alias for the original - page and purge through that. (Alternatively, we could have done - this by switching ASID to match the original mapping and purged - through that, but that involves ASID switching cost + probably a - TLBMISS + refill anyway.) - */ - unsigned long long magic_page_start; unsigned long long magic_eaddr, magic_eaddr_end; @@ -531,47 +393,45 @@ static void sh64_dcache_purge_coloured_phy_page(unsigned long paddr, unsigned lo /* As long as the kernel is not pre-emptible, this doesn't need to be under cli/sti. */ - sh64_setup_dtlb_cache_slot(magic_page_start, get_asid(), paddr); magic_eaddr = magic_page_start; magic_eaddr_end = magic_eaddr + PAGE_SIZE; + while (magic_eaddr < magic_eaddr_end) { /* Little point in unrolling this loop - the OCBPs are blocking and won't go any quicker (i.e. the loop overhead is parallel to part of the OCBP execution.) */ - asm __volatile__ ("ocbp %0, 0" : : "r" (magic_eaddr)); + __asm__ __volatile__ ("ocbp %0, 0" : : "r" (magic_eaddr)); magic_eaddr += L1_CACHE_BYTES; } sh64_teardown_dtlb_cache_slot(); } -/****************************************************************************/ - +/* + * Purge a page given its physical start address, by creating a temporary + * 1 page mapping and purging across that. Even if we know the virtual + * address (& vma or mm) of the page, the method here is more elegant + * because it avoids issues of coping with page faults on the purge + * instructions (i.e. no special-case code required in the critical path + * in the TLB miss handling). + */ static void sh64_dcache_purge_phy_page(unsigned long paddr) { - /* Pure a page given its physical start address, by creating a - temporary 1 page mapping and purging across that. Even if we know - the virtual address (& vma or mm) of the page, the method here is - more elegant because it avoids issues of coping with page faults on - the purge instructions (i.e. no special-case code required in the - critical path in the TLB miss handling). */ - unsigned long long eaddr_start, eaddr, eaddr_end; int i; /* As long as the kernel is not pre-emptible, this doesn't need to be under cli/sti. */ - eaddr_start = MAGIC_PAGE0_START; - for (i=0; i < (1 << CACHE_OC_N_SYNBITS); i++) { + for (i = 0; i < (1 << CACHE_OC_N_SYNBITS); i++) { sh64_setup_dtlb_cache_slot(eaddr_start, get_asid(), paddr); eaddr = eaddr_start; eaddr_end = eaddr + PAGE_SIZE; while (eaddr < eaddr_end) { - asm __volatile__ ("ocbp %0, 0" : : "r" (eaddr)); + __asm__ __volatile__ ("ocbp %0, 0" : : "r" (eaddr)); eaddr += L1_CACHE_BYTES; } @@ -584,6 +444,7 @@ static void sh64_dcache_purge_user_pages(struct mm_struct *mm, unsigned long addr, unsigned long end) { pgd_t *pgd; + pud_t *pud; pmd_t *pmd; pte_t *pte; pte_t entry; @@ -597,7 +458,11 @@ static void sh64_dcache_purge_user_pages(struct mm_struct *mm, if (pgd_bad(*pgd)) return; - pmd = pmd_offset(pgd, addr); + pud = pud_offset(pgd, addr); + if (pud_none(*pud) || pud_bad(*pud)) + return; + + pmd = pmd_offset(pud, addr); if (pmd_none(*pmd) || pmd_bad(*pmd)) return; @@ -611,419 +476,357 @@ static void sh64_dcache_purge_user_pages(struct mm_struct *mm, } while (pte++, addr += PAGE_SIZE, addr != end); pte_unmap_unlock(pte - 1, ptl); } -/****************************************************************************/ +/* + * There are at least 5 choices for the implementation of this, with + * pros (+), cons(-), comments(*): + * + * 1. ocbp each line in the range through the original user's ASID + * + no lines spuriously evicted + * - tlbmiss handling (must either handle faults on demand => extra + * special-case code in tlbmiss critical path), or map the page in + * advance (=> flush_tlb_range in advance to avoid multiple hits) + * - ASID switching + * - expensive for large ranges + * + * 2. temporarily map each page in the range to a special effective + * address and ocbp through the temporary mapping; relies on the + * fact that SH-5 OCB* always do TLB lookup and match on ptags (they + * never look at the etags) + * + no spurious evictions + * - expensive for large ranges + * * surely cheaper than (1) + * + * 3. walk all the lines in the cache, check the tags, if a match + * occurs create a page mapping to ocbp the line through + * + no spurious evictions + * - tag inspection overhead + * - (especially for small ranges) + * - potential cost of setting up/tearing down page mapping for + * every line that matches the range + * * cost partly independent of range size + * + * 4. walk all the lines in the cache, check the tags, if a match + * occurs use 4 * alloco to purge the line (+3 other probably + * innocent victims) by natural eviction + * + no tlb mapping overheads + * - spurious evictions + * - tag inspection overhead + * + * 5. implement like flush_cache_all + * + no tag inspection overhead + * - spurious evictions + * - bad for small ranges + * + * (1) can be ruled out as more expensive than (2). (2) appears best + * for small ranges. The choice between (3), (4) and (5) for large + * ranges and the range size for the large/small boundary need + * benchmarking to determine. + * + * For now use approach (2) for small ranges and (5) for large ones. + */ static void sh64_dcache_purge_user_range(struct mm_struct *mm, unsigned long start, unsigned long end) { - /* There are at least 5 choices for the implementation of this, with - pros (+), cons(-), comments(*): - - 1. ocbp each line in the range through the original user's ASID - + no lines spuriously evicted - - tlbmiss handling (must either handle faults on demand => extra - special-case code in tlbmiss critical path), or map the page in - advance (=> flush_tlb_range in advance to avoid multiple hits) - - ASID switching - - expensive for large ranges - - 2. temporarily map each page in the range to a special effective - address and ocbp through the temporary mapping; relies on the - fact that SH-5 OCB* always do TLB lookup and match on ptags (they - never look at the etags) - + no spurious evictions - - expensive for large ranges - * surely cheaper than (1) - - 3. walk all the lines in the cache, check the tags, if a match - occurs create a page mapping to ocbp the line through - + no spurious evictions - - tag inspection overhead - - (especially for small ranges) - - potential cost of setting up/tearing down page mapping for - every line that matches the range - * cost partly independent of range size - - 4. walk all the lines in the cache, check the tags, if a match - occurs use 4 * alloco to purge the line (+3 other probably - innocent victims) by natural eviction - + no tlb mapping overheads - - spurious evictions - - tag inspection overhead - - 5. implement like flush_cache_all - + no tag inspection overhead - - spurious evictions - - bad for small ranges - - (1) can be ruled out as more expensive than (2). (2) appears best - for small ranges. The choice between (3), (4) and (5) for large - ranges and the range size for the large/small boundary need - benchmarking to determine. - - For now use approach (2) for small ranges and (5) for large ones. - - */ - - int n_pages; + int n_pages = ((end - start) >> PAGE_SHIFT); - n_pages = ((end - start) >> PAGE_SHIFT); if (n_pages >= 64 || ((start ^ (end - 1)) & PMD_MASK)) { -#if 1 sh64_dcache_purge_all(); -#else - unsigned long long set, way; - unsigned long mm_asid = mm->context & MMU_CONTEXT_ASID_MASK; - for (set = 0; set < cpu_data->dcache.sets; set++) { - unsigned long long set_base_config_addr = CACHE_OC_ADDRESS_ARRAY + (set << cpu_data->dcache.set_shift); - for (way = 0; way < cpu_data->dcache.ways; way++) { - unsigned long long config_addr = set_base_config_addr + (way << cpu_data->dcache.way_step_shift); - unsigned long long tag0; - unsigned long line_valid; - - asm __volatile__("getcfg %1, 0, %0" : "=r" (tag0) : "r" (config_addr)); - line_valid = tag0 & SH_CACHE_VALID; - if (line_valid) { - unsigned long cache_asid; - unsigned long epn; - - cache_asid = (tag0 & cpu_data->dcache.asid_mask) >> cpu_data->dcache.asid_shift; - /* The next line needs some - explanation. The virtual tags - encode bits [31:13] of the virtual - address, bit [12] of the 'tag' being - implied by the cache set index. */ - epn = (tag0 & cpu_data->dcache.epn_mask) | ((set & 0x80) << cpu_data->dcache.entry_shift); - - if ((cache_asid == mm_asid) && (start <= epn) && (epn < end)) { - /* TODO : could optimise this - call by batching multiple - adjacent sets together. */ - sh64_dcache_purge_sets(set, 1); - break; /* Don't waste time inspecting other ways for this set */ - } - } - } - } -#endif } else { /* Small range, covered by a single page table page */ start &= PAGE_MASK; /* should already be so */ end = PAGE_ALIGN(end); /* should already be so */ sh64_dcache_purge_user_pages(mm, start, end); } - return; } -static void sh64_dcache_wback_current_user_range(unsigned long start, unsigned long end) +/* + * Purge the range of addresses from the D-cache. + * + * The addresses lie in the superpage mapping. There's no harm if we + * overpurge at either end - just a small performance loss. + */ +void __flush_purge_region(void *start, int size) { - unsigned long long aligned_start; - unsigned long long ull_end; - unsigned long long addr; - - ull_end = end; + unsigned long long ullend, addr, aligned_start; - /* Just wback over the range using the natural addresses. TLB miss - handling will be OK (TBC) : the range has just been written to by - the signal frame setup code, so the PTEs must exist. + aligned_start = (unsigned long long)(signed long long)(signed long) start; + addr = L1_CACHE_ALIGN(aligned_start); + ullend = (unsigned long long) (signed long long) (signed long) start + size; - Note, if we have CONFIG_PREEMPT and get preempted inside this loop, - it doesn't matter, even if the pid->ASID mapping changes whilst - we're away. In that case the cache will have been flushed when the - mapping was renewed. So the writebacks below will be nugatory (and - we'll doubtless have to fault the TLB entry/ies in again with the - new ASID), but it's a rare case. - */ - aligned_start = start & L1_CACHE_ALIGN_MASK; - addr = aligned_start; - while (addr < ull_end) { - asm __volatile__ ("ocbwb %0, 0" : : "r" (addr)); + while (addr <= ullend) { + __asm__ __volatile__ ("ocbp %0, 0" : : "r" (addr)); addr += L1_CACHE_BYTES; } } -/****************************************************************************/ - -/* These *MUST* lie in an area of virtual address space that's otherwise unused. */ -#define UNIQUE_EADDR_START 0xe0000000UL -#define UNIQUE_EADDR_END 0xe8000000UL - -static unsigned long sh64_make_unique_eaddr(unsigned long user_eaddr, unsigned long paddr) +void __flush_wback_region(void *start, int size) { - /* Given a physical address paddr, and a user virtual address - user_eaddr which will eventually be mapped to it, create a one-off - kernel-private eaddr mapped to the same paddr. This is used for - creating special destination pages for copy_user_page and - clear_user_page */ + unsigned long long ullend, addr, aligned_start; - static unsigned long current_pointer = UNIQUE_EADDR_START; - unsigned long coloured_pointer; + aligned_start = (unsigned long long)(signed long long)(signed long) start; + addr = L1_CACHE_ALIGN(aligned_start); + ullend = (unsigned long long) (signed long long) (signed long) start + size; - if (current_pointer == UNIQUE_EADDR_END) { - sh64_dcache_purge_all(); - current_pointer = UNIQUE_EADDR_START; + while (addr < ullend) { + __asm__ __volatile__ ("ocbwb %0, 0" : : "r" (addr)); + addr += L1_CACHE_BYTES; } - - coloured_pointer = (current_pointer & ~CACHE_OC_SYN_MASK) | (user_eaddr & CACHE_OC_SYN_MASK); - sh64_setup_dtlb_cache_slot(coloured_pointer, get_asid(), paddr); - - current_pointer += (PAGE_SIZE << CACHE_OC_N_SYNBITS); - - return coloured_pointer; -} - -/****************************************************************************/ - -static void sh64_copy_user_page_coloured(void *to, void *from, unsigned long address) -{ - void *coloured_to; - - /* Discard any existing cache entries of the wrong colour. These are - present quite often, if the kernel has recently used the page - internally, then given it up, then it's been allocated to the user. - */ - sh64_dcache_purge_coloured_phy_page(__pa(to), (unsigned long) to); - - coloured_to = (void *) sh64_make_unique_eaddr(address, __pa(to)); - sh64_page_copy(from, coloured_to); - - sh64_teardown_dtlb_cache_slot(); } -static void sh64_clear_user_page_coloured(void *to, unsigned long address) +void __flush_invalidate_region(void *start, int size) { - void *coloured_to; - - /* Discard any existing kernel-originated lines of the wrong colour (as - above) */ - sh64_dcache_purge_coloured_phy_page(__pa(to), (unsigned long) to); + unsigned long long ullend, addr, aligned_start; - coloured_to = (void *) sh64_make_unique_eaddr(address, __pa(to)); - sh64_page_clear(coloured_to); + aligned_start = (unsigned long long)(signed long long)(signed long) start; + addr = L1_CACHE_ALIGN(aligned_start); + ullend = (unsigned long long) (signed long long) (signed long) start + size; - sh64_teardown_dtlb_cache_slot(); + while (addr < ullend) { + __asm__ __volatile__ ("ocbi %0, 0" : : "r" (addr)); + addr += L1_CACHE_BYTES; + } } - #endif /* !CONFIG_DCACHE_DISABLED */ -/****************************************************************************/ - -/*########################################################################## - EXTERNALLY CALLABLE API. - ##########################################################################*/ - -/* These functions are described in Documentation/cachetlb.txt. - Each one of these functions varies in behaviour depending on whether the - I-cache and/or D-cache are configured out. - - Note that the Linux term 'flush' corresponds to what is termed 'purge' in - the sh/sh64 jargon for the D-cache, i.e. write back dirty data then - invalidate the cache lines, and 'invalidate' for the I-cache. - */ - -#undef FLUSH_TRACE - +/* + * Invalidate the entire contents of both caches, after writing back to + * memory any dirty data from the D-cache. + */ void flush_cache_all(void) { - /* Invalidate the entire contents of both caches, after writing back to - memory any dirty data from the D-cache. */ sh64_dcache_purge_all(); sh64_icache_inv_all(); } -/****************************************************************************/ - +/* + * Invalidate an entire user-address space from both caches, after + * writing back dirty data (e.g. for shared mmap etc). + * + * This could be coded selectively by inspecting all the tags then + * doing 4*alloco on any set containing a match (as for + * flush_cache_range), but fork/exit/execve (where this is called from) + * are expensive anyway. + * + * Have to do a purge here, despite the comments re I-cache below. + * There could be odd-coloured dirty data associated with the mm still + * in the cache - if this gets written out through natural eviction + * after the kernel has reused the page there will be chaos. + * + * The mm being torn down won't ever be active again, so any Icache + * lines tagged with its ASID won't be visible for the rest of the + * lifetime of this ASID cycle. Before the ASID gets reused, there + * will be a flush_cache_all. Hence we don't need to touch the + * I-cache. This is similar to the lack of action needed in + * flush_tlb_mm - see fault.c. + */ void flush_cache_mm(struct mm_struct *mm) { - /* Invalidate an entire user-address space from both caches, after - writing back dirty data (e.g. for shared mmap etc). */ - - /* This could be coded selectively by inspecting all the tags then - doing 4*alloco on any set containing a match (as for - flush_cache_range), but fork/exit/execve (where this is called from) - are expensive anyway. */ - - /* Have to do a purge here, despite the comments re I-cache below. - There could be odd-coloured dirty data associated with the mm still - in the cache - if this gets written out through natural eviction - after the kernel has reused the page there will be chaos. - */ - sh64_dcache_purge_all(); - - /* The mm being torn down won't ever be active again, so any Icache - lines tagged with its ASID won't be visible for the rest of the - lifetime of this ASID cycle. Before the ASID gets reused, there - will be a flush_cache_all. Hence we don't need to touch the - I-cache. This is similar to the lack of action needed in - flush_tlb_mm - see fault.c. */ } -/****************************************************************************/ - +/* + * Invalidate (from both caches) the range [start,end) of virtual + * addresses from the user address space specified by mm, after writing + * back any dirty data. + * + * Note, 'end' is 1 byte beyond the end of the range to flush. + */ void flush_cache_range(struct vm_area_struct *vma, unsigned long start, unsigned long end) { struct mm_struct *mm = vma->vm_mm; - /* Invalidate (from both caches) the range [start,end) of virtual - addresses from the user address space specified by mm, after writing - back any dirty data. - - Note, 'end' is 1 byte beyond the end of the range to flush. */ - sh64_dcache_purge_user_range(mm, start, end); sh64_icache_inv_user_page_range(mm, start, end); } -/****************************************************************************/ - -void flush_cache_page(struct vm_area_struct *vma, unsigned long eaddr, unsigned long pfn) +/* + * Invalidate any entries in either cache for the vma within the user + * address space vma->vm_mm for the page starting at virtual address + * 'eaddr'. This seems to be used primarily in breaking COW. Note, + * the I-cache must be searched too in case the page in question is + * both writable and being executed from (e.g. stack trampolines.) + * + * Note, this is called with pte lock held. + */ +void flush_cache_page(struct vm_area_struct *vma, unsigned long eaddr, + unsigned long pfn) { - /* Invalidate any entries in either cache for the vma within the user - address space vma->vm_mm for the page starting at virtual address - 'eaddr'. This seems to be used primarily in breaking COW. Note, - the I-cache must be searched too in case the page in question is - both writable and being executed from (e.g. stack trampolines.) - - Note, this is called with pte lock held. - */ - sh64_dcache_purge_phy_page(pfn << PAGE_SHIFT); - if (vma->vm_flags & VM_EXEC) { + if (vma->vm_flags & VM_EXEC) sh64_icache_inv_user_page(vma, eaddr); - } } -/****************************************************************************/ +void flush_dcache_page(struct page *page) +{ + sh64_dcache_purge_phy_page(page_to_phys(page)); + wmb(); +} -#ifndef CONFIG_DCACHE_DISABLED +/* + * Flush the range [start,end] of kernel virtual adddress space from + * the I-cache. The corresponding range must be purged from the + * D-cache also because the SH-5 doesn't have cache snooping between + * the caches. The addresses will be visible through the superpage + * mapping, therefore it's guaranteed that there no cache entries for + * the range in cache sets of the wrong colour. + */ +void flush_icache_range(unsigned long start, unsigned long end) +{ + __flush_purge_region((void *)start, end); + wmb(); + sh64_icache_inv_kernel_range(start, end); +} -void copy_user_page(void *to, void *from, unsigned long address, struct page *page) +/* + * Flush the range of user (defined by vma->vm_mm) address space starting + * at 'addr' for 'len' bytes from the cache. The range does not straddle + * a page boundary, the unique physical page containing the range is + * 'page'. This seems to be used mainly for invalidating an address + * range following a poke into the program text through the ptrace() call + * from another process (e.g. for BRK instruction insertion). + */ +void flush_icache_user_range(struct vm_area_struct *vma, + struct page *page, unsigned long addr, int len) { - /* 'from' and 'to' are kernel virtual addresses (within the superpage - mapping of the physical RAM). 'address' is the user virtual address - where the copy 'to' will be mapped after. This allows a custom - mapping to be used to ensure that the new copy is placed in the - right cache sets for the user to see it without having to bounce it - out via memory. Note however : the call to flush_page_to_ram in - (generic)/mm/memory.c:(break_cow) undoes all this good work in that one - very important case! - - TBD : can we guarantee that on every call, any cache entries for - 'from' are in the same colour sets as 'address' also? i.e. is this - always used just to deal with COW? (I suspect not). */ - - /* There are two possibilities here for when the page 'from' was last accessed: - * by the kernel : this is OK, no purge required. - * by the/a user (e.g. for break_COW) : need to purge. - - If the potential user mapping at 'address' is the same colour as - 'from' there is no need to purge any cache lines from the 'from' - page mapped into cache sets of colour 'address'. (The copy will be - accessing the page through 'from'). - */ - if (((address ^ (unsigned long) from) & CACHE_OC_SYN_MASK) != 0) { - sh64_dcache_purge_coloured_phy_page(__pa(from), address); - } + sh64_dcache_purge_coloured_phy_page(page_to_phys(page), addr); + mb(); - if (((address ^ (unsigned long) to) & CACHE_OC_SYN_MASK) == 0) { - /* No synonym problem on destination */ - sh64_page_copy(from, to); - } else { - sh64_copy_user_page_coloured(to, from, address); - } + if (vma->vm_flags & VM_EXEC) + sh64_icache_inv_user_small_range(vma->vm_mm, addr, len); +} + +/* + * For the address range [start,end), write back the data from the + * D-cache and invalidate the corresponding region of the I-cache for the + * current process. Used to flush signal trampolines on the stack to + * make them executable. + */ +void flush_cache_sigtramp(unsigned long vaddr) +{ + unsigned long end = vaddr + L1_CACHE_BYTES; - /* Note, don't need to flush 'from' page from the cache again - it's - done anyway by the generic code */ + __flush_wback_region((void *)vaddr, L1_CACHE_BYTES); + wmb(); + sh64_icache_inv_current_user_range(vaddr, end); } -void clear_user_page(void *to, unsigned long address, struct page *page) +/* + * These *MUST* lie in an area of virtual address space that's otherwise + * unused. + */ +#define UNIQUE_EADDR_START 0xe0000000UL +#define UNIQUE_EADDR_END 0xe8000000UL + +/* + * Given a physical address paddr, and a user virtual address user_eaddr + * which will eventually be mapped to it, create a one-off kernel-private + * eaddr mapped to the same paddr. This is used for creating special + * destination pages for copy_user_page and clear_user_page. + */ +static unsigned long sh64_make_unique_eaddr(unsigned long user_eaddr, + unsigned long paddr) { - /* 'to' is a kernel virtual address (within the superpage - mapping of the physical RAM). 'address' is the user virtual address - where the 'to' page will be mapped after. This allows a custom - mapping to be used to ensure that the new copy is placed in the - right cache sets for the user to see it without having to bounce it - out via memory. - */ + static unsigned long current_pointer = UNIQUE_EADDR_START; + unsigned long coloured_pointer; - if (((address ^ (unsigned long) to) & CACHE_OC_SYN_MASK) == 0) { - /* No synonym problem on destination */ - sh64_page_clear(to); - } else { - sh64_clear_user_page_coloured(to, address); + if (current_pointer == UNIQUE_EADDR_END) { + sh64_dcache_purge_all(); + current_pointer = UNIQUE_EADDR_START; } -} -#endif /* !CONFIG_DCACHE_DISABLED */ + coloured_pointer = (current_pointer & ~CACHE_OC_SYN_MASK) | + (user_eaddr & CACHE_OC_SYN_MASK); + sh64_setup_dtlb_cache_slot(coloured_pointer, get_asid(), paddr); -/****************************************************************************/ + current_pointer += (PAGE_SIZE << CACHE_OC_N_SYNBITS); -void flush_dcache_page(struct page *page) -{ - sh64_dcache_purge_phy_page(page_to_phys(page)); - wmb(); + return coloured_pointer; } -/****************************************************************************/ - -void flush_icache_range(unsigned long start, unsigned long end) +static void sh64_copy_user_page_coloured(void *to, void *from, + unsigned long address) { - /* Flush the range [start,end] of kernel virtual adddress space from - the I-cache. The corresponding range must be purged from the - D-cache also because the SH-5 doesn't have cache snooping between - the caches. The addresses will be visible through the superpage - mapping, therefore it's guaranteed that there no cache entries for - the range in cache sets of the wrong colour. + void *coloured_to; - Primarily used for cohering the I-cache after a module has - been loaded. */ + /* + * Discard any existing cache entries of the wrong colour. These are + * present quite often, if the kernel has recently used the page + * internally, then given it up, then it's been allocated to the user. + */ + sh64_dcache_purge_coloured_phy_page(__pa(to), (unsigned long)to); - /* We also make sure to purge the same range from the D-cache since - flush_page_to_ram() won't be doing this for us! */ + coloured_to = (void *)sh64_make_unique_eaddr(address, __pa(to)); + copy_page(from, coloured_to); - sh64_dcache_purge_kernel_range(start, end); - wmb(); - sh64_icache_inv_kernel_range(start, end); + sh64_teardown_dtlb_cache_slot(); } -/****************************************************************************/ - -void flush_icache_user_range(struct vm_area_struct *vma, - struct page *page, unsigned long addr, int len) +static void sh64_clear_user_page_coloured(void *to, unsigned long address) { - /* Flush the range of user (defined by vma->vm_mm) address space - starting at 'addr' for 'len' bytes from the cache. The range does - not straddle a page boundary, the unique physical page containing - the range is 'page'. This seems to be used mainly for invalidating - an address range following a poke into the program text through the - ptrace() call from another process (e.g. for BRK instruction - insertion). */ + void *coloured_to; - sh64_dcache_purge_coloured_phy_page(page_to_phys(page), addr); - mb(); + /* + * Discard any existing kernel-originated lines of the wrong + * colour (as above) + */ + sh64_dcache_purge_coloured_phy_page(__pa(to), (unsigned long)to); - if (vma->vm_flags & VM_EXEC) { - sh64_icache_inv_user_small_range(vma->vm_mm, addr, len); - } -} + coloured_to = (void *)sh64_make_unique_eaddr(address, __pa(to)); + clear_page(coloured_to); -/*########################################################################## - ARCH/SH64 PRIVATE CALLABLE API. - ##########################################################################*/ + sh64_teardown_dtlb_cache_slot(); +} -void flush_cache_sigtramp(unsigned long start, unsigned long end) +/* + * 'from' and 'to' are kernel virtual addresses (within the superpage + * mapping of the physical RAM). 'address' is the user virtual address + * where the copy 'to' will be mapped after. This allows a custom + * mapping to be used to ensure that the new copy is placed in the + * right cache sets for the user to see it without having to bounce it + * out via memory. Note however : the call to flush_page_to_ram in + * (generic)/mm/memory.c:(break_cow) undoes all this good work in that one + * very important case! + * + * TBD : can we guarantee that on every call, any cache entries for + * 'from' are in the same colour sets as 'address' also? i.e. is this + * always used just to deal with COW? (I suspect not). + * + * There are two possibilities here for when the page 'from' was last accessed: + * - by the kernel : this is OK, no purge required. + * - by the/a user (e.g. for break_COW) : need to purge. + * + * If the potential user mapping at 'address' is the same colour as + * 'from' there is no need to purge any cache lines from the 'from' + * page mapped into cache sets of colour 'address'. (The copy will be + * accessing the page through 'from'). + */ +void copy_user_page(void *to, void *from, unsigned long address, + struct page *page) { - /* For the address range [start,end), write back the data from the - D-cache and invalidate the corresponding region of the I-cache for - the current process. Used to flush signal trampolines on the stack - to make them executable. */ + if (((address ^ (unsigned long) from) & CACHE_OC_SYN_MASK) != 0) + sh64_dcache_purge_coloured_phy_page(__pa(from), address); - sh64_dcache_wback_current_user_range(start, end); - wmb(); - sh64_icache_inv_current_user_range(start, end); + if (((address ^ (unsigned long) to) & CACHE_OC_SYN_MASK) == 0) + copy_page(to, from); + else + sh64_copy_user_page_coloured(to, from, address); } +/* + * 'to' is a kernel virtual address (within the superpage mapping of the + * physical RAM). 'address' is the user virtual address where the 'to' + * page will be mapped after. This allows a custom mapping to be used to + * ensure that the new copy is placed in the right cache sets for the + * user to see it without having to bounce it out via memory. + */ +void clear_user_page(void *to, unsigned long address, struct page *page) +{ + if (((address ^ (unsigned long) to) & CACHE_OC_SYN_MASK) == 0) + clear_page(to); + else + sh64_clear_user_page_coloured(to, address); +} diff --git a/arch/sh/mm/consistent.c b/arch/sh/mm/consistent.c index 7b2131c9eed..d3c33fc5b1c 100644 --- a/arch/sh/mm/consistent.c +++ b/arch/sh/mm/consistent.c @@ -26,7 +26,7 @@ struct dma_coherent_mem { void *dma_alloc_coherent(struct device *dev, size_t size, dma_addr_t *dma_handle, gfp_t gfp) { - void *ret; + void *ret, *ret_nocache; struct dma_coherent_mem *mem = dev ? dev->dma_mem : NULL; int order = get_order(size); @@ -44,17 +44,24 @@ void *dma_alloc_coherent(struct device *dev, size_t size, } ret = (void *)__get_free_pages(gfp, order); - - if (ret != NULL) { - memset(ret, 0, size); - /* - * Pages from the page allocator may have data present in - * cache. So flush the cache before using uncached memory. - */ - dma_cache_sync(NULL, ret, size, DMA_BIDIRECTIONAL); - *dma_handle = virt_to_phys(ret); + if (!ret) + return NULL; + + memset(ret, 0, size); + /* + * Pages from the page allocator may have data present in + * cache. So flush the cache before using uncached memory. + */ + dma_cache_sync(dev, ret, size, DMA_BIDIRECTIONAL); + + ret_nocache = ioremap_nocache(virt_to_phys(ret), size); + if (!ret_nocache) { + free_pages((unsigned long)ret, order); + return NULL; } - return ret; + + *dma_handle = virt_to_phys(ret); + return ret_nocache; } EXPORT_SYMBOL(dma_alloc_coherent); @@ -71,7 +78,8 @@ void dma_free_coherent(struct device *dev, size_t size, } else { WARN_ON(irqs_disabled()); /* for portability */ BUG_ON(mem && mem->flags & DMA_MEMORY_EXCLUSIVE); - free_pages((unsigned long)vaddr, order); + free_pages((unsigned long)phys_to_virt(dma_handle), order); + iounmap(vaddr); } } EXPORT_SYMBOL(dma_free_coherent); diff --git a/arch/sh/mm/fault_32.c b/arch/sh/mm/fault_32.c index 33b43d20e9f..d1fa27594c6 100644 --- a/arch/sh/mm/fault_32.c +++ b/arch/sh/mm/fault_32.c @@ -15,6 +15,7 @@ #include <linux/mm.h> #include <linux/hardirq.h> #include <linux/kprobes.h> +#include <asm/io_trapped.h> #include <asm/system.h> #include <asm/mmu_context.h> #include <asm/tlbflush.h> @@ -163,6 +164,8 @@ no_context: if (fixup_exception(regs)) return; + if (handle_trapped_io(regs, address)) + return; /* * Oops. The kernel tried to access some bad page. We'll have to * terminate things with extreme prejudice. @@ -296,6 +299,14 @@ asmlinkage int __kprobes __do_page_fault(struct pt_regs *regs, entry = pte_mkdirty(entry); entry = pte_mkyoung(entry); +#if defined(CONFIG_CPU_SH4) && !defined(CONFIG_SMP) + /* + * ITLB is not affected by "ldtlb" instruction. + * So, we need to flush the entry by ourselves. + */ + local_flush_tlb_one(get_asid(), address & PAGE_MASK); +#endif + set_pte(pte, entry); update_mmu_cache(NULL, address, entry); diff --git a/arch/sh/mm/init.c b/arch/sh/mm/init.c index 2918c6b1465..e2ed6dd252b 100644 --- a/arch/sh/mm/init.c +++ b/arch/sh/mm/init.c @@ -203,6 +203,7 @@ void __init paging_init(void) free_area_init_nodes(max_zone_pfns); +#ifdef CONFIG_SUPERH32 /* Set up the uncached fixmap */ set_fixmap_nocache(FIX_UNCACHED, __pa(&__uncached_start)); @@ -214,6 +215,7 @@ void __init paging_init(void) */ cached_to_uncached = P2SEG - P1SEG; #endif +#endif } static struct kcore_list kcore_mem, kcore_vmalloc; diff --git a/arch/sh/tools/mach-types b/arch/sh/tools/mach-types index 25810670a0f..67997af25c0 100644 --- a/arch/sh/tools/mach-types +++ b/arch/sh/tools/mach-types @@ -45,3 +45,5 @@ MAGICPANELR2 SH_MAGIC_PANEL_R2 R2D_PLUS RTS7751R2D_PLUS R2D_1 RTS7751R2D_1 CAYMAN SH_CAYMAN +SDK7780 SH_SDK7780 +MIGOR SH_MIGOR diff --git a/arch/sparc/kernel/pcic.c b/arch/sparc/kernel/pcic.c index 4cd5d7818dc..a6a6f982337 100644 --- a/arch/sparc/kernel/pcic.c +++ b/arch/sparc/kernel/pcic.c @@ -713,10 +713,10 @@ static irqreturn_t pcic_timer_handler (int irq, void *h) write_seqlock(&xtime_lock); /* Dummy, to show that we remember */ pcic_clear_clock_irq(); do_timer(1); + write_sequnlock(&xtime_lock); #ifndef CONFIG_SMP update_process_times(user_mode(get_irq_regs())); #endif - write_sequnlock(&xtime_lock); return IRQ_HANDLED; } diff --git a/arch/sparc/kernel/time.c b/arch/sparc/kernel/time.c index 00b393c3a4a..cfaf22c05bc 100644 --- a/arch/sparc/kernel/time.c +++ b/arch/sparc/kernel/time.c @@ -128,10 +128,6 @@ irqreturn_t timer_interrupt(int irq, void *dev_id) clear_clock_irq(); do_timer(1); -#ifndef CONFIG_SMP - update_process_times(user_mode(get_irq_regs())); -#endif - /* Determine when to update the Mostek clock. */ if (ntp_synced() && @@ -145,6 +141,9 @@ irqreturn_t timer_interrupt(int irq, void *dev_id) } write_sequnlock(&xtime_lock); +#ifndef CONFIG_SMP + update_process_times(user_mode(get_irq_regs())); +#endif return IRQ_HANDLED; } diff --git a/arch/sparc64/solaris/fs.c b/arch/sparc64/solaris/fs.c index 9311bfe4f2f..7d035f0d3ae 100644 --- a/arch/sparc64/solaris/fs.c +++ b/arch/sparc64/solaris/fs.c @@ -434,9 +434,9 @@ asmlinkage int solaris_statvfs(u32 path, u32 buf) error = user_path_walk(A(path),&nd); if (!error) { - struct inode * inode = nd.dentry->d_inode; - error = report_statvfs(nd.mnt, inode, buf); - path_release(&nd); + struct inode *inode = nd.path.dentry->d_inode; + error = report_statvfs(nd.path.mnt, inode, buf); + path_put(&nd.path); } return error; } @@ -464,9 +464,9 @@ asmlinkage int solaris_statvfs64(u32 path, u32 buf) lock_kernel(); error = user_path_walk(A(path), &nd); if (!error) { - struct inode * inode = nd.dentry->d_inode; - error = report_statvfs64(nd.mnt, inode, buf); - path_release(&nd); + struct inode *inode = nd.path.dentry->d_inode; + error = report_statvfs64(nd.path.mnt, inode, buf); + path_put(&nd.path); } unlock_kernel(); return error; diff --git a/arch/um/drivers/mconsole_kern.c b/arch/um/drivers/mconsole_kern.c index ebb265c07e4..19d579d74d2 100644 --- a/arch/um/drivers/mconsole_kern.c +++ b/arch/um/drivers/mconsole_kern.c @@ -145,8 +145,8 @@ void mconsole_proc(struct mc_request *req) } up_write(&super->s_umount); - nd.dentry = super->s_root; - nd.mnt = NULL; + nd.path.dentry = super->s_root; + nd.path.mnt = NULL; nd.flags = O_RDONLY + 1; nd.last_type = LAST_ROOT; @@ -159,7 +159,7 @@ void mconsole_proc(struct mc_request *req) goto out_kill; } - file = dentry_open(nd.dentry, nd.mnt, O_RDONLY); + file = dentry_open(nd.path.dentry, nd.path.mnt, O_RDONLY); if (IS_ERR(file)) { mconsole_reply(req, "Failed to open file", 1, 0); goto out_kill; diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig index aaed1a3b92d..3be2305709b 100644 --- a/arch/x86/Kconfig +++ b/arch/x86/Kconfig @@ -21,6 +21,8 @@ config X86 select HAVE_IDE select HAVE_OPROFILE select HAVE_KPROBES + select HAVE_KVM + config GENERIC_LOCKBREAK def_bool n @@ -119,8 +121,6 @@ config ARCH_HAS_CPU_RELAX config HAVE_SETUP_PER_CPU_AREA def_bool X86_64 -select HAVE_KVM - config ARCH_HIBERNATION_POSSIBLE def_bool y depends on !SMP || !X86_VOYAGER diff --git a/arch/x86/kernel/acpi/cstate.c b/arch/x86/kernel/acpi/cstate.c index 10b67170b13..8ca3557a6d5 100644 --- a/arch/x86/kernel/acpi/cstate.c +++ b/arch/x86/kernel/acpi/cstate.c @@ -126,6 +126,8 @@ int acpi_processor_ffh_cstate_probe(unsigned int cpu, printk(KERN_DEBUG "Monitor-Mwait will be used to enter C-%d " "state\n", cx->type); } + snprintf(cx->desc, ACPI_CX_DESC_LEN, "ACPI FFH INTEL MWAIT 0x%x", + cx->address); out: set_cpus_allowed(current, saved_mask); diff --git a/arch/x86/kernel/asm-offsets_32.c b/arch/x86/kernel/asm-offsets_32.c index afd84463b71..a33d5301799 100644 --- a/arch/x86/kernel/asm-offsets_32.c +++ b/arch/x86/kernel/asm-offsets_32.c @@ -20,10 +20,8 @@ #include <xen/interface/xen.h> -#ifdef CONFIG_LGUEST_GUEST #include <linux/lguest.h> #include "../../../drivers/lguest/lg.h" -#endif #define DEFINE(sym, val) \ asm volatile("\n->" #sym " %0 " #val : : "i" (val)) @@ -134,6 +132,10 @@ void foo(void) BLANK(); OFFSET(LGUEST_DATA_irq_enabled, lguest_data, irq_enabled); OFFSET(LGUEST_DATA_pgdir, lguest_data, pgdir); +#endif + +#ifdef CONFIG_LGUEST + BLANK(); OFFSET(LGUEST_PAGES_host_gdt_desc, lguest_pages, state.host_gdt_desc); OFFSET(LGUEST_PAGES_host_idt_desc, lguest_pages, state.host_idt_desc); OFFSET(LGUEST_PAGES_host_cr3, lguest_pages, state.host_cr3); diff --git a/arch/x86/kernel/efi.c b/arch/x86/kernel/efi.c index 32dd62b36ff..0c0eeb163d9 100644 --- a/arch/x86/kernel/efi.c +++ b/arch/x86/kernel/efi.c @@ -384,9 +384,6 @@ static void __init runtime_code_page_mkexec(void) efi_memory_desc_t *md; void *p; - if (!(__supported_pte_mask & _PAGE_NX)) - return; - /* Make EFI runtime service code area executable */ for (p = memmap.map; p < memmap.map_end; p += memmap.desc_size) { md = p; @@ -394,7 +391,7 @@ static void __init runtime_code_page_mkexec(void) if (md->type != EFI_RUNTIME_SERVICES_CODE) continue; - set_memory_x(md->virt_addr, md->num_pages << EFI_PAGE_SHIFT); + set_memory_x(md->virt_addr, md->num_pages); } } @@ -428,9 +425,6 @@ void __init efi_enter_virtual_mode(void) else va = efi_ioremap(md->phys_addr, size); - if (md->attribute & EFI_MEMORY_WB) - set_memory_uc(md->virt_addr, size); - md->virt_addr = (u64) (unsigned long) va; if (!va) { @@ -439,6 +433,9 @@ void __init efi_enter_virtual_mode(void) continue; } + if (!(md->attribute & EFI_MEMORY_WB)) + set_memory_uc(md->virt_addr, md->num_pages); + systab = (u64) (unsigned long) efi_phys.systab; if (md->phys_addr <= systab && systab < end) { systab += md->virt_addr - md->phys_addr; @@ -476,7 +473,8 @@ void __init efi_enter_virtual_mode(void) efi.get_next_high_mono_count = virt_efi_get_next_high_mono_count; efi.reset_system = virt_efi_reset_system; efi.set_virtual_address_map = virt_efi_set_virtual_address_map; - runtime_code_page_mkexec(); + if (__supported_pte_mask & _PAGE_NX) + runtime_code_page_mkexec(); early_iounmap(memmap.map, memmap.nr_map * memmap.desc_size); memmap.map = NULL; } diff --git a/arch/x86/kernel/efi_64.c b/arch/x86/kernel/efi_64.c index 09d5c233093..d143a1e76b3 100644 --- a/arch/x86/kernel/efi_64.c +++ b/arch/x86/kernel/efi_64.c @@ -35,6 +35,7 @@ #include <asm/tlbflush.h> #include <asm/proto.h> #include <asm/efi.h> +#include <asm/cacheflush.h> static pgd_t save_pgd __initdata; static unsigned long efi_flags __initdata; @@ -43,22 +44,15 @@ static void __init early_mapping_set_exec(unsigned long start, unsigned long end, int executable) { - pte_t *kpte; - unsigned int level; - - while (start < end) { - kpte = lookup_address((unsigned long)__va(start), &level); - BUG_ON(!kpte); - if (executable) - set_pte(kpte, pte_mkexec(*kpte)); - else - set_pte(kpte, __pte((pte_val(*kpte) | _PAGE_NX) & \ - __supported_pte_mask)); - if (level == PG_LEVEL_4K) - start = (start + PAGE_SIZE) & PAGE_MASK; - else - start = (start + PMD_SIZE) & PMD_MASK; - } + unsigned long num_pages; + + start &= PMD_MASK; + end = (end + PMD_SIZE - 1) & PMD_MASK; + num_pages = (end - start) >> PAGE_SHIFT; + if (executable) + set_memory_x((unsigned long)__va(start), num_pages); + else + set_memory_nx((unsigned long)__va(start), num_pages); } static void __init early_runtime_code_mapping_set_exec(int executable) @@ -74,7 +68,7 @@ static void __init early_runtime_code_mapping_set_exec(int executable) md = p; if (md->type == EFI_RUNTIME_SERVICES_CODE) { unsigned long end; - end = md->phys_addr + (md->num_pages << PAGE_SHIFT); + end = md->phys_addr + (md->num_pages << EFI_PAGE_SHIFT); early_mapping_set_exec(md->phys_addr, end, executable); } } @@ -84,8 +78,8 @@ void __init efi_call_phys_prelog(void) { unsigned long vaddress; - local_irq_save(efi_flags); early_runtime_code_mapping_set_exec(1); + local_irq_save(efi_flags); vaddress = (unsigned long)__va(0x0UL); save_pgd = *pgd_offset_k(0x0UL); set_pgd(pgd_offset_k(0x0UL), *pgd_offset_k(vaddress)); @@ -98,9 +92,9 @@ void __init efi_call_phys_epilog(void) * After the lock is released, the original page table is restored. */ set_pgd(pgd_offset_k(0x0UL), save_pgd); - early_runtime_code_mapping_set_exec(0); __flush_tlb_all(); local_irq_restore(efi_flags); + early_runtime_code_mapping_set_exec(0); } void __init efi_reserve_bootmem(void) diff --git a/arch/x86/kernel/head64.c b/arch/x86/kernel/head64.c index 24dbf56928d..ad2440832de 100644 --- a/arch/x86/kernel/head64.c +++ b/arch/x86/kernel/head64.c @@ -88,6 +88,9 @@ void __init x86_64_start_kernel(char * real_mode_data) /* Make NULL pointers segfault */ zap_identity_mappings(); + /* Cleanup the over mapped high alias */ + cleanup_highmap(); + for (i = 0; i < IDT_ENTRIES; i++) { #ifdef CONFIG_EARLY_PRINTK set_intr_gate(i, &early_idt_handlers[i]); diff --git a/arch/x86/kernel/head_64.S b/arch/x86/kernel/head_64.S index 09b38d539b0..53e5820d605 100644 --- a/arch/x86/kernel/head_64.S +++ b/arch/x86/kernel/head_64.S @@ -107,8 +107,13 @@ startup_64: movq %rdx, 0(%rbx, %rax, 8) ident_complete: - /* Fixup the kernel text+data virtual addresses + /* + * Fixup the kernel text+data virtual addresses. Note that + * we might write invalid pmds, when the kernel is relocated + * cleanup_highmap() fixes this up along with the mappings + * beyond _end. */ + leaq level2_kernel_pgt(%rip), %rdi leaq 4096(%rdi), %r8 /* See if it is a valid page table entry */ diff --git a/arch/x86/kernel/i8253.c b/arch/x86/kernel/i8253.c index ef62b07b2b4..8540abe86ad 100644 --- a/arch/x86/kernel/i8253.c +++ b/arch/x86/kernel/i8253.c @@ -95,7 +95,7 @@ static int pit_next_event(unsigned long delta, struct clock_event_device *evt) * registered. This mechanism replaces the previous #ifdef LOCAL_APIC - * !using_apic_timer decisions in do_timer_interrupt_hook() */ -struct clock_event_device pit_clockevent = { +static struct clock_event_device pit_clockevent = { .name = "pit", .features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT, .set_mode = init_pit_timer, diff --git a/arch/x86/kernel/pci-gart_64.c b/arch/x86/kernel/pci-gart_64.c index 65f6acb025c..faf3229f8fb 100644 --- a/arch/x86/kernel/pci-gart_64.c +++ b/arch/x86/kernel/pci-gart_64.c @@ -749,6 +749,15 @@ void __init gart_iommu_init(void) */ set_memory_np((unsigned long)__va(iommu_bus_base), iommu_size >> PAGE_SHIFT); + /* + * Tricky. The GART table remaps the physical memory range, + * so the CPU wont notice potential aliases and if the memory + * is remapped to UC later on, we might surprise the PCI devices + * with a stray writeout of a cacheline. So play it sure and + * do an explicit, full-scale wbinvd() _after_ having marked all + * the pages as Not-Present: + */ + wbinvd(); /* * Try to workaround a bug (thanks to BenH) diff --git a/arch/x86/kernel/reboot.c b/arch/x86/kernel/reboot.c index 5818dc28167..7fd6ac43e4a 100644 --- a/arch/x86/kernel/reboot.c +++ b/arch/x86/kernel/reboot.c @@ -326,7 +326,7 @@ static inline void kb_wait(void) } } -void machine_emergency_restart(void) +static void native_machine_emergency_restart(void) { int i; @@ -376,7 +376,7 @@ void machine_emergency_restart(void) } } -void machine_shutdown(void) +static void native_machine_shutdown(void) { /* Stop the cpus and apics */ #ifdef CONFIG_SMP @@ -420,7 +420,7 @@ void machine_shutdown(void) #endif } -void machine_restart(char *__unused) +static void native_machine_restart(char *__unused) { printk("machine restart\n"); @@ -429,11 +429,11 @@ void machine_restart(char *__unused) machine_emergency_restart(); } -void machine_halt(void) +static void native_machine_halt(void) { } -void machine_power_off(void) +static void native_machine_power_off(void) { if (pm_power_off) { if (!reboot_force) @@ -443,9 +443,35 @@ void machine_power_off(void) } struct machine_ops machine_ops = { - .power_off = machine_power_off, - .shutdown = machine_shutdown, - .emergency_restart = machine_emergency_restart, - .restart = machine_restart, - .halt = machine_halt + .power_off = native_machine_power_off, + .shutdown = native_machine_shutdown, + .emergency_restart = native_machine_emergency_restart, + .restart = native_machine_restart, + .halt = native_machine_halt }; + +void machine_power_off(void) +{ + machine_ops.power_off(); +} + +void machine_shutdown(void) +{ + machine_ops.shutdown(); +} + +void machine_emergency_restart(void) +{ + machine_ops.emergency_restart(); +} + +void machine_restart(char *cmd) +{ + machine_ops.restart(cmd); +} + +void machine_halt(void) +{ + machine_ops.halt(); +} + diff --git a/arch/x86/kernel/test_rodata.c b/arch/x86/kernel/test_rodata.c index 4c163772000..c29e235792a 100644 --- a/arch/x86/kernel/test_rodata.c +++ b/arch/x86/kernel/test_rodata.c @@ -10,8 +10,8 @@ * of the License. */ #include <linux/module.h> +#include <asm/cacheflush.h> #include <asm/sections.h> -extern int rodata_test_data; int rodata_test(void) { diff --git a/arch/x86/kernel/traps_64.c b/arch/x86/kernel/traps_64.c index efc66df728b..04546668191 100644 --- a/arch/x86/kernel/traps_64.c +++ b/arch/x86/kernel/traps_64.c @@ -84,7 +84,7 @@ static inline void conditional_sti(struct pt_regs *regs) static inline void preempt_conditional_sti(struct pt_regs *regs) { - preempt_disable(); + inc_preempt_count(); if (regs->flags & X86_EFLAGS_IF) local_irq_enable(); } @@ -95,7 +95,7 @@ static inline void preempt_conditional_cli(struct pt_regs *regs) local_irq_disable(); /* Make sure to not schedule here because we could be running on an exception stack. */ - preempt_enable_no_resched(); + dec_preempt_count(); } int kstack_depth_to_print = 12; diff --git a/arch/x86/mm/fault.c b/arch/x86/mm/fault.c index 621afb6343d..fdc667422df 100644 --- a/arch/x86/mm/fault.c +++ b/arch/x86/mm/fault.c @@ -186,7 +186,7 @@ static int bad_address(void *p) } #endif -void dump_pagetable(unsigned long address) +static void dump_pagetable(unsigned long address) { #ifdef CONFIG_X86_32 __typeof__(pte_val(__pte(0))) page; diff --git a/arch/x86/mm/init_32.c b/arch/x86/mm/init_32.c index 8106bba41ec..ee1091a4696 100644 --- a/arch/x86/mm/init_32.c +++ b/arch/x86/mm/init_32.c @@ -47,6 +47,7 @@ #include <asm/sections.h> #include <asm/paravirt.h> #include <asm/setup.h> +#include <asm/cacheflush.h> unsigned int __VMALLOC_RESERVE = 128 << 20; diff --git a/arch/x86/mm/init_64.c b/arch/x86/mm/init_64.c index b59fc238151..bb652f5a93f 100644 --- a/arch/x86/mm/init_64.c +++ b/arch/x86/mm/init_64.c @@ -45,6 +45,7 @@ #include <asm/sections.h> #include <asm/kdebug.h> #include <asm/numa.h> +#include <asm/cacheflush.h> const struct dma_mapping_ops *dma_ops; EXPORT_SYMBOL(dma_ops); @@ -170,6 +171,33 @@ set_pte_phys(unsigned long vaddr, unsigned long phys, pgprot_t prot) __flush_tlb_one(vaddr); } +/* + * The head.S code sets up the kernel high mapping from: + * __START_KERNEL_map to __START_KERNEL_map + KERNEL_TEXT_SIZE + * + * phys_addr holds the negative offset to the kernel, which is added + * to the compile time generated pmds. This results in invalid pmds up + * to the point where we hit the physaddr 0 mapping. + * + * We limit the mappings to the region from _text to _end. _end is + * rounded up to the 2MB boundary. This catches the invalid pmds as + * well, as they are located before _text: + */ +void __init cleanup_highmap(void) +{ + unsigned long vaddr = __START_KERNEL_map; + unsigned long end = round_up((unsigned long)_end, PMD_SIZE) - 1; + pmd_t *pmd = level2_kernel_pgt; + pmd_t *last_pmd = pmd + PTRS_PER_PMD; + + for (; pmd < last_pmd; pmd++, vaddr += PMD_SIZE) { + if (!pmd_present(*pmd)) + continue; + if (vaddr < (unsigned long) _text || vaddr > end) + set_pmd(pmd, __pmd(0)); + } +} + /* NOTE: this is meant to be run only at boot */ void __init __set_fixmap(enum fixed_addresses idx, unsigned long phys, pgprot_t prot) diff --git a/arch/x86/mm/ioremap.c b/arch/x86/mm/ioremap.c index a4897a85268..9f42d7e9c15 100644 --- a/arch/x86/mm/ioremap.c +++ b/arch/x86/mm/ioremap.c @@ -265,7 +265,9 @@ static __initdata pte_t bm_pte[PAGE_SIZE/sizeof(pte_t)] static inline pmd_t * __init early_ioremap_pmd(unsigned long addr) { - pgd_t *pgd = &swapper_pg_dir[pgd_index(addr)]; + /* Don't assume we're using swapper_pg_dir at this point */ + pgd_t *base = __va(read_cr3()); + pgd_t *pgd = &base[pgd_index(addr)]; pud_t *pud = pud_offset(pgd, addr); pmd_t *pmd = pmd_offset(pud, addr); diff --git a/arch/x86/mm/numa_64.c b/arch/x86/mm/numa_64.c index 1aecc658cd7..59898fb0a4a 100644 --- a/arch/x86/mm/numa_64.c +++ b/arch/x86/mm/numa_64.c @@ -494,11 +494,13 @@ void __init numa_initmem_init(unsigned long start_pfn, unsigned long end_pfn) int i; nodes_clear(node_possible_map); + nodes_clear(node_online_map); #ifdef CONFIG_NUMA_EMU if (cmdline && !numa_emulation(start_pfn, end_pfn)) return; nodes_clear(node_possible_map); + nodes_clear(node_online_map); #endif #ifdef CONFIG_ACPI_NUMA @@ -506,6 +508,7 @@ void __init numa_initmem_init(unsigned long start_pfn, unsigned long end_pfn) end_pfn << PAGE_SHIFT)) return; nodes_clear(node_possible_map); + nodes_clear(node_online_map); #endif #ifdef CONFIG_K8_NUMA @@ -513,6 +516,7 @@ void __init numa_initmem_init(unsigned long start_pfn, unsigned long end_pfn) end_pfn<<PAGE_SHIFT)) return; nodes_clear(node_possible_map); + nodes_clear(node_online_map); #endif printk(KERN_INFO "%s\n", numa_off ? "NUMA turned off" : "No NUMA configuration found"); @@ -524,7 +528,6 @@ void __init numa_initmem_init(unsigned long start_pfn, unsigned long end_pfn) memnode_shift = 63; memnodemap = memnode.embedded_map; memnodemap[0] = 0; - nodes_clear(node_online_map); node_set_online(0); node_set(0, node_possible_map); for (i = 0; i < NR_CPUS; i++) diff --git a/arch/x86/mm/pageattr.c b/arch/x86/mm/pageattr.c index 440210a2277..3ee14996c82 100644 --- a/arch/x86/mm/pageattr.c +++ b/arch/x86/mm/pageattr.c @@ -16,6 +16,7 @@ #include <asm/sections.h> #include <asm/uaccess.h> #include <asm/pgalloc.h> +#include <asm/proto.h> /* * The current flushing context - we pass it instead of 5 arguments: @@ -26,8 +27,23 @@ struct cpa_data { pgprot_t mask_clr; int numpages; int flushtlb; + unsigned long pfn; }; +#ifdef CONFIG_X86_64 + +static inline unsigned long highmap_start_pfn(void) +{ + return __pa(_text) >> PAGE_SHIFT; +} + +static inline unsigned long highmap_end_pfn(void) +{ + return __pa(round_up((unsigned long)_end, PMD_SIZE)) >> PAGE_SHIFT; +} + +#endif + static inline int within(unsigned long addr, unsigned long start, unsigned long end) { @@ -123,29 +139,14 @@ static void cpa_flush_range(unsigned long start, int numpages, int cache) } } -#define HIGH_MAP_START __START_KERNEL_map -#define HIGH_MAP_END (__START_KERNEL_map + KERNEL_TEXT_SIZE) - - -/* - * Converts a virtual address to a X86-64 highmap address - */ -static unsigned long virt_to_highmap(void *address) -{ -#ifdef CONFIG_X86_64 - return __pa((unsigned long)address) + HIGH_MAP_START - phys_base; -#else - return (unsigned long)address; -#endif -} - /* * Certain areas of memory on x86 require very specific protection flags, * for example the BIOS area or kernel text. Callers don't always get this * right (again, ioremap() on BIOS memory is not uncommon) so this function * checks and fixes these known static required protection bits. */ -static inline pgprot_t static_protections(pgprot_t prot, unsigned long address) +static inline pgprot_t static_protections(pgprot_t prot, unsigned long address, + unsigned long pfn) { pgprot_t forbidden = __pgprot(0); @@ -153,30 +154,23 @@ static inline pgprot_t static_protections(pgprot_t prot, unsigned long address) * The BIOS area between 640k and 1Mb needs to be executable for * PCI BIOS based config access (CONFIG_PCI_GOBIOS) support. */ - if (within(__pa(address), BIOS_BEGIN, BIOS_END)) + if (within(pfn, BIOS_BEGIN >> PAGE_SHIFT, BIOS_END >> PAGE_SHIFT)) pgprot_val(forbidden) |= _PAGE_NX; /* * The kernel text needs to be executable for obvious reasons - * Does not cover __inittext since that is gone later on + * Does not cover __inittext since that is gone later on. On + * 64bit we do not enforce !NX on the low mapping */ if (within(address, (unsigned long)_text, (unsigned long)_etext)) pgprot_val(forbidden) |= _PAGE_NX; - /* - * Do the same for the x86-64 high kernel mapping - */ - if (within(address, virt_to_highmap(_text), virt_to_highmap(_etext))) - pgprot_val(forbidden) |= _PAGE_NX; - /* The .rodata section needs to be read-only */ - if (within(address, (unsigned long)__start_rodata, - (unsigned long)__end_rodata)) - pgprot_val(forbidden) |= _PAGE_RW; /* - * Do the same for the x86-64 high kernel mapping + * The .rodata section needs to be read-only. Using the pfn + * catches all aliases. */ - if (within(address, virt_to_highmap(__start_rodata), - virt_to_highmap(__end_rodata))) + if (within(pfn, __pa((unsigned long)__start_rodata) >> PAGE_SHIFT, + __pa((unsigned long)__end_rodata) >> PAGE_SHIFT)) pgprot_val(forbidden) |= _PAGE_RW; prot = __pgprot(pgprot_val(prot) & ~pgprot_val(forbidden)); @@ -253,7 +247,7 @@ static int try_preserve_large_page(pte_t *kpte, unsigned long address, struct cpa_data *cpa) { - unsigned long nextpage_addr, numpages, pmask, psize, flags, addr; + unsigned long nextpage_addr, numpages, pmask, psize, flags, addr, pfn; pte_t new_pte, old_pte, *tmp; pgprot_t old_prot, new_prot; int i, do_split = 1; @@ -275,8 +269,8 @@ try_preserve_large_page(pte_t *kpte, unsigned long address, break; #ifdef CONFIG_X86_64 case PG_LEVEL_1G: - psize = PMD_PAGE_SIZE; - pmask = PMD_PAGE_MASK; + psize = PUD_PAGE_SIZE; + pmask = PUD_PAGE_MASK; break; #endif default: @@ -301,7 +295,15 @@ try_preserve_large_page(pte_t *kpte, unsigned long address, pgprot_val(new_prot) &= ~pgprot_val(cpa->mask_clr); pgprot_val(new_prot) |= pgprot_val(cpa->mask_set); - new_prot = static_protections(new_prot, address); + + /* + * old_pte points to the large page base address. So we need + * to add the offset of the virtual address: + */ + pfn = pte_pfn(old_pte) + ((address & (psize - 1)) >> PAGE_SHIFT); + cpa->pfn = pfn; + + new_prot = static_protections(new_prot, address, pfn); /* * We need to check the full range, whether @@ -309,8 +311,9 @@ try_preserve_large_page(pte_t *kpte, unsigned long address, * the pages in the range we try to preserve: */ addr = address + PAGE_SIZE; - for (i = 1; i < cpa->numpages; i++, addr += PAGE_SIZE) { - pgprot_t chk_prot = static_protections(new_prot, addr); + pfn++; + for (i = 1; i < cpa->numpages; i++, addr += PAGE_SIZE, pfn++) { + pgprot_t chk_prot = static_protections(new_prot, addr, pfn); if (pgprot_val(chk_prot) != pgprot_val(new_prot)) goto out_unlock; @@ -505,46 +508,51 @@ out_unlock: return 0; } -static int __change_page_attr(unsigned long address, struct cpa_data *cpa) +static int __change_page_attr(struct cpa_data *cpa, int primary) { + unsigned long address = cpa->vaddr; int do_split, err; unsigned int level; struct page *kpte_page; - pte_t *kpte; + pte_t *kpte, old_pte; repeat: kpte = lookup_address(address, &level); if (!kpte) + return primary ? -EINVAL : 0; + + old_pte = *kpte; + if (!pte_val(old_pte)) { + if (!primary) + return 0; + printk(KERN_WARNING "CPA: called for zero pte. " + "vaddr = %lx cpa->vaddr = %lx\n", address, + cpa->vaddr); + WARN_ON(1); return -EINVAL; + } kpte_page = virt_to_page(kpte); BUG_ON(PageLRU(kpte_page)); BUG_ON(PageCompound(kpte_page)); if (level == PG_LEVEL_4K) { - pte_t new_pte, old_pte = *kpte; + pte_t new_pte; pgprot_t new_prot = pte_pgprot(old_pte); - - if(!pte_val(old_pte)) { - printk(KERN_WARNING "CPA: called for zero pte. " - "vaddr = %lx cpa->vaddr = %lx\n", address, - cpa->vaddr); - WARN_ON(1); - return -EINVAL; - } + unsigned long pfn = pte_pfn(old_pte); pgprot_val(new_prot) &= ~pgprot_val(cpa->mask_clr); pgprot_val(new_prot) |= pgprot_val(cpa->mask_set); - new_prot = static_protections(new_prot, address); + new_prot = static_protections(new_prot, address, pfn); /* * We need to keep the pfn from the existing PTE, * after all we're only going to change it's attributes * not the memory it points to */ - new_pte = pfn_pte(pte_pfn(old_pte), canon_pgprot(new_prot)); - + new_pte = pfn_pte(pfn, canon_pgprot(new_prot)); + cpa->pfn = pfn; /* * Do we really change anything ? */ @@ -581,67 +589,59 @@ repeat: return err; } -/** - * change_page_attr_addr - Change page table attributes in linear mapping - * @address: Virtual address in linear mapping. - * @prot: New page table attribute (PAGE_*) - * - * Change page attributes of a page in the direct mapping. This is a variant - * of change_page_attr() that also works on memory holes that do not have - * mem_map entry (pfn_valid() is false). - * - * See change_page_attr() documentation for more details. - * - * Modules and drivers should use the set_memory_* APIs instead. - */ -static int change_page_attr_addr(struct cpa_data *cpa) +static int __change_page_attr_set_clr(struct cpa_data *cpa, int checkalias); + +static int cpa_process_alias(struct cpa_data *cpa) { - int err; - unsigned long address = cpa->vaddr; + struct cpa_data alias_cpa; + int ret = 0; -#ifdef CONFIG_X86_64 - unsigned long phys_addr = __pa(address); + if (cpa->pfn > max_pfn_mapped) + return 0; /* - * If we are inside the high mapped kernel range, then we - * fixup the low mapping first. __va() returns the virtual - * address in the linear mapping: + * No need to redo, when the primary call touched the direct + * mapping already: */ - if (within(address, HIGH_MAP_START, HIGH_MAP_END)) - address = (unsigned long) __va(phys_addr); -#endif + if (!within(cpa->vaddr, PAGE_OFFSET, + PAGE_OFFSET + (max_pfn_mapped << PAGE_SHIFT))) { - err = __change_page_attr(address, cpa); - if (err) - return err; + alias_cpa = *cpa; + alias_cpa.vaddr = (unsigned long) __va(cpa->pfn << PAGE_SHIFT); + + ret = __change_page_attr_set_clr(&alias_cpa, 0); + } #ifdef CONFIG_X86_64 + if (ret) + return ret; + /* + * No need to redo, when the primary call touched the high + * mapping already: + */ + if (within(cpa->vaddr, (unsigned long) _text, (unsigned long) _end)) + return 0; + /* * If the physical address is inside the kernel map, we need * to touch the high mapped kernel as well: */ - if (within(phys_addr, 0, KERNEL_TEXT_SIZE)) { - /* - * Calc the high mapping address. See __phys_addr() - * for the non obvious details. - * - * Note that NX and other required permissions are - * checked in static_protections(). - */ - address = phys_addr + HIGH_MAP_START - phys_base; + if (!within(cpa->pfn, highmap_start_pfn(), highmap_end_pfn())) + return 0; - /* - * Our high aliases are imprecise, because we check - * everything between 0 and KERNEL_TEXT_SIZE, so do - * not propagate lookup failures back to users: - */ - __change_page_attr(address, cpa); - } + alias_cpa = *cpa; + alias_cpa.vaddr = + (cpa->pfn << PAGE_SHIFT) + __START_KERNEL_map - phys_base; + + /* + * The high mapping range is imprecise, so ignore the return value. + */ + __change_page_attr_set_clr(&alias_cpa, 0); #endif - return err; + return ret; } -static int __change_page_attr_set_clr(struct cpa_data *cpa) +static int __change_page_attr_set_clr(struct cpa_data *cpa, int checkalias) { int ret, numpages = cpa->numpages; @@ -651,10 +651,17 @@ static int __change_page_attr_set_clr(struct cpa_data *cpa) * preservation check. */ cpa->numpages = numpages; - ret = change_page_attr_addr(cpa); + + ret = __change_page_attr(cpa, checkalias); if (ret) return ret; + if (checkalias) { + ret = cpa_process_alias(cpa); + if (ret) + return ret; + } + /* * Adjust the number of pages with the result of the * CPA operation. Either a large page has been @@ -677,7 +684,7 @@ static int change_page_attr_set_clr(unsigned long addr, int numpages, pgprot_t mask_set, pgprot_t mask_clr) { struct cpa_data cpa; - int ret, cache; + int ret, cache, checkalias; /* * Check, if we are requested to change a not supported @@ -688,13 +695,25 @@ static int change_page_attr_set_clr(unsigned long addr, int numpages, if (!pgprot_val(mask_set) && !pgprot_val(mask_clr)) return 0; + /* Ensure we are PAGE_SIZE aligned */ + if (addr & ~PAGE_MASK) { + addr &= PAGE_MASK; + /* + * People should not be passing in unaligned addresses: + */ + WARN_ON_ONCE(1); + } + cpa.vaddr = addr; cpa.numpages = numpages; cpa.mask_set = mask_set; cpa.mask_clr = mask_clr; cpa.flushtlb = 0; - ret = __change_page_attr_set_clr(&cpa); + /* No alias checking for _NX bit modifications */ + checkalias = (pgprot_val(mask_set) | pgprot_val(mask_clr)) != _PAGE_NX; + + ret = __change_page_attr_set_clr(&cpa, checkalias); /* * Check whether we really changed something: @@ -832,7 +851,7 @@ static int __set_pages_p(struct page *page, int numpages) .mask_set = __pgprot(_PAGE_PRESENT | _PAGE_RW), .mask_clr = __pgprot(0)}; - return __change_page_attr_set_clr(&cpa); + return __change_page_attr_set_clr(&cpa, 1); } static int __set_pages_np(struct page *page, int numpages) @@ -842,7 +861,7 @@ static int __set_pages_np(struct page *page, int numpages) .mask_set = __pgprot(0), .mask_clr = __pgprot(_PAGE_PRESENT | _PAGE_RW)}; - return __change_page_attr_set_clr(&cpa); + return __change_page_attr_set_clr(&cpa, 1); } void kernel_map_pages(struct page *page, int numpages, int enable) @@ -861,8 +880,12 @@ void kernel_map_pages(struct page *page, int numpages, int enable) return; /* - * The return value is ignored - the calls cannot fail, - * large pages are disabled at boot time: + * The return value is ignored as the calls cannot fail. + * Large pages are kept enabled at boot time, and are + * split up quickly with DEBUG_PAGEALLOC. If a splitup + * fails here (due to temporary memory shortage) no damage + * is done because we just keep the largepage intact up + * to the next attempt when it will likely be split up: */ if (enable) __set_pages_p(page, numpages); diff --git a/arch/x86/xen/enlighten.c b/arch/x86/xen/enlighten.c index de647bc6e74..49e5358f481 100644 --- a/arch/x86/xen/enlighten.c +++ b/arch/x86/xen/enlighten.c @@ -798,6 +798,10 @@ static __init void xen_pagetable_setup_start(pgd_t *base) * added to the table can be prepared properly for Xen. */ xen_write_cr3(__pa(base)); + + /* Unpin initial Xen pagetable */ + pin_pagetable_pfn(MMUEXT_UNPIN_TABLE, + PFN_DOWN(__pa(xen_start_info->pt_base))); } static __init void xen_pagetable_setup_done(pgd_t *base) diff --git a/crypto/Kconfig b/crypto/Kconfig index c3166a1a5bb..898acc5c196 100644 --- a/crypto/Kconfig +++ b/crypto/Kconfig @@ -74,6 +74,7 @@ config CRYPTO_XCBC config CRYPTO_NULL tristate "Null algorithms" select CRYPTO_ALGAPI + select CRYPTO_BLKCIPHER help These are 'Null' algorithms, used by IPsec, which do nothing. @@ -567,6 +568,7 @@ config CRYPTO_TEST depends on m select CRYPTO_ALGAPI select CRYPTO_AEAD + select CRYPTO_BLKCIPHER help Quick & dirty crypto test module. diff --git a/drivers/acpi/blacklist.c b/drivers/acpi/blacklist.c index 9ce983ed60f..ea92bac42c5 100644 --- a/drivers/acpi/blacklist.c +++ b/drivers/acpi/blacklist.c @@ -186,6 +186,12 @@ static int __init dmi_unknown_osi_linux(const struct dmi_system_id *d) acpi_dmi_osi_linux(-1, d); /* unknown */ return 0; } +static int __init dmi_disable_osi_vista(const struct dmi_system_id *d) +{ + printk(KERN_NOTICE PREFIX "DMI detected: %s\n", d->ident); + acpi_osi_setup("!Windows 2006"); + return 0; +} /* * Most BIOS that invoke OSI(Linux) do nothing with it. @@ -228,10 +234,10 @@ static struct dmi_system_id acpi_osi_dmi_table[] __initdata = { * DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 5520"), * DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 6460"), * DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 7510"), - * DMI_MATCH(DMI_PRODUCT_NAME, "Extensa 5220"), * * _OSI(Linux) is a NOP: * DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5315"), + * DMI_MATCH(DMI_PRODUCT_NAME, "Extensa 5220"), */ { .callback = dmi_disable_osi_linux, @@ -327,12 +333,20 @@ static struct dmi_system_id acpi_osi_dmi_table[] __initdata = { }, { /* OSI(Linux) effect unknown */ .callback = dmi_unknown_osi_linux, - .ident = "Dell OP GX620", + .ident = "Dell OptiPlex GX620", .matches = { DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), DMI_MATCH(DMI_PRODUCT_NAME, "OptiPlex GX620"), }, }, + { /* OSI(Linux) causes some USB initialization to not run */ + .callback = dmi_unknown_osi_linux, + .ident = "Dell OptiPlex 755", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), + DMI_MATCH(DMI_PRODUCT_NAME, "OptiPlex 755"), + }, + }, { /* OSI(Linux) effect unknown */ .callback = dmi_unknown_osi_linux, .ident = "Dell PE 1900", @@ -342,6 +356,14 @@ static struct dmi_system_id acpi_osi_dmi_table[] __initdata = { }, }, { /* OSI(Linux) is a NOP */ + .callback = dmi_unknown_osi_linux, + .ident = "Dell PE 1950", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), + DMI_MATCH(DMI_PRODUCT_NAME, "PowerEdge 1950"), + }, + }, + { /* OSI(Linux) is a NOP */ .callback = dmi_disable_osi_linux, .ident = "Dell PE R200", .matches = { @@ -357,6 +379,22 @@ static struct dmi_system_id acpi_osi_dmi_table[] __initdata = { DMI_MATCH(DMI_PRODUCT_NAME, "Precision WorkStation 390"), }, }, + { /* OSI(Linux) touches USB */ + .callback = dmi_unknown_osi_linux, + .ident = "Dell PR 390", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), + DMI_MATCH(DMI_PRODUCT_NAME, "Precision WorkStation 690"), + }, + }, + { /* OSI(Linux) unknown - ASL looks benign, but may effect dock/SMM */ + .callback = dmi_unknown_osi_linux, + .ident = "Dell PR M4300", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), + DMI_MATCH(DMI_PRODUCT_NAME, "Precision M4300"), + }, + }, { /* OSI(Linux) is a NOP */ .callback = dmi_disable_osi_linux, .ident = "Dell Vostro 1000", @@ -390,10 +428,10 @@ static struct dmi_system_id acpi_osi_dmi_table[] __initdata = { * DMI_MATCH(DMI_PRODUCT_NAME, "AMILO Pi 1536"), * DMI_MATCH(DMI_PRODUCT_NAME, "AMILO Pi 1556"), * DMI_MATCH(DMI_PRODUCT_NAME, "AMILO Xi 1546"), + * DMI_MATCH(DMI_PRODUCT_NAME, "ESPRIMO Mobile V5505"), * _OSI(Linux) unknown effect: * DMI_MATCH(DMI_PRODUCT_NAME, "Amilo M1425"), * DMI_MATCH(DMI_PRODUCT_NAME, "Amilo Si 1520"), - * DMI_MATCH(DMI_PRODUCT_NAME, "ESPRIMO Mobile V5505"), */ { .callback = dmi_disable_osi_linux, @@ -402,6 +440,14 @@ static struct dmi_system_id acpi_osi_dmi_table[] __initdata = { DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"), }, }, + { + .callback = dmi_disable_osi_vista, + .ident = "Fujitsu Siemens", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"), + DMI_MATCH(DMI_PRODUCT_NAME, "ESPRIMO Mobile V5505"), + }, + }, /* * Disable OSI(Linux) warnings on all "Hewlett-Packard" * @@ -443,10 +489,11 @@ static struct dmi_system_id acpi_osi_dmi_table[] __initdata = { * _OSI(Linux) helps sound * DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkPad R61"), * DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkPad T61"), + * _OSI(Linux) has Linux specific hooks + * DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkPad X61"), * _OSI(Linux) is a NOP: * DMI_MATCH(DMI_PRODUCT_VERSION, "3000 N100"), - * _OSI(Linux) effect unknown - * DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkPad X61"), + * DMI_MATCH(DMI_PRODUCT_VERSION, "LENOVO3000 V100"), */ { .callback = dmi_enable_osi_linux, @@ -465,7 +512,7 @@ static struct dmi_system_id acpi_osi_dmi_table[] __initdata = { }, }, { - .callback = dmi_unknown_osi_linux, + .callback = dmi_enable_osi_linux, .ident = "Lenovo ThinkPad X61", .matches = { DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), @@ -473,7 +520,7 @@ static struct dmi_system_id acpi_osi_dmi_table[] __initdata = { }, }, { - .callback = dmi_unknown_osi_linux, + .callback = dmi_disable_osi_linux, .ident = "Lenovo 3000 V100", .matches = { DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), @@ -543,8 +590,9 @@ static struct dmi_system_id acpi_osi_dmi_table[] __initdata = { * Disable OSI(Linux) warnings on all "Sony Corporation" * * _OSI(Linux) is a NOP: - * DMI_MATCH(DMI_PRODUCT_NAME, "VGN-SZ650N"), + * DMI_MATCH(DMI_PRODUCT_NAME, "VGN-NR11S_S"), * DMI_MATCH(DMI_PRODUCT_NAME, "VGN-SZ38GP_C"), + * DMI_MATCH(DMI_PRODUCT_NAME, "VGN-SZ650N"), * DMI_MATCH(DMI_PRODUCT_NAME, "VGN-TZ21MN_N"), * _OSI(Linux) unknown effect: * DMI_MATCH(DMI_PRODUCT_NAME, "VGN-FZ11M"), diff --git a/drivers/acpi/event.c b/drivers/acpi/event.c index 5479dc0eeee..abec1ca94cf 100644 --- a/drivers/acpi/event.c +++ b/drivers/acpi/event.c @@ -110,7 +110,7 @@ static const struct file_operations acpi_system_event_ops = { #endif /* CONFIG_ACPI_PROC_EVENT */ /* ACPI notifier chain */ -BLOCKING_NOTIFIER_HEAD(acpi_chain_head); +static BLOCKING_NOTIFIER_HEAD(acpi_chain_head); int acpi_notifier_call_chain(struct acpi_device *dev, u32 type, u32 data) { diff --git a/drivers/acpi/hardware/hwsleep.c b/drivers/acpi/hardware/hwsleep.c index 058d0be5cbe..4290e019309 100644 --- a/drivers/acpi/hardware/hwsleep.c +++ b/drivers/acpi/hardware/hwsleep.c @@ -616,6 +616,7 @@ acpi_status acpi_leave_sleep_state(u8 sleep_state) return_ACPI_STATUS(status); } + arg.integer.value = sleep_state; status = acpi_evaluate_object(NULL, METHOD_NAME__WAK, &arg_list, NULL); if (ACPI_FAILURE(status) && status != AE_NOT_FOUND) { ACPI_EXCEPTION((AE_INFO, status, "During Method _WAK")); diff --git a/drivers/acpi/osl.c b/drivers/acpi/osl.c index 34b3386dedc..8edba7b678e 100644 --- a/drivers/acpi/osl.c +++ b/drivers/acpi/osl.c @@ -325,7 +325,7 @@ acpi_os_predefined_override(const struct acpi_predefined_names *init_val, } #ifdef CONFIG_ACPI_CUSTOM_DSDT_INITRD -struct acpi_table_header *acpi_find_dsdt_initrd(void) +static struct acpi_table_header *acpi_find_dsdt_initrd(void) { struct file *firmware_file; mm_segment_t oldfs; @@ -419,7 +419,7 @@ acpi_os_table_override(struct acpi_table_header * existing_table, } #ifdef CONFIG_ACPI_CUSTOM_DSDT_INITRD -int __init acpi_no_initrd_override_setup(char *s) +static int __init acpi_no_initrd_override_setup(char *s) { acpi_no_initrd_override = 1; return 1; @@ -623,7 +623,7 @@ acpi_os_write_memory(acpi_physical_address phys_addr, u32 value, u32 width) acpi_status acpi_os_read_pci_configuration(struct acpi_pci_id * pci_id, u32 reg, - void *value, u32 width) + u32 *value, u32 width) { int result, size; @@ -689,7 +689,6 @@ static void acpi_os_derive_pci_id_2(acpi_handle rhandle, /* upper bound */ acpi_status status; unsigned long temp; acpi_object_type type; - u8 tu8; acpi_get_parent(chandle, &handle); if (handle != rhandle) { @@ -704,6 +703,7 @@ static void acpi_os_derive_pci_id_2(acpi_handle rhandle, /* upper bound */ acpi_evaluate_integer(handle, METHOD_NAME__ADR, NULL, &temp); if (ACPI_SUCCESS(status)) { + u32 val; pci_id->device = ACPI_HIWORD(ACPI_LODWORD(temp)); pci_id->function = ACPI_LOWORD(ACPI_LODWORD(temp)); @@ -712,24 +712,24 @@ static void acpi_os_derive_pci_id_2(acpi_handle rhandle, /* upper bound */ /* any nicer way to get bus number of bridge ? */ status = - acpi_os_read_pci_configuration(pci_id, 0x0e, &tu8, + acpi_os_read_pci_configuration(pci_id, 0x0e, &val, 8); if (ACPI_SUCCESS(status) - && ((tu8 & 0x7f) == 1 || (tu8 & 0x7f) == 2)) { + && ((val & 0x7f) == 1 || (val & 0x7f) == 2)) { status = acpi_os_read_pci_configuration(pci_id, 0x18, - &tu8, 8); + &val, 8); if (!ACPI_SUCCESS(status)) { /* Certainly broken... FIX ME */ return; } *is_bridge = 1; - pci_id->bus = tu8; + pci_id->bus = val; status = acpi_os_read_pci_configuration(pci_id, 0x19, - &tu8, 8); + &val, 8); if (ACPI_SUCCESS(status)) { - *bus_number = tu8; + *bus_number = val; } } else *is_bridge = 0; @@ -1109,7 +1109,7 @@ void __init acpi_dmi_osi_linux(int enable, const struct dmi_system_id *d) * string starting with '!' disables that string * otherwise string is added to list, augmenting built-in strings */ -static int __init acpi_osi_setup(char *str) +int __init acpi_osi_setup(char *str) { if (str == NULL || *str == '\0') { printk(KERN_INFO PREFIX "_OSI method disabled\n"); diff --git a/drivers/acpi/processor_idle.c b/drivers/acpi/processor_idle.c index 32003fdc91e..980e1c33e6c 100644 --- a/drivers/acpi/processor_idle.c +++ b/drivers/acpi/processor_idle.c @@ -945,11 +945,16 @@ static int acpi_processor_get_power_info_cst(struct acpi_processor *pr) * Otherwise, ignore this info and continue. */ cx.entry_method = ACPI_CSTATE_HALT; + snprintf(cx.desc, ACPI_CX_DESC_LEN, "ACPI HLT"); } else { continue; } + } else { + snprintf(cx.desc, ACPI_CX_DESC_LEN, "ACPI IOPORT 0x%x", + cx.address); } + obj = &(element->package.elements[2]); if (obj->type != ACPI_TYPE_INTEGER) continue; @@ -1420,6 +1425,14 @@ static int acpi_idle_enter_c1(struct cpuidle_device *dev, return 0; local_irq_disable(); + + /* Do not access any ACPI IO ports in suspend path */ + if (acpi_idle_suspend) { + acpi_safe_halt(); + local_irq_enable(); + return 0; + } + if (pr->flags.bm_check) acpi_idle_update_bm_rld(pr, cx); @@ -1643,6 +1656,11 @@ static int acpi_processor_setup_cpuidle(struct acpi_processor *pr) return -EINVAL; } + for (i = 0; i < CPUIDLE_STATE_MAX; i++) { + dev->states[i].name[0] = '\0'; + dev->states[i].desc[0] = '\0'; + } + for (i = 1; i < ACPI_PROCESSOR_MAX_POWER && i <= max_cstate; i++) { cx = &pr->power.states[i]; state = &dev->states[count]; @@ -1659,6 +1677,7 @@ static int acpi_processor_setup_cpuidle(struct acpi_processor *pr) cpuidle_set_statedata(state, cx); snprintf(state->name, CPUIDLE_NAME_LEN, "C%d", i); + strncpy(state->desc, cx->desc, CPUIDLE_DESC_LEN); state->exit_latency = cx->latency; state->target_residency = cx->latency * latency_factor; state->power_usage = cx->power; diff --git a/drivers/acpi/wmi.c b/drivers/acpi/wmi.c index 457ed3d3f51..efacc9f8bfe 100644 --- a/drivers/acpi/wmi.c +++ b/drivers/acpi/wmi.c @@ -247,7 +247,7 @@ u32 method_id, const struct acpi_buffer *in, struct acpi_buffer *out) block = &wblock->gblock; handle = wblock->handle; - if (!block->flags & ACPI_WMI_METHOD) + if (!(block->flags & ACPI_WMI_METHOD)) return AE_BAD_DATA; if (block->instance_count < instance) diff --git a/drivers/ata/ata_piix.c b/drivers/ata/ata_piix.c index 9c2515f67de..752e7d2f3b2 100644 --- a/drivers/ata/ata_piix.c +++ b/drivers/ata/ata_piix.c @@ -1652,7 +1652,7 @@ static int __devinit piix_init_one(struct pci_dev *pdev, u8 tmp; pci_read_config_byte(pdev, PIIX_SCC, &tmp); if (tmp == PIIX_AHCI_DEVICE) { - int rc = piix_disable_ahci(pdev); + rc = piix_disable_ahci(pdev); if (rc) return rc; } diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index 004dae4ea5b..f46eb6f6dc9 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -4190,6 +4190,7 @@ static const struct ata_blacklist_entry ata_device_blacklist [] = { /* Devices which report 1 sector over size HPA */ { "ST340823A", NULL, ATA_HORKAGE_HPA_SIZE, }, { "ST320413A", NULL, ATA_HORKAGE_HPA_SIZE, }, + { "ST310211A", NULL, ATA_HORKAGE_HPA_SIZE, }, /* Devices which get the IVB wrong */ { "QUANTUM FIREBALLlct10 05", "A03.0900", ATA_HORKAGE_IVB, }, @@ -7086,7 +7087,6 @@ int ata_host_register(struct ata_host *host, struct scsi_host_template *sht) DPRINTK("probe begin\n"); for (i = 0; i < host->n_ports; i++) { struct ata_port *ap = host->ports[i]; - int rc; /* probe */ if (ap->ops->error_handler) { diff --git a/drivers/ata/libata-scsi.c b/drivers/ata/libata-scsi.c index c02c490122d..1cea18f62ab 100644 --- a/drivers/ata/libata-scsi.c +++ b/drivers/ata/libata-scsi.c @@ -1862,7 +1862,7 @@ unsigned int ata_scsiop_inq_83(struct ata_scsi_args *args, u8 *rbuf, * spin_lock_irqsave(host lock) */ -unsigned int ata_scsiop_inq_89(struct ata_scsi_args *args, u8 *rbuf, +static unsigned int ata_scsiop_inq_89(struct ata_scsi_args *args, u8 *rbuf, unsigned int buflen) { u8 pbuf[60]; diff --git a/drivers/ata/pata_acpi.c b/drivers/ata/pata_acpi.c index 244098a80ce..bdc3b9d7395 100644 --- a/drivers/ata/pata_acpi.c +++ b/drivers/ata/pata_acpi.c @@ -77,8 +77,8 @@ static int pacpi_cable_detect(struct ata_port *ap) static void pacpi_error_handler(struct ata_port *ap) { - return ata_bmdma_drive_eh(ap, pacpi_pre_reset, ata_std_softreset, - NULL, ata_std_postreset); + ata_bmdma_drive_eh(ap, pacpi_pre_reset, ata_std_softreset, NULL, + ata_std_postreset); } /** diff --git a/drivers/ata/pata_amd.c b/drivers/ata/pata_amd.c index ea567e2b170..4b8d9b592ca 100644 --- a/drivers/ata/pata_amd.c +++ b/drivers/ata/pata_amd.c @@ -146,9 +146,8 @@ static int amd_pre_reset(struct ata_link *link, unsigned long deadline) static void amd_error_handler(struct ata_port *ap) { - return ata_bmdma_drive_eh(ap, amd_pre_reset, - ata_std_softreset, NULL, - ata_std_postreset); + ata_bmdma_drive_eh(ap, amd_pre_reset, ata_std_softreset, NULL, + ata_std_postreset); } static int amd_cable_detect(struct ata_port *ap) @@ -506,7 +505,6 @@ static struct ata_port_operations amd133_port_ops = { static struct ata_port_operations nv100_port_ops = { .set_piomode = nv100_set_piomode, .set_dmamode = nv100_set_dmamode, - .mode_filter = ata_pci_default_filter, .tf_load = ata_tf_load, .tf_read = ata_tf_read, .check_status = ata_check_status, @@ -541,7 +539,6 @@ static struct ata_port_operations nv100_port_ops = { static struct ata_port_operations nv133_port_ops = { .set_piomode = nv133_set_piomode, .set_dmamode = nv133_set_dmamode, - .mode_filter = ata_pci_default_filter, .tf_load = ata_tf_load, .tf_read = ata_tf_read, .check_status = ata_check_status, diff --git a/drivers/ata/pata_cs5536.c b/drivers/ata/pata_cs5536.c index d753e568588..1c4ff9b52b5 100644 --- a/drivers/ata/pata_cs5536.c +++ b/drivers/ata/pata_cs5536.c @@ -40,7 +40,7 @@ #include <asm/msr.h> #define DRV_NAME "pata_cs5536" -#define DRV_VERSION "0.0.6" +#define DRV_VERSION "0.0.7" enum { CFG = 0, @@ -85,7 +85,7 @@ static const u8 pci_reg[4] = { PCI_IDE_CFG, PCI_IDE_DTC, PCI_IDE_CAST, PCI_IDE_ETC, }; -static inline int cs5536_read(struct pci_dev *pdev, int reg, int *val) +static inline int cs5536_read(struct pci_dev *pdev, int reg, u32 *val) { if (unlikely(use_msr)) { u32 dummy; @@ -153,8 +153,8 @@ static void cs5536_set_piomode(struct ata_port *ap, struct ata_device *adev) struct ata_device *pair = ata_dev_pair(adev); int mode = adev->pio_mode - XFER_PIO_0; int cmdmode = mode; - int dshift = ap->port_no ? IDE_D1_SHIFT : IDE_D0_SHIFT; - int cshift = ap->port_no ? IDE_CAST_D1_SHIFT : IDE_CAST_D0_SHIFT; + int dshift = adev->devno ? IDE_D1_SHIFT : IDE_D0_SHIFT; + int cshift = adev->devno ? IDE_CAST_D1_SHIFT : IDE_CAST_D0_SHIFT; u32 dtc, cast, etc; if (pair) @@ -201,7 +201,7 @@ static void cs5536_set_dmamode(struct ata_port *ap, struct ata_device *adev) struct pci_dev *pdev = to_pci_dev(ap->host->dev); u32 dtc, etc; int mode = adev->dma_mode; - int dshift = ap->port_no ? IDE_D1_SHIFT : IDE_D0_SHIFT; + int dshift = adev->devno ? IDE_D1_SHIFT : IDE_D0_SHIFT; if (mode >= XFER_UDMA_0) { cs5536_read(pdev, ETC, &etc); diff --git a/drivers/ata/pata_jmicron.c b/drivers/ata/pata_jmicron.c index 5b8174d9406..00bbbbd50e9 100644 --- a/drivers/ata/pata_jmicron.c +++ b/drivers/ata/pata_jmicron.c @@ -115,7 +115,8 @@ static int jmicron_pre_reset(struct ata_link *link, unsigned long deadline) static void jmicron_error_handler(struct ata_port *ap) { - return ata_bmdma_drive_eh(ap, jmicron_pre_reset, ata_std_softreset, NULL, ata_std_postreset); + ata_bmdma_drive_eh(ap, jmicron_pre_reset, ata_std_softreset, NULL, + ata_std_postreset); } /* No PIO or DMA methods needed for this device */ diff --git a/drivers/ata/pata_legacy.c b/drivers/ata/pata_legacy.c index 6c59969fd50..d2177f75078 100644 --- a/drivers/ata/pata_legacy.c +++ b/drivers/ata/pata_legacy.c @@ -1278,8 +1278,6 @@ static __init int legacy_init_one(struct legacy_probe *probe) } } fail: - if (host) - ata_host_detach(host); platform_device_unregister(pdev); return ret; } diff --git a/drivers/ata/pata_marvell.c b/drivers/ata/pata_marvell.c index 9afc8a32b22..a81f25d8723 100644 --- a/drivers/ata/pata_marvell.c +++ b/drivers/ata/pata_marvell.c @@ -85,8 +85,8 @@ static int marvell_cable_detect(struct ata_port *ap) static void marvell_error_handler(struct ata_port *ap) { - return ata_bmdma_drive_eh(ap, marvell_pre_reset, ata_std_softreset, - NULL, ata_std_postreset); + ata_bmdma_drive_eh(ap, marvell_pre_reset, ata_std_softreset, NULL, + ata_std_postreset); } /* No PIO or DMA methods needed for this device */ diff --git a/drivers/ata/pata_scc.c b/drivers/ata/pata_scc.c index 55055b27524..6c016deeaed 100644 --- a/drivers/ata/pata_scc.c +++ b/drivers/ata/pata_scc.c @@ -1007,6 +1007,8 @@ static const struct ata_port_operations scc_pata_ops = { .qc_issue = ata_qc_issue_prot, .freeze = scc_bmdma_freeze, + .thaw = ata_bmdma_thaw, + .error_handler = scc_error_handler, .post_internal_cmd = scc_bmdma_stop, diff --git a/drivers/ata/sata_mv.c b/drivers/ata/sata_mv.c index 04b571764af..2ecd44db414 100644 --- a/drivers/ata/sata_mv.c +++ b/drivers/ata/sata_mv.c @@ -1542,7 +1542,7 @@ static void mv_err_intr(struct ata_port *ap, struct ata_queued_cmd *qc) eh_freeze_mask = EDMA_EH_FREEZE_5; if (edma_err_cause & EDMA_ERR_SELF_DIS_5) { - struct mv_port_priv *pp = ap->private_data; + pp = ap->private_data; pp->pp_flags &= ~MV_PP_FLAG_EDMA_EN; ata_ehi_push_desc(ehi, "EDMA self-disable"); } @@ -1550,7 +1550,7 @@ static void mv_err_intr(struct ata_port *ap, struct ata_queued_cmd *qc) eh_freeze_mask = EDMA_EH_FREEZE; if (edma_err_cause & EDMA_ERR_SELF_DIS) { - struct mv_port_priv *pp = ap->private_data; + pp = ap->private_data; pp->pp_flags &= ~MV_PP_FLAG_EDMA_EN; ata_ehi_push_desc(ehi, "EDMA self-disable"); } diff --git a/drivers/ata/sata_promise.c b/drivers/ata/sata_promise.c index a07d319f6e8..f251a5f569d 100644 --- a/drivers/ata/sata_promise.c +++ b/drivers/ata/sata_promise.c @@ -543,7 +543,7 @@ static void pdc_fill_sg(struct ata_queued_cmd *qc) idx = 0; for_each_sg(qc->sg, sg, qc->n_elem, si) { u32 addr, offset; - u32 sg_len, len; + u32 sg_len; /* determine if physical DMA addr spans 64K boundary. * Note h/w doesn't support 64-bit, so we unconditionally diff --git a/drivers/ata/sata_via.c b/drivers/ata/sata_via.c index 30caa033719..0d03f44824f 100644 --- a/drivers/ata/sata_via.c +++ b/drivers/ata/sata_via.c @@ -333,8 +333,8 @@ static int vt6420_prereset(struct ata_link *link, unsigned long deadline) static void vt6420_error_handler(struct ata_port *ap) { - return ata_bmdma_drive_eh(ap, vt6420_prereset, ata_std_softreset, - NULL, ata_std_postreset); + ata_bmdma_drive_eh(ap, vt6420_prereset, ata_std_softreset, NULL, + ata_std_postreset); } static int vt6421_pata_cable_detect(struct ata_port *ap) diff --git a/drivers/block/swim3.c b/drivers/block/swim3.c index b4e462f154e..730ccea78e4 100644 --- a/drivers/block/swim3.c +++ b/drivers/block/swim3.c @@ -251,10 +251,6 @@ static int floppy_release(struct inode *inode, struct file *filp); static int floppy_check_change(struct gendisk *disk); static int floppy_revalidate(struct gendisk *disk); -#ifndef CONFIG_PMAC_MEDIABAY -#define check_media_bay(which, what) 1 -#endif - static void swim3_select(struct floppy_state *fs, int sel) { struct swim3 __iomem *sw = fs->swim3; diff --git a/drivers/bluetooth/hci_ldisc.c b/drivers/bluetooth/hci_ldisc.c index e68821d074b..7e31d5f1bc8 100644 --- a/drivers/bluetooth/hci_ldisc.c +++ b/drivers/bluetooth/hci_ldisc.c @@ -208,6 +208,7 @@ static int hci_uart_close(struct hci_dev *hdev) return 0; hci_uart_flush(hdev); + hdev->flush = NULL; return 0; } diff --git a/drivers/char/drm/i830_dma.c b/drivers/char/drm/i830_dma.c index 379cbdad492..9df08105f4f 100644 --- a/drivers/char/drm/i830_dma.c +++ b/drivers/char/drm/i830_dma.c @@ -36,7 +36,7 @@ #include "i830_drm.h" #include "i830_drv.h" #include <linux/interrupt.h> /* For task queue support */ -#include <linux/pagemap.h> /* For FASTCALL on unlock_page() */ +#include <linux/pagemap.h> #include <linux/delay.h> #include <asm/uaccess.h> diff --git a/drivers/char/hvc_rtas.c b/drivers/char/hvc_rtas.c index bb09413d5a2..88590d04004 100644 --- a/drivers/char/hvc_rtas.c +++ b/drivers/char/hvc_rtas.c @@ -76,7 +76,7 @@ static struct hv_ops hvc_rtas_get_put_ops = { .put_chars = hvc_rtas_write_console, }; -static int hvc_rtas_init(void) +static int __init hvc_rtas_init(void) { struct hvc_struct *hp; diff --git a/drivers/char/pcmcia/Kconfig b/drivers/char/pcmcia/Kconfig index 00b8a84b031..ffa0efce0ae 100644 --- a/drivers/char/pcmcia/Kconfig +++ b/drivers/char/pcmcia/Kconfig @@ -45,7 +45,7 @@ config CARDMAN_4040 config IPWIRELESS tristate "IPWireless 3G UMTS PCMCIA card support" - depends on PCMCIA + depends on PCMCIA && NETDEVICES select PPP help This is a driver for 3G UMTS PCMCIA card from IPWireless company. In diff --git a/drivers/cpuidle/cpuidle.c b/drivers/cpuidle/cpuidle.c index 60f71e6345e..d73663a5232 100644 --- a/drivers/cpuidle/cpuidle.c +++ b/drivers/cpuidle/cpuidle.c @@ -219,7 +219,8 @@ static void poll_idle_init(struct cpuidle_device *dev) cpuidle_set_statedata(state, NULL); - snprintf(state->name, CPUIDLE_NAME_LEN, "C0 (poll idle)"); + snprintf(state->name, CPUIDLE_NAME_LEN, "C0"); + snprintf(state->desc, CPUIDLE_DESC_LEN, "CPUIDLE CORE POLL IDLE"); state->exit_latency = 0; state->target_residency = 0; state->power_usage = -1; diff --git a/drivers/cpuidle/sysfs.c b/drivers/cpuidle/sysfs.c index 088ea74edd3..69102ca0568 100644 --- a/drivers/cpuidle/sysfs.c +++ b/drivers/cpuidle/sysfs.c @@ -218,16 +218,23 @@ static ssize_t show_state_##_name(struct cpuidle_state *state, char *buf) \ return sprintf(buf, "%u\n", state->_name);\ } -static ssize_t show_state_name(struct cpuidle_state *state, char *buf) -{ - return sprintf(buf, "%s\n", state->name); +#define define_show_state_str_function(_name) \ +static ssize_t show_state_##_name(struct cpuidle_state *state, char *buf) \ +{ \ + if (state->_name[0] == '\0')\ + return sprintf(buf, "<null>\n");\ + return sprintf(buf, "%s\n", state->_name);\ } define_show_state_function(exit_latency) define_show_state_function(power_usage) define_show_state_function(usage) define_show_state_function(time) +define_show_state_str_function(name) +define_show_state_str_function(desc) + define_one_state_ro(name, show_state_name); +define_one_state_ro(desc, show_state_desc); define_one_state_ro(latency, show_state_exit_latency); define_one_state_ro(power, show_state_power_usage); define_one_state_ro(usage, show_state_usage); @@ -235,6 +242,7 @@ define_one_state_ro(time, show_state_time); static struct attribute *cpuidle_state_default_attrs[] = { &attr_name.attr, + &attr_desc.attr, &attr_latency.attr, &attr_power.attr, &attr_usage.attr, diff --git a/drivers/crypto/hifn_795x.c b/drivers/crypto/hifn_795x.c index dfbf24c4033..3110bf7014f 100644 --- a/drivers/crypto/hifn_795x.c +++ b/drivers/crypto/hifn_795x.c @@ -463,7 +463,7 @@ struct hifn_device unsigned int pk_clk_freq; -#ifdef CRYPTO_DEV_HIFN_795X_RNG +#ifdef CONFIG_CRYPTO_DEV_HIFN_795X_RNG unsigned int rng_wait_time; ktime_t rngtime; struct hwrng rng; @@ -795,7 +795,7 @@ static struct pci2id { } }; -#ifdef CRYPTO_DEV_HIFN_795X_RNG +#ifdef CONFIG_CRYPTO_DEV_HIFN_795X_RNG static int hifn_rng_data_present(struct hwrng *rng, int wait) { struct hifn_device *dev = (struct hifn_device *)rng->priv; @@ -880,7 +880,7 @@ static int hifn_init_pubrng(struct hifn_device *dev) dprintk("Chip %s: RNG engine has been successfully initialised.\n", dev->name); -#ifdef CRYPTO_DEV_HIFN_795X_RNG +#ifdef CONFIG_CRYPTO_DEV_HIFN_795X_RNG /* First value must be discarded */ hifn_read_1(dev, HIFN_1_RNG_DATA); dev->rngtime = ktime_get(); diff --git a/drivers/hid/hid-input-quirks.c b/drivers/hid/hid-input-quirks.c index a870ba58faa..dceadd0c141 100644 --- a/drivers/hid/hid-input-quirks.c +++ b/drivers/hid/hid-input-quirks.c @@ -352,7 +352,7 @@ int hidinput_mapping_quirks(struct hid_usage *usage, return 0; } -void hidinput_event_quirks(struct hid_device *hid, struct hid_field *field, struct hid_usage *usage, __s32 value) +int hidinput_event_quirks(struct hid_device *hid, struct hid_field *field, struct hid_usage *usage, __s32 value) { struct input_dev *input; @@ -362,34 +362,34 @@ void hidinput_event_quirks(struct hid_device *hid, struct hid_field *field, stru || ((hid->quirks & HID_QUIRK_2WHEEL_MOUSE_HACK_7) && (usage->hid == 0x00090007))) { if (value) hid->quirks |= HID_QUIRK_2WHEEL_MOUSE_HACK_ON; else hid->quirks &= ~HID_QUIRK_2WHEEL_MOUSE_HACK_ON; - return; + return 1; } if ((hid->quirks & HID_QUIRK_2WHEEL_MOUSE_HACK_B8) && (usage->type == EV_REL) && (usage->code == REL_WHEEL)) { hid->delayed_value = value; - return; + return 1; } if ((hid->quirks & HID_QUIRK_2WHEEL_MOUSE_HACK_B8) && (usage->hid == 0x000100b8)) { input_event(input, EV_REL, value ? REL_HWHEEL : REL_WHEEL, hid->delayed_value); - return; + return 1; } if ((hid->quirks & HID_QUIRK_INVERT_HWHEEL) && (usage->code == REL_HWHEEL)) { input_event(input, usage->type, usage->code, -value); - return; + return 1; } if ((hid->quirks & HID_QUIRK_2WHEEL_MOUSE_HACK_ON) && (usage->code == REL_WHEEL)) { input_event(input, usage->type, REL_HWHEEL, value); - return; + return 1; } if ((hid->quirks & HID_QUIRK_APPLE_HAS_FN) && hidinput_apple_event(hid, input, usage, value)) - return; + return 1; /* Handling MS keyboards special buttons */ if (hid->quirks & HID_QUIRK_MICROSOFT_KEYS && @@ -416,8 +416,9 @@ void hidinput_event_quirks(struct hid_device *hid, struct hid_field *field, stru if (hid->quirks & HID_QUIRK_HWHEEL_WHEEL_INVERT && usage->type == EV_REL && usage->code == REL_HWHEEL) { input_event(input, usage->type, REL_WHEEL, -value); - return; + return 1; } + return 0; } diff --git a/drivers/hid/hid-input.c b/drivers/hid/hid-input.c index 5325d98b432..5a38fb27d69 100644 --- a/drivers/hid/hid-input.c +++ b/drivers/hid/hid-input.c @@ -97,6 +97,7 @@ struct hidinput_key_translation { #define APPLE_FLAG_FKEY 0x01 static struct hidinput_key_translation apple_fn_keys[] = { + { KEY_BACKSPACE, KEY_DELETE }, { KEY_F1, KEY_BRIGHTNESSDOWN, APPLE_FLAG_FKEY }, { KEY_F2, KEY_BRIGHTNESSUP, APPLE_FLAG_FKEY }, { KEY_F3, KEY_CYCLEWINDOWS, APPLE_FLAG_FKEY }, /* Exposé */ @@ -109,6 +110,10 @@ static struct hidinput_key_translation apple_fn_keys[] = { { KEY_F10, KEY_MUTE, APPLE_FLAG_FKEY }, { KEY_F11, KEY_VOLUMEDOWN, APPLE_FLAG_FKEY }, { KEY_F12, KEY_VOLUMEUP, APPLE_FLAG_FKEY }, + { KEY_UP, KEY_PAGEUP }, + { KEY_DOWN, KEY_PAGEDOWN }, + { KEY_LEFT, KEY_HOME }, + { KEY_RIGHT, KEY_END }, { } }; @@ -854,7 +859,8 @@ void hidinput_hid_event(struct hid_device *hid, struct hid_field *field, struct return; /* handle input events for quirky devices */ - hidinput_event_quirks(hid, field, usage, value); + if (hidinput_event_quirks(hid, field, usage, value)) + return; if (usage->hat_min < usage->hat_max || usage->hat_dir) { int hat_dir = usage->hat_dir; diff --git a/drivers/hid/usbhid/hid-quirks.c b/drivers/hid/usbhid/hid-quirks.c index b77b61e0cd7..e6d05f6b1c1 100644 --- a/drivers/hid/usbhid/hid-quirks.c +++ b/drivers/hid/usbhid/hid-quirks.c @@ -66,6 +66,12 @@ #define USB_DEVICE_ID_APPLE_ALU_ANSI 0x0220 #define USB_DEVICE_ID_APPLE_ALU_ISO 0x0221 #define USB_DEVICE_ID_APPLE_ALU_JIS 0x0222 +#define USB_DEVICE_ID_APPLE_GEYSER4_HF_ANSI 0x0229 +#define USB_DEVICE_ID_APPLE_GEYSER4_HF_ISO 0x022a +#define USB_DEVICE_ID_APPLE_GEYSER4_HF_JIS 0x022b +#define USB_DEVICE_ID_APPLE_ALU_WIRELESS_ANSI 0x022c +#define USB_DEVICE_ID_APPLE_ALU_WIRELESS_ISO 0x022d +#define USB_DEVICE_ID_APPLE_ALU_WIRELESS_JIS 0x022e #define USB_DEVICE_ID_APPLE_FOUNTAIN_TP_ONLY 0x030a #define USB_DEVICE_ID_APPLE_GEYSER1_TP_ONLY 0x030b #define USB_DEVICE_ID_APPLE_IRCONTROL4 0x8242 @@ -193,6 +199,17 @@ #define USB_DEVICE_ID_GTCO_502 0x0502 #define USB_DEVICE_ID_GTCO_503 0x0503 #define USB_DEVICE_ID_GTCO_504 0x0504 +#define USB_DEVICE_ID_GTCO_600 0x0600 +#define USB_DEVICE_ID_GTCO_601 0x0601 +#define USB_DEVICE_ID_GTCO_602 0x0602 +#define USB_DEVICE_ID_GTCO_603 0x0603 +#define USB_DEVICE_ID_GTCO_604 0x0604 +#define USB_DEVICE_ID_GTCO_605 0x0605 +#define USB_DEVICE_ID_GTCO_606 0x0606 +#define USB_DEVICE_ID_GTCO_607 0x0607 +#define USB_DEVICE_ID_GTCO_608 0x0608 +#define USB_DEVICE_ID_GTCO_609 0x0609 +#define USB_DEVICE_ID_GTCO_609 0x0609 #define USB_DEVICE_ID_GTCO_1000 0x1000 #define USB_DEVICE_ID_GTCO_1001 0x1001 #define USB_DEVICE_ID_GTCO_1002 0x1002 @@ -200,7 +217,7 @@ #define USB_DEVICE_ID_GTCO_1004 0x1004 #define USB_DEVICE_ID_GTCO_1005 0x1005 #define USB_DEVICE_ID_GTCO_1006 0x1006 - +#define USB_DEVICE_ID_GTCO_1007 0x1007 #define USB_VENDOR_ID_HAPP 0x078b #define USB_DEVICE_ID_UGCI_DRIVING 0x0010 #define USB_DEVICE_ID_UGCI_FLYING 0x0020 @@ -368,6 +385,7 @@ #define USB_DEVICE_ID_VERNIER_GOTEMP 0x0002 #define USB_DEVICE_ID_VERNIER_SKIP 0x0003 #define USB_DEVICE_ID_VERNIER_CYCLOPS 0x0004 +#define USB_DEVICE_ID_VERNIER_LCSPEC 0x0006 #define USB_VENDOR_ID_WACOM 0x056a @@ -496,6 +514,16 @@ static const struct hid_blacklist { { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_502, HID_QUIRK_IGNORE }, { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_503, HID_QUIRK_IGNORE }, { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_504, HID_QUIRK_IGNORE }, + { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_600, HID_QUIRK_IGNORE }, + { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_601, HID_QUIRK_IGNORE }, + { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_602, HID_QUIRK_IGNORE }, + { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_603, HID_QUIRK_IGNORE }, + { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_604, HID_QUIRK_IGNORE }, + { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_605, HID_QUIRK_IGNORE }, + { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_606, HID_QUIRK_IGNORE }, + { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_607, HID_QUIRK_IGNORE }, + { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_608, HID_QUIRK_IGNORE }, + { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_609, HID_QUIRK_IGNORE }, { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_1000, HID_QUIRK_IGNORE }, { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_1001, HID_QUIRK_IGNORE }, { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_1002, HID_QUIRK_IGNORE }, @@ -503,6 +531,7 @@ static const struct hid_blacklist { { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_1004, HID_QUIRK_IGNORE }, { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_1005, HID_QUIRK_IGNORE }, { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_1006, HID_QUIRK_IGNORE }, + { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_1007, HID_QUIRK_IGNORE }, { USB_VENDOR_ID_IMATION, USB_DEVICE_ID_DISC_STAKKA, HID_QUIRK_IGNORE }, { USB_VENDOR_ID_KBGEAR, USB_DEVICE_ID_KBGEAR_JAMSTUDIO, HID_QUIRK_IGNORE }, { USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_CASSY, HID_QUIRK_IGNORE }, @@ -541,6 +570,7 @@ static const struct hid_blacklist { { USB_VENDOR_ID_VERNIER, USB_DEVICE_ID_VERNIER_GOTEMP, HID_QUIRK_IGNORE }, { USB_VENDOR_ID_VERNIER, USB_DEVICE_ID_VERNIER_SKIP, HID_QUIRK_IGNORE }, { USB_VENDOR_ID_VERNIER, USB_DEVICE_ID_VERNIER_CYCLOPS, HID_QUIRK_IGNORE }, + { USB_VENDOR_ID_VERNIER, USB_DEVICE_ID_VERNIER_LCSPEC, HID_QUIRK_IGNORE }, { USB_VENDOR_ID_WISEGROUP, USB_DEVICE_ID_4_PHIDGETSERVO_20, HID_QUIRK_IGNORE }, { USB_VENDOR_ID_WISEGROUP, USB_DEVICE_ID_1_PHIDGETSERVO_20, HID_QUIRK_IGNORE }, { USB_VENDOR_ID_WISEGROUP, USB_DEVICE_ID_8_8_4_IF_KIT, HID_QUIRK_IGNORE }, @@ -593,6 +623,12 @@ static const struct hid_blacklist { { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_ANSI, HID_QUIRK_APPLE_HAS_FN }, { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_ISO, HID_QUIRK_APPLE_HAS_FN | HID_QUIRK_APPLE_ISO_KEYBOARD }, { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_JIS, HID_QUIRK_APPLE_HAS_FN }, + { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER4_HF_ANSI, HID_QUIRK_APPLE_HAS_FN | HID_QUIRK_IGNORE_MOUSE }, + { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER4_HF_ISO, HID_QUIRK_APPLE_HAS_FN | HID_QUIRK_IGNORE_MOUSE | HID_QUIRK_APPLE_ISO_KEYBOARD }, + { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER4_HF_JIS, HID_QUIRK_APPLE_HAS_FN | HID_QUIRK_IGNORE_MOUSE }, + { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_ANSI, HID_QUIRK_APPLE_HAS_FN }, + { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_ISO, HID_QUIRK_APPLE_HAS_FN | HID_QUIRK_APPLE_ISO_KEYBOARD }, + { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_JIS, HID_QUIRK_APPLE_HAS_FN }, { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_FOUNTAIN_TP_ONLY, HID_QUIRK_APPLE_HAS_FN | HID_QUIRK_IGNORE_MOUSE }, { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER1_TP_ONLY, HID_QUIRK_APPLE_HAS_FN | HID_QUIRK_IGNORE_MOUSE }, diff --git a/drivers/ide/ide-cd.c b/drivers/ide/ide-cd.c index 354c91d06a6..310e497b583 100644 --- a/drivers/ide/ide-cd.c +++ b/drivers/ide/ide-cd.c @@ -1207,9 +1207,13 @@ static ide_startstop_t cdrom_newpc_intr(ide_drive_t *drive) end_request: if (blk_pc_request(rq)) { unsigned long flags; + unsigned int dlen = rq->data_len; + + if (dma) + rq->data_len = 0; spin_lock_irqsave(&ide_lock, flags); - if (__blk_end_request(rq, 0, rq->data_len)) + if (__blk_end_request(rq, 0, dlen)) BUG(); HWGROUP(drive)->rq = NULL; spin_unlock_irqrestore(&ide_lock, flags); diff --git a/drivers/ide/ide-disk.c b/drivers/ide/ide-disk.c index aed8b31ca56..8f5bed47105 100644 --- a/drivers/ide/ide-disk.c +++ b/drivers/ide/ide-disk.c @@ -397,6 +397,7 @@ static inline int idedisk_supports_lba48(const struct hd_driveid *id) static const struct drive_list_entry hpa_list[] = { { "ST340823A", NULL }, { "ST320413A", NULL }, + { "ST310211A", NULL }, { NULL, NULL } }; diff --git a/drivers/ide/ide-generic.c b/drivers/ide/ide-generic.c index 709b9e4d287..9ebec08eefd 100644 --- a/drivers/ide/ide-generic.c +++ b/drivers/ide/ide-generic.c @@ -17,9 +17,6 @@ static int __init ide_generic_init(void) u8 idx[MAX_HWIFS]; int i; - if (ide_hwifs[0].io_ports[IDE_DATA_OFFSET]) - ide_get_lock(NULL, NULL); /* for atari only */ - for (i = 0; i < MAX_HWIFS; i++) { ide_hwif_t *hwif = &ide_hwifs[i]; @@ -31,9 +28,6 @@ static int __init ide_generic_init(void) ide_device_add_all(idx, NULL); - if (ide_hwifs[0].io_ports[IDE_DATA_OFFSET]) - ide_release_lock(); /* for atari only */ - return 0; } diff --git a/drivers/ide/legacy/falconide.c b/drivers/ide/legacy/falconide.c index f044048903b..8949ce71bdd 100644 --- a/drivers/ide/legacy/falconide.c +++ b/drivers/ide/legacy/falconide.c @@ -54,7 +54,7 @@ static void __init falconide_setup_ports(hw_regs_t *hw) for (i = 1; i < 8; i++) hw->io_ports[i] = ATA_HD_BASE + 1 + i * 4; - hw->io_ports[IDE_CONTROL_OFFSET] = ATA_HD_CONTROL; + hw->io_ports[IDE_CONTROL_OFFSET] = ATA_HD_BASE + ATA_HD_CONTROL; hw->irq = IRQ_MFP_IDE; hw->ack_intr = NULL; @@ -84,7 +84,9 @@ static int __init falconide_init(void) ide_init_port_data(hwif, index); ide_init_port_hw(hwif, &hw); + ide_get_lock(NULL, NULL); ide_device_add(idx, NULL); + ide_release_lock(); } return 0; diff --git a/drivers/ide/legacy/ht6560b.c b/drivers/ide/legacy/ht6560b.c index 02d12c74764..78ca68e60f9 100644 --- a/drivers/ide/legacy/ht6560b.c +++ b/drivers/ide/legacy/ht6560b.c @@ -21,18 +21,21 @@ * "Prefetch" mode bit OFF for ide disks and * ON for anything else. * + * Version 0.08 Need to force prefetch for CDs and other non-disk + * devices. (not sure which devices exactly need + * prefetch) * * HT-6560B EIDE-controller support * To activate controller support use kernel parameter "ide0=ht6560b". * Use hdparm utility to enable PIO mode support. * * Author: Mikko Ala-Fossi <maf@iki.fi> - * Jan Evert van Grootheest <janevert@iae.nl> + * Jan Evert van Grootheest <janevert@caiway.nl> * * Try: http://www.maf.iki.fi/~maf/ht6560b/ */ -#define HT6560B_VERSION "v0.07" +#define HT6560B_VERSION "v0.08" #include <linux/module.h> #include <linux/types.h> @@ -130,15 +133,20 @@ static void ht6560b_selectproc (ide_drive_t *drive) u8 select, timing; local_irq_save(flags); - + select = HT_CONFIG(drive); timing = HT_TIMING(drive); - + + /* + * Need to enforce prefetch sometimes because otherwise + * it'll hang (hard). + */ + if (drive->media != ide_disk || !drive->present) + select |= HT_PREFETCH_MODE; + if (select != current_select || timing != current_timing) { current_select = select; current_timing = timing; - if (drive->media != ide_disk || !drive->present) - select |= HT_PREFETCH_MODE; (void)inb(HT_CONFIG_PORT); (void)inb(HT_CONFIG_PORT); (void)inb(HT_CONFIG_PORT); @@ -188,11 +196,12 @@ static int __init try_to_init_ht6560b(void) outb(HT_TIMING_DEFAULT, 0x1f6); /* IDE_SELECT_REG */ (void) inb(0x1f7); /* IDE_STATUS_REG */ - printk("\nht6560b " HT6560B_VERSION + printk("ht6560b " HT6560B_VERSION ": chipset detected and initialized" #ifdef DEBUG " with debug enabled" #endif + "\n" ); return 1; } @@ -323,7 +332,7 @@ static const struct ide_port_info ht6560b_port_info __initdata = { IDE_HFLAG_NO_DMA | IDE_HFLAG_NO_AUTOTUNE | IDE_HFLAG_ABUSE_PREFETCH, - .pio_mask = ATA_PIO5, + .pio_mask = ATA_PIO4, }; static int __init ht6560b_init(void) diff --git a/drivers/ide/legacy/macide.c b/drivers/ide/legacy/macide.c index a61e60737dc..9a79098d9eb 100644 --- a/drivers/ide/legacy/macide.c +++ b/drivers/ide/legacy/macide.c @@ -74,7 +74,7 @@ static void __init macide_setup_ports(hw_regs_t *hw, unsigned long base, for (i = 0; i < 8; i++) hw->io_ports[i] = base + i * 4; - hw->io_ports[IDE_CONTROL_OFFSET] = IDE_CONTROL; + hw->io_ports[IDE_CONTROL_OFFSET] = base + IDE_CONTROL; hw->irq = irq; hw->ack_intr = ack_intr; diff --git a/drivers/ide/pci/via82cxxx.c b/drivers/ide/pci/via82cxxx.c index f3f79f80581..9004e752188 100644 --- a/drivers/ide/pci/via82cxxx.c +++ b/drivers/ide/pci/via82cxxx.c @@ -479,6 +479,7 @@ static int __devinit via_init_one(struct pci_dev *dev, const struct pci_device_i static const struct pci_device_id via_pci_tbl[] = { { PCI_VDEVICE(VIA, PCI_DEVICE_ID_VIA_82C576_1), 0 }, { PCI_VDEVICE(VIA, PCI_DEVICE_ID_VIA_82C586_1), 0 }, + { PCI_VDEVICE(VIA, PCI_DEVICE_ID_VIA_CX700_IDE), 0 }, { PCI_VDEVICE(VIA, PCI_DEVICE_ID_VIA_6410), 1 }, { PCI_VDEVICE(VIA, PCI_DEVICE_ID_VIA_SATA_EIDE), 1 }, { 0, }, diff --git a/drivers/infiniband/core/cm.c b/drivers/infiniband/core/cm.c index 638b727d42e..b10ade92efe 100644 --- a/drivers/infiniband/core/cm.c +++ b/drivers/infiniband/core/cm.c @@ -3587,8 +3587,6 @@ static void cm_release_port_obj(struct kobject *obj) { struct cm_port *cm_port; - printk(KERN_ERR "free cm port\n"); - cm_port = container_of(obj, struct cm_port, port_obj); kfree(cm_port); } @@ -3601,8 +3599,6 @@ static void cm_release_dev_obj(struct kobject *obj) { struct cm_device *cm_dev; - printk(KERN_ERR "free cm dev\n"); - cm_dev = container_of(obj, struct cm_device, dev_obj); kfree(cm_dev); } @@ -3616,18 +3612,12 @@ struct class cm_class = { }; EXPORT_SYMBOL(cm_class); -static void cm_remove_fs_obj(struct kobject *obj) -{ - kobject_put(obj->parent); - kobject_put(obj); -} - static int cm_create_port_fs(struct cm_port *port) { int i, ret; ret = kobject_init_and_add(&port->port_obj, &cm_port_obj_type, - kobject_get(&port->cm_dev->dev_obj), + &port->cm_dev->dev_obj, "%d", port->port_num); if (ret) { kfree(port); @@ -3637,7 +3627,7 @@ static int cm_create_port_fs(struct cm_port *port) for (i = 0; i < CM_COUNTER_GROUPS; i++) { ret = kobject_init_and_add(&port->counter_group[i].obj, &cm_counter_obj_type, - kobject_get(&port->port_obj), + &port->port_obj, "%s", counter_group_names[i]); if (ret) goto error; @@ -3647,8 +3637,8 @@ static int cm_create_port_fs(struct cm_port *port) error: while (i--) - cm_remove_fs_obj(&port->counter_group[i].obj); - cm_remove_fs_obj(&port->port_obj); + kobject_put(&port->counter_group[i].obj); + kobject_put(&port->port_obj); return ret; } @@ -3658,9 +3648,9 @@ static void cm_remove_port_fs(struct cm_port *port) int i; for (i = 0; i < CM_COUNTER_GROUPS; i++) - cm_remove_fs_obj(&port->counter_group[i].obj); + kobject_put(&port->counter_group[i].obj); - cm_remove_fs_obj(&port->port_obj); + kobject_put(&port->port_obj); } static void cm_add_one(struct ib_device *device) @@ -3744,7 +3734,7 @@ error1: ib_unregister_mad_agent(port->mad_agent); cm_remove_port_fs(port); } - cm_remove_fs_obj(&cm_dev->dev_obj); + kobject_put(&cm_dev->dev_obj); } static void cm_remove_one(struct ib_device *device) @@ -3771,7 +3761,7 @@ static void cm_remove_one(struct ib_device *device) ib_unregister_mad_agent(port->mad_agent); cm_remove_port_fs(port); } - cm_remove_fs_obj(&cm_dev->dev_obj); + kobject_put(&cm_dev->dev_obj); } static int __init ib_cm_init(void) diff --git a/drivers/infiniband/core/cma.c b/drivers/infiniband/core/cma.c index 1eff1b2c0e0..34507daaf9b 100644 --- a/drivers/infiniband/core/cma.c +++ b/drivers/infiniband/core/cma.c @@ -1107,7 +1107,6 @@ static int cma_req_handler(struct ib_cm_id *cm_id, struct ib_cm_event *ib_event) event.param.ud.private_data_len = IB_CM_SIDR_REQ_PRIVATE_DATA_SIZE - offset; } else { - ib_send_cm_mra(cm_id, CMA_CM_MRA_SETTING, NULL, 0); conn_id = cma_new_conn_id(&listen_id->id, ib_event); cma_set_req_event_data(&event, &ib_event->param.req_rcvd, ib_event->private_data, offset); @@ -1130,6 +1129,15 @@ static int cma_req_handler(struct ib_cm_id *cm_id, struct ib_cm_event *ib_event) ret = conn_id->id.event_handler(&conn_id->id, &event); if (!ret) { + /* + * Acquire mutex to prevent user executing rdma_destroy_id() + * while we're accessing the cm_id. + */ + mutex_lock(&lock); + if (cma_comp(conn_id, CMA_CONNECT) && + !cma_is_ud_ps(conn_id->id.ps)) + ib_send_cm_mra(cm_id, CMA_CM_MRA_SETTING, NULL, 0); + mutex_unlock(&lock); cma_enable_remove(conn_id); goto out; } diff --git a/drivers/infiniband/core/sysfs.c b/drivers/infiniband/core/sysfs.c index c864ef70fdf..5a4b2e65534 100644 --- a/drivers/infiniband/core/sysfs.c +++ b/drivers/infiniband/core/sysfs.c @@ -686,8 +686,10 @@ int ib_device_register_sysfs(struct ib_device *device) device->ports_parent = kobject_create_and_add("ports", kobject_get(&class_dev->kobj)); - if (!device->ports_parent) + if (!device->ports_parent) { + ret = -ENOMEM; goto err_put; + } if (device->node_type == RDMA_NODE_IB_SWITCH) { ret = add_port(device, 0); diff --git a/drivers/infiniband/hw/cxgb3/iwch_cm.c b/drivers/infiniband/hw/cxgb3/iwch_cm.c index e9a08fa3dff..320f2b6ddee 100644 --- a/drivers/infiniband/hw/cxgb3/iwch_cm.c +++ b/drivers/infiniband/hw/cxgb3/iwch_cm.c @@ -35,6 +35,7 @@ #include <linux/skbuff.h> #include <linux/timer.h> #include <linux/notifier.h> +#include <linux/inetdevice.h> #include <net/neighbour.h> #include <net/netevent.h> @@ -1784,6 +1785,17 @@ err: return err; } +static int is_loopback_dst(struct iw_cm_id *cm_id) +{ + struct net_device *dev; + + dev = ip_dev_find(&init_net, cm_id->remote_addr.sin_addr.s_addr); + if (!dev) + return 0; + dev_put(dev); + return 1; +} + int iwch_connect(struct iw_cm_id *cm_id, struct iw_cm_conn_param *conn_param) { int err = 0; @@ -1791,6 +1803,11 @@ int iwch_connect(struct iw_cm_id *cm_id, struct iw_cm_conn_param *conn_param) struct iwch_ep *ep; struct rtable *rt; + if (is_loopback_dst(cm_id)) { + err = -ENOSYS; + goto out; + } + ep = alloc_ep(sizeof(*ep), GFP_KERNEL); if (!ep) { printk(KERN_ERR MOD "%s - cannot alloc ep.\n", __FUNCTION__); diff --git a/drivers/infiniband/hw/mlx4/mr.c b/drivers/infiniband/hw/mlx4/mr.c index 7dc91a3e712..fe2c2e94a5f 100644 --- a/drivers/infiniband/hw/mlx4/mr.c +++ b/drivers/infiniband/hw/mlx4/mr.c @@ -199,7 +199,7 @@ struct ib_fmr *mlx4_ib_fmr_alloc(struct ib_pd *pd, int acc, if (err) goto err_free; - err = mlx4_mr_enable(to_mdev(pd->device)->dev, &fmr->mfmr.mr); + err = mlx4_fmr_enable(to_mdev(pd->device)->dev, &fmr->mfmr); if (err) goto err_mr; diff --git a/drivers/infiniband/hw/mthca/mthca_cq.c b/drivers/infiniband/hw/mthca/mthca_cq.c index 6bd9f139334..1e1e336d3ef 100644 --- a/drivers/infiniband/hw/mthca/mthca_cq.c +++ b/drivers/infiniband/hw/mthca/mthca_cq.c @@ -473,7 +473,7 @@ static void handle_error_cqe(struct mthca_dev *dev, struct mthca_cq *cq, if (!(new_wqe & cpu_to_be32(0x3f)) || (!cqe->db_cnt && dbd)) return; - cqe->db_cnt = cpu_to_be16(be16_to_cpu(cqe->db_cnt) - dbd); + be16_add_cpu(&cqe->db_cnt, -dbd); cqe->wqe = new_wqe; cqe->syndrome = SYNDROME_WR_FLUSH_ERR; diff --git a/drivers/infiniband/hw/mthca/mthca_memfree.c b/drivers/infiniband/hw/mthca/mthca_memfree.c index 1f4d27d7c16..252db0822f6 100644 --- a/drivers/infiniband/hw/mthca/mthca_memfree.c +++ b/drivers/infiniband/hw/mthca/mthca_memfree.c @@ -542,6 +542,7 @@ struct mthca_user_db_table *mthca_init_user_db_tab(struct mthca_dev *dev) for (i = 0; i < npages; ++i) { db_tab->page[i].refcount = 0; db_tab->page[i].uvirt = 0; + sg_init_table(&db_tab->page[i].mem, 1); } return db_tab; diff --git a/drivers/infiniband/hw/nes/nes_nic.c b/drivers/infiniband/hw/nes/nes_nic.c index b6cc265aa9a..eee77da6193 100644 --- a/drivers/infiniband/hw/nes/nes_nic.c +++ b/drivers/infiniband/hw/nes/nes_nic.c @@ -148,14 +148,15 @@ static int nes_netdev_open(struct net_device *netdev) struct nes_device *nesdev = nesvnic->nesdev; int ret; int i; - struct nes_vnic *first_nesvnic; + struct nes_vnic *first_nesvnic = NULL; u32 nic_active_bit; u32 nic_active; + struct list_head *list_pos, *list_temp; assert(nesdev != NULL); - first_nesvnic = list_entry(nesdev->nesadapter->nesvnic_list[nesdev->mac_index].next, - struct nes_vnic, list); + if (nesvnic->netdev_open == 1) + return 0; if (netif_msg_ifup(nesvnic)) printk(KERN_INFO PFX "%s: enabling interface\n", netdev->name); @@ -225,7 +226,18 @@ static int nes_netdev_open(struct net_device *netdev) nes_write32(nesdev->regs+NES_CQE_ALLOC, NES_CQE_ALLOC_NOTIFY_NEXT | nesvnic->nic_cq.cq_number); nes_read32(nesdev->regs+NES_CQE_ALLOC); - + list_for_each_safe(list_pos, list_temp, &nesdev->nesadapter->nesvnic_list[nesdev->mac_index]) { + first_nesvnic = container_of(list_pos, struct nes_vnic, list); + if (first_nesvnic->netdev_open == 1) + break; + } + if (first_nesvnic->netdev_open == 0) { + nes_debug(NES_DBG_INIT, "Setting up MAC interrupt mask.\n"); + nes_write_indexed(nesdev, NES_IDX_MAC_INT_MASK + (0x200 * nesdev->mac_index), + ~(NES_MAC_INT_LINK_STAT_CHG | NES_MAC_INT_XGMII_EXT | + NES_MAC_INT_TX_UNDERFLOW | NES_MAC_INT_TX_ERROR)); + first_nesvnic = nesvnic; + } if (first_nesvnic->linkup) { /* Enable network packets */ nesvnic->linkup = 1; @@ -248,6 +260,8 @@ static int nes_netdev_stop(struct net_device *netdev) struct nes_device *nesdev = nesvnic->nesdev; u32 nic_active_mask; u32 nic_active; + struct nes_vnic *first_nesvnic = NULL; + struct list_head *list_pos, *list_temp; nes_debug(NES_DBG_SHUTDOWN, "nesvnic=%p, nesdev=%p, netdev=%p %s\n", nesvnic, nesdev, netdev, netdev->name); @@ -260,9 +274,20 @@ static int nes_netdev_stop(struct net_device *netdev) /* Disable network packets */ napi_disable(&nesvnic->napi); netif_stop_queue(netdev); - if ((nesdev->netdev[0] == netdev) & (nesvnic->logical_port == nesdev->mac_index)) { - nes_write_indexed(nesdev, - NES_IDX_MAC_INT_MASK+(0x200*nesdev->mac_index), 0xffffffff); + list_for_each_safe(list_pos, list_temp, &nesdev->nesadapter->nesvnic_list[nesdev->mac_index]) { + first_nesvnic = container_of(list_pos, struct nes_vnic, list); + if ((first_nesvnic->netdev_open == 1) && (first_nesvnic != nesvnic)) + break; + } + + if (first_nesvnic->netdev_open == 0) + nes_write_indexed(nesdev, NES_IDX_MAC_INT_MASK+(0x200*nesdev->mac_index), 0xffffffff); + else if ((first_nesvnic != nesvnic) && + (PCI_FUNC(first_nesvnic->nesdev->pcidev->devfn) != PCI_FUNC(nesvnic->nesdev->pcidev->devfn))) { + nes_write_indexed(nesdev, NES_IDX_MAC_INT_MASK + (0x200 * nesdev->mac_index), 0xffffffff); + nes_write_indexed(first_nesvnic->nesdev, NES_IDX_MAC_INT_MASK + (0x200 * first_nesvnic->nesdev->mac_index), + ~(NES_MAC_INT_LINK_STAT_CHG | NES_MAC_INT_XGMII_EXT | + NES_MAC_INT_TX_UNDERFLOW | NES_MAC_INT_TX_ERROR)); } nic_active_mask = ~((u32)(1 << nesvnic->nic_index)); @@ -859,7 +884,6 @@ void nes_netdev_set_multicast_list(struct net_device *netdev) for (mc_index=0; mc_index < NES_MULTICAST_PF_MAX; mc_index++) { while (multicast_addr && nesvnic->mcrq_mcast_filter && ((mc_nic_index = nesvnic->mcrq_mcast_filter(nesvnic, multicast_addr->dmi_addr)) == 0)) multicast_addr = multicast_addr->next; - if (mc_nic_index < 0) mc_nic_index = nesvnic->nic_index; if (multicast_addr) { @@ -908,7 +932,7 @@ static int nes_netdev_change_mtu(struct net_device *netdev, int new_mtu) return -EINVAL; netdev->mtu = new_mtu; - nesvnic->max_frame_size = new_mtu+ETH_HLEN; + nesvnic->max_frame_size = new_mtu + VLAN_ETH_HLEN; if (netdev->mtu > 1500) { jumbomode=1; @@ -1470,10 +1494,15 @@ static void nes_netdev_vlan_rx_register(struct net_device *netdev, struct vlan_g { struct nes_vnic *nesvnic = netdev_priv(netdev); struct nes_device *nesdev = nesvnic->nesdev; + struct nes_adapter *nesadapter = nesdev->nesadapter; u32 u32temp; + unsigned long flags; + spin_lock_irqsave(&nesadapter->phy_lock, flags); nesvnic->vlan_grp = grp; + nes_debug(NES_DBG_NETDEV, "%s: %s\n", __func__, netdev->name); + /* Enable/Disable VLAN Stripping */ u32temp = nes_read_indexed(nesdev, NES_IDX_PCIX_DIAG); if (grp) @@ -1482,6 +1511,7 @@ static void nes_netdev_vlan_rx_register(struct net_device *netdev, struct vlan_g u32temp |= 0x02000000; nes_write_indexed(nesdev, NES_IDX_PCIX_DIAG, u32temp); + spin_unlock_irqrestore(&nesadapter->phy_lock, flags); } @@ -1540,7 +1570,7 @@ struct net_device *nes_netdev_init(struct nes_device *nesdev, nesvnic->msg_enable = netif_msg_init(debug, default_msg); nesvnic->netdev_index = nesdev->netdev_count; nesvnic->perfect_filter_index = nesdev->nesadapter->netdev_count; - nesvnic->max_frame_size = netdev->mtu+netdev->hard_header_len; + nesvnic->max_frame_size = netdev->mtu + netdev->hard_header_len + VLAN_HLEN; curr_qp_map = nic_qp_mapping_per_function[PCI_FUNC(nesdev->pcidev->devfn)]; nesvnic->nic.qp_id = curr_qp_map[nesdev->netdev_count].qpid; @@ -1610,7 +1640,7 @@ struct net_device *nes_netdev_init(struct nes_device *nesdev, list_add_tail(&nesvnic->list, &nesdev->nesadapter->nesvnic_list[nesdev->mac_index]); if ((nesdev->netdev_count == 0) && - (PCI_FUNC(nesdev->pcidev->devfn) == nesdev->mac_index)) { + (PCI_FUNC(nesdev->pcidev->devfn) == nesdev->mac_index)) { nes_debug(NES_DBG_INIT, "Setting up PHY interrupt mask. Using register index 0x%04X\n", NES_IDX_PHY_PCS_CONTROL_STATUS0+(0x200*(nesvnic->logical_port&1))); u32temp = nes_read_indexed(nesdev, NES_IDX_PHY_PCS_CONTROL_STATUS0 + @@ -1648,18 +1678,14 @@ struct net_device *nes_netdev_init(struct nes_device *nesdev, nesvnic->linkup = 1; } } - nes_debug(NES_DBG_INIT, "Setting up MAC interrupt mask.\n"); /* clear the MAC interrupt status, assumes direct logical to physical mapping */ - u32temp = nes_read_indexed(nesdev, NES_IDX_MAC_INT_STATUS+(0x200*nesvnic->logical_port)); + u32temp = nes_read_indexed(nesdev, NES_IDX_MAC_INT_STATUS + (0x200 * nesdev->mac_index)); nes_debug(NES_DBG_INIT, "Phy interrupt status = 0x%X.\n", u32temp); - nes_write_indexed(nesdev, NES_IDX_MAC_INT_STATUS+(0x200*nesvnic->logical_port), u32temp); + nes_write_indexed(nesdev, NES_IDX_MAC_INT_STATUS + (0x200 * nesdev->mac_index), u32temp); - if (nesdev->nesadapter->phy_type[nesvnic->logical_port] != NES_PHY_TYPE_IRIS) + if (nesdev->nesadapter->phy_type[nesdev->mac_index] != NES_PHY_TYPE_IRIS) nes_init_phy(nesdev); - nes_write_indexed(nesdev, NES_IDX_MAC_INT_MASK+(0x200*nesvnic->logical_port), - ~(NES_MAC_INT_LINK_STAT_CHG | NES_MAC_INT_XGMII_EXT | - NES_MAC_INT_TX_UNDERFLOW | NES_MAC_INT_TX_ERROR)); } return netdev; diff --git a/drivers/infiniband/hw/nes/nes_verbs.c b/drivers/infiniband/hw/nes/nes_verbs.c index ffd4b425567..4dafbe16e82 100644 --- a/drivers/infiniband/hw/nes/nes_verbs.c +++ b/drivers/infiniband/hw/nes/nes_verbs.c @@ -1337,7 +1337,7 @@ static struct ib_qp *nes_create_qp(struct ib_pd *ibpd, NES_MAX_USER_WQ_REGIONS, nes_ucontext->first_free_wq); /* nes_debug(NES_DBG_QP, "find_first_zero_biton wqs returned %u\n", nespd->mmap_db_index); */ - if (nesqp->mmap_sq_db_index > NES_MAX_USER_WQ_REGIONS) { + if (nesqp->mmap_sq_db_index >= NES_MAX_USER_WQ_REGIONS) { nes_debug(NES_DBG_QP, "db index > max user regions, failing create QP\n"); nes_free_resource(nesadapter, nesadapter->allocated_qps, qp_num); diff --git a/drivers/infiniband/ulp/ipoib/ipoib.h b/drivers/infiniband/ulp/ipoib/ipoib.h index f9b7caa5414..054fab8e27a 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib.h +++ b/drivers/infiniband/ulp/ipoib/ipoib.h @@ -209,7 +209,6 @@ struct ipoib_cm_tx { unsigned tx_tail; unsigned long flags; u32 mtu; - struct ib_wc ibwc[IPOIB_NUM_WC]; }; struct ipoib_cm_rx_buf { diff --git a/drivers/infiniband/ulp/ipoib/ipoib_ib.c b/drivers/infiniband/ulp/ipoib/ipoib_ib.c index 9d3e778dc56..08c4396cf41 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib_ib.c +++ b/drivers/infiniband/ulp/ipoib/ipoib_ib.c @@ -780,6 +780,7 @@ static void __ipoib_ib_dev_flush(struct ipoib_dev_priv *priv, int pkey_event) if (ib_find_pkey(priv->ca, priv->port, priv->pkey, &new_index)) { clear_bit(IPOIB_PKEY_ASSIGNED, &priv->flags); ipoib_ib_dev_down(dev, 0); + ipoib_ib_dev_stop(dev, 0); ipoib_pkey_dev_delay_open(dev); return; } diff --git a/drivers/macintosh/mediabay.c b/drivers/macintosh/mediabay.c index 936788272a5..51a112815f4 100644 --- a/drivers/macintosh/mediabay.c +++ b/drivers/macintosh/mediabay.c @@ -416,7 +416,6 @@ static void poll_media_bay(struct media_bay_info* bay) } } -#ifdef CONFIG_MAC_FLOPPY int check_media_bay(struct device_node *which_bay, int what) { int i; @@ -431,7 +430,6 @@ int check_media_bay(struct device_node *which_bay, int what) return -ENODEV; } EXPORT_SYMBOL(check_media_bay); -#endif /* CONFIG_MAC_FLOPPY */ #ifdef CONFIG_BLK_DEV_IDE_PMAC int check_media_bay_by_base(unsigned long base, int what) diff --git a/drivers/md/bitmap.c b/drivers/md/bitmap.c index a0585fb6da9..7aeceedcf7d 100644 --- a/drivers/md/bitmap.c +++ b/drivers/md/bitmap.c @@ -206,16 +206,10 @@ static void bitmap_checkfree(struct bitmap *bitmap, unsigned long page) /* copy the pathname of a file to a buffer */ char *file_path(struct file *file, char *buf, int count) { - struct dentry *d; - struct vfsmount *v; - if (!buf) return NULL; - d = file->f_path.dentry; - v = file->f_path.mnt; - - buf = d_path(d, v, buf, count); + buf = d_path(&file->f_path, buf, count); return IS_ERR(buf) ? NULL : buf; } diff --git a/drivers/md/dm-raid1.c b/drivers/md/dm-raid1.c index edc057f5cdc..2928ef22810 100644 --- a/drivers/md/dm-raid1.c +++ b/drivers/md/dm-raid1.c @@ -124,7 +124,7 @@ enum dm_raid1_error { struct mirror { struct mirror_set *ms; atomic_t error_count; - uint32_t error_type; + unsigned long error_type; struct dm_dev *dev; sector_t offset; }; diff --git a/drivers/md/dm-table.c b/drivers/md/dm-table.c index f1606298238..e75b1437b58 100644 --- a/drivers/md/dm-table.c +++ b/drivers/md/dm-table.c @@ -361,7 +361,7 @@ static int lookup_device(const char *path, dev_t *dev) if ((r = path_lookup(path, LOOKUP_FOLLOW, &nd))) return r; - inode = nd.dentry->d_inode; + inode = nd.path.dentry->d_inode; if (!inode) { r = -ENOENT; goto out; @@ -375,7 +375,7 @@ static int lookup_device(const char *path, dev_t *dev) *dev = inode->i_rdev; out: - path_release(&nd); + path_put(&nd.path); return r; } diff --git a/drivers/md/md.c b/drivers/md/md.c index 5fc326d3970..7da6ec244e1 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c @@ -5197,8 +5197,7 @@ static int md_seq_show(struct seq_file *seq, void *v) chunk_kb ? "KB" : "B"); if (bitmap->file) { seq_printf(seq, ", file: "); - seq_path(seq, bitmap->file->f_path.mnt, - bitmap->file->f_path.dentry," \t\n"); + seq_path(seq, &bitmap->file->f_path, " \t\n"); } seq_printf(seq, "\n"); diff --git a/drivers/media/Kconfig b/drivers/media/Kconfig index 8f4a45346de..11950698a2e 100644 --- a/drivers/media/Kconfig +++ b/drivers/media/Kconfig @@ -25,11 +25,16 @@ config VIDEO_DEV To compile this driver as a module, choose M here: the module will be called videodev. +config VIDEO_V4L2_COMMON + tristate + depends on (I2C || I2C=n) && VIDEO_DEV + default (I2C || I2C=n) && VIDEO_DEV + config VIDEO_V4L1 bool "Enable Video For Linux API 1 (DEPRECATED)" - depends on VIDEO_DEV + depends on VIDEO_DEV && VIDEO_V4L2_COMMON + default VIDEO_DEV && VIDEO_V4L2_COMMON select VIDEO_V4L1_COMPAT - default y ---help--- Enables a compatibility API used by most V4L2 devices to allow its usage with legacy applications that supports only V4L1 api. @@ -39,7 +44,7 @@ config VIDEO_V4L1 config VIDEO_V4L1_COMPAT bool "Enable Video For Linux API 1 compatible Layer" depends on VIDEO_DEV - default y + default VIDEO_DEV ---help--- This api were developed to be used at Kernel 2.2 and 2.4, but lacks support for several video standards. There are several @@ -55,8 +60,8 @@ config VIDEO_V4L1_COMPAT config VIDEO_V4L2 bool - depends on VIDEO_DEV - default y + depends on VIDEO_DEV && VIDEO_V4L2_COMMON + default VIDEO_DEV && VIDEO_V4L2_COMMON source "drivers/media/video/Kconfig" @@ -93,7 +98,7 @@ if VIDEO_TUNER_CUSTOMIZE config TUNER_XC2028 tristate "XCeive xc2028/xc3028 tuners" - depends on I2C + depends on I2C && FW_LOADER default m if VIDEO_TUNER_CUSTOMIZE help Say Y here to include support for the xc2028/xc3028 tuners. @@ -180,7 +185,6 @@ config VIDEO_TVEEPROM config DAB boolean "DAB adapters" - default y ---help--- Allow selecting support for for Digital Audio Broadcasting (DAB) Receiver adapters. diff --git a/drivers/media/common/Kconfig b/drivers/media/common/Kconfig index 06ca75911b7..769c6f8142d 100644 --- a/drivers/media/common/Kconfig +++ b/drivers/media/common/Kconfig @@ -4,6 +4,6 @@ config VIDEO_SAA7146 config VIDEO_SAA7146_VV tristate - depends on VIDEO_DEV + depends on VIDEO_V4L2 select VIDEOBUF_DMA_SG select VIDEO_SAA7146 diff --git a/drivers/media/common/ir-keymaps.c b/drivers/media/common/ir-keymaps.c index a4a937c9053..2ab5a120470 100644 --- a/drivers/media/common/ir-keymaps.c +++ b/drivers/media/common/ir-keymaps.c @@ -1987,3 +1987,49 @@ IR_KEYTAB_TYPE ir_codes_behold[IR_KEYTAB_SIZE] = { }; EXPORT_SYMBOL_GPL(ir_codes_behold); + +/* + * Remote control for the Genius TVGO A11MCE + * Adrian Pardini <pardo.bsso@gmail.com> + */ +IR_KEYTAB_TYPE ir_codes_genius_tvgo_a11mce[IR_KEYTAB_SIZE] = { + /* Keys 0 to 9 */ + [0x48] = KEY_0, + [0x09] = KEY_1, + [0x1d] = KEY_2, + [0x1f] = KEY_3, + [0x19] = KEY_4, + [0x1b] = KEY_5, + [0x11] = KEY_6, + [0x17] = KEY_7, + [0x12] = KEY_8, + [0x16] = KEY_9, + + [0x54] = KEY_RECORD, /* recording */ + [0x06] = KEY_MUTE, /* mute */ + [0x10] = KEY_POWER, + [0x40] = KEY_LAST, /* recall */ + [0x4c] = KEY_CHANNELUP, /* channel / program + */ + [0x00] = KEY_CHANNELDOWN, /* channel / program - */ + [0x0d] = KEY_VOLUMEUP, + [0x15] = KEY_VOLUMEDOWN, + [0x4d] = KEY_OK, /* also labeled as Pause */ + [0x1c] = KEY_ZOOM, /* full screen and Stop*/ + [0x02] = KEY_MODE, /* AV Source or Rewind*/ + [0x04] = KEY_LIST, /* -/-- */ + /* small arrows above numbers */ + [0x1a] = KEY_NEXT, /* also Fast Forward */ + [0x0e] = KEY_PREVIOUS, /* also Rewind */ + /* these are in a rather non standard layout and have + an alternate name written */ + [0x1e] = KEY_UP, /* Video Setting */ + [0x0a] = KEY_DOWN, /* Video Default */ + [0x05] = KEY_LEFT, /* Snapshot */ + [0x0c] = KEY_RIGHT, /* Hide Panel */ + /* Four buttons without label */ + [0x49] = KEY_RED, + [0x0b] = KEY_GREEN, + [0x13] = KEY_YELLOW, + [0x50] = KEY_BLUE, +}; +EXPORT_SYMBOL_GPL(ir_codes_genius_tvgo_a11mce); diff --git a/drivers/media/common/saa7146_vbi.c b/drivers/media/common/saa7146_vbi.c index c32dda973e9..bfbd5a841eb 100644 --- a/drivers/media/common/saa7146_vbi.c +++ b/drivers/media/common/saa7146_vbi.c @@ -413,7 +413,6 @@ static int vbi_open(struct saa7146_dev *dev, struct file *file) V4L2_FIELD_SEQ_TB, // FIXME: does this really work? sizeof(struct saa7146_buf), file); - mutex_init(&fh->vbi_q.lock); init_timer(&fh->vbi_read_timeout); fh->vbi_read_timeout.function = vbi_read_timeout; diff --git a/drivers/media/common/saa7146_video.c b/drivers/media/common/saa7146_video.c index c31ab480d8e..66fdbd0e6a6 100644 --- a/drivers/media/common/saa7146_video.c +++ b/drivers/media/common/saa7146_video.c @@ -1417,8 +1417,6 @@ static int video_open(struct saa7146_dev *dev, struct file *file) sizeof(struct saa7146_buf), file); - mutex_init(&fh->video_q.lock); - return 0; } diff --git a/drivers/media/dvb/bt8xx/bt878.c b/drivers/media/dvb/bt8xx/bt878.c index c7bbb40223f..56d8fab688b 100644 --- a/drivers/media/dvb/bt8xx/bt878.c +++ b/drivers/media/dvb/bt8xx/bt878.c @@ -75,7 +75,11 @@ EXPORT_SYMBOL(bt878); #if defined(dprintk) #undef dprintk #endif -#define dprintk if(bt878_debug) printk +#define dprintk(fmt, arg...) \ + do { \ + if (bt878_debug) \ + printk(KERN_DEBUG fmt, ##arg); \ + } while (0) static void bt878_mem_free(struct bt878 *bt) { @@ -154,7 +158,7 @@ static int bt878_make_risc(struct bt878 *bt) } if (bt->line_count > 255) { - printk("bt878: buffer size error!\n"); + printk(KERN_ERR "bt878: buffer size error!\n"); return -EINVAL; } return 0; @@ -285,7 +289,8 @@ static irqreturn_t bt878_irq(int irq, void *dev_id) if (astat & (BT878_ASCERR | BT878_AOCERR)) { if (bt878_verbose) { - printk("bt878(%d): irq%s%s risc_pc=%08x\n", + printk(KERN_INFO + "bt878(%d): irq%s%s risc_pc=%08x\n", bt->nr, (astat & BT878_ASCERR) ? " SCERR" : "", @@ -295,8 +300,8 @@ static irqreturn_t bt878_irq(int irq, void *dev_id) } if (astat & (BT878_APABORT | BT878_ARIPERR | BT878_APPERR)) { if (bt878_verbose) { - printk - ("bt878(%d): irq%s%s%s risc_pc=%08x\n", + printk(KERN_INFO + "bt878(%d): irq%s%s%s risc_pc=%08x\n", bt->nr, (astat & BT878_APABORT) ? " PABORT" : "", @@ -308,8 +313,8 @@ static irqreturn_t bt878_irq(int irq, void *dev_id) } if (astat & (BT878_AFDSR | BT878_AFTRGT | BT878_AFBUS)) { if (bt878_verbose) { - printk - ("bt878(%d): irq%s%s%s risc_pc=%08x\n", + printk(KERN_INFO + "bt878(%d): irq%s%s%s risc_pc=%08x\n", bt->nr, (astat & BT878_AFDSR) ? " FDSR" : "", (astat & BT878_AFTRGT) ? " FTRGT" : @@ -510,7 +515,7 @@ static int __devinit bt878_probe(struct pci_dev *dev, */ if ((result = bt878_mem_alloc(bt))) { - printk("bt878: failed to allocate memory!\n"); + printk(KERN_ERR "bt878: failed to allocate memory!\n"); goto fail2; } @@ -536,7 +541,7 @@ static void __devexit bt878_remove(struct pci_dev *pci_dev) struct bt878 *bt = pci_get_drvdata(pci_dev); if (bt878_verbose) - printk("bt878(%d): unloading\n", bt->nr); + printk(KERN_INFO "bt878(%d): unloading\n", bt->nr); /* turn off all capturing, DMA and IRQs */ btand(~0x13, BT878_AGPIO_DMA_CTL); diff --git a/drivers/media/dvb/dvb-usb/ttusb2.c b/drivers/media/dvb/dvb-usb/ttusb2.c index 88dc4367a2e..3b9da9c25c6 100644 --- a/drivers/media/dvb/dvb-usb/ttusb2.c +++ b/drivers/media/dvb/dvb-usb/ttusb2.c @@ -144,6 +144,7 @@ static int ttusb2_power_ctrl(struct dvb_usb_device *d, int onoff) static struct tda10086_config tda10086_config = { .demod_address = 0x0e, .invert = 0, + .diseqc_tone = 1, }; static int ttusb2_frontend_attach(struct dvb_usb_adapter *adap) diff --git a/drivers/media/dvb/frontends/tda10086.c b/drivers/media/dvb/frontends/tda10086.c index 9d26ace6515..0d2b69a99ad 100644 --- a/drivers/media/dvb/frontends/tda10086.c +++ b/drivers/media/dvb/frontends/tda10086.c @@ -106,9 +106,12 @@ static int tda10086_write_mask(struct tda10086_state *state, int reg, int mask, static int tda10086_init(struct dvb_frontend* fe) { struct tda10086_state* state = fe->demodulator_priv; + u8 t22k_off = 0x80; dprintk ("%s\n", __FUNCTION__); + if (state->config->diseqc_tone) + t22k_off = 0; // reset tda10086_write_byte(state, 0x00, 0x00); msleep(10); @@ -158,7 +161,7 @@ static int tda10086_init(struct dvb_frontend* fe) tda10086_write_byte(state, 0x3d, 0x80); // setup SEC - tda10086_write_byte(state, 0x36, 0x80); // all SEC off, no 22k tone + tda10086_write_byte(state, 0x36, t22k_off); // all SEC off, 22k tone tda10086_write_byte(state, 0x34, (((1<<19) * (22000/1000)) / (SACLK/1000))); // } tone frequency tda10086_write_byte(state, 0x35, (((1<<19) * (22000/1000)) / (SACLK/1000)) >> 8); // } @@ -180,16 +183,20 @@ static void tda10086_diseqc_wait(struct tda10086_state *state) static int tda10086_set_tone (struct dvb_frontend* fe, fe_sec_tone_mode_t tone) { struct tda10086_state* state = fe->demodulator_priv; + u8 t22k_off = 0x80; dprintk ("%s\n", __FUNCTION__); + if (state->config->diseqc_tone) + t22k_off = 0; + switch (tone) { case SEC_TONE_OFF: - tda10086_write_byte(state, 0x36, 0x80); + tda10086_write_byte(state, 0x36, t22k_off); break; case SEC_TONE_ON: - tda10086_write_byte(state, 0x36, 0x81); + tda10086_write_byte(state, 0x36, 0x01 + t22k_off); break; } @@ -202,9 +209,13 @@ static int tda10086_send_master_cmd (struct dvb_frontend* fe, struct tda10086_state* state = fe->demodulator_priv; int i; u8 oldval; + u8 t22k_off = 0x80; dprintk ("%s\n", __FUNCTION__); + if (state->config->diseqc_tone) + t22k_off = 0; + if (cmd->msg_len > 6) return -EINVAL; oldval = tda10086_read_byte(state, 0x36); @@ -212,7 +223,8 @@ static int tda10086_send_master_cmd (struct dvb_frontend* fe, for(i=0; i< cmd->msg_len; i++) { tda10086_write_byte(state, 0x48+i, cmd->msg[i]); } - tda10086_write_byte(state, 0x36, 0x88 | ((cmd->msg_len - 1) << 4)); + tda10086_write_byte(state, 0x36, (0x08 + t22k_off) + | ((cmd->msg_len - 1) << 4)); tda10086_diseqc_wait(state); @@ -225,16 +237,20 @@ static int tda10086_send_burst (struct dvb_frontend* fe, fe_sec_mini_cmd_t minic { struct tda10086_state* state = fe->demodulator_priv; u8 oldval = tda10086_read_byte(state, 0x36); + u8 t22k_off = 0x80; dprintk ("%s\n", __FUNCTION__); + if (state->config->diseqc_tone) + t22k_off = 0; + switch(minicmd) { case SEC_MINI_A: - tda10086_write_byte(state, 0x36, 0x84); + tda10086_write_byte(state, 0x36, 0x04 + t22k_off); break; case SEC_MINI_B: - tda10086_write_byte(state, 0x36, 0x86); + tda10086_write_byte(state, 0x36, 0x06 + t22k_off); break; } diff --git a/drivers/media/dvb/frontends/tda10086.h b/drivers/media/dvb/frontends/tda10086.h index ed584a8f4a8..eeceaeee78f 100644 --- a/drivers/media/dvb/frontends/tda10086.h +++ b/drivers/media/dvb/frontends/tda10086.h @@ -33,6 +33,9 @@ struct tda10086_config /* does the "inversion" need inverted? */ u8 invert; + + /* do we need the diseqc signal with carrier? */ + u8 diseqc_tone; }; #if defined(CONFIG_DVB_TDA10086) || (defined(CONFIG_DVB_TDA10086_MODULE) && defined(MODULE)) diff --git a/drivers/media/dvb/frontends/tda18271-common.c b/drivers/media/dvb/frontends/tda18271-common.c index cebb6b90b7e..bca57099061 100644 --- a/drivers/media/dvb/frontends/tda18271-common.c +++ b/drivers/media/dvb/frontends/tda18271-common.c @@ -171,7 +171,7 @@ int tda18271_read_extended(struct dvb_frontend *fe) if (ret != 2) tda_err("ERROR: i2c_transfer returned: %d\n", ret); - for (i = 0; i <= TDA18271_NUM_REGS; i++) { + for (i = 0; i < TDA18271_NUM_REGS; i++) { /* don't update write-only registers */ if ((i != R_EB9) && (i != R_EB16) && diff --git a/drivers/media/dvb/frontends/xc5000.h b/drivers/media/dvb/frontends/xc5000.h index e0e84562aed..32a5f1c86a1 100644 --- a/drivers/media/dvb/frontends/xc5000.h +++ b/drivers/media/dvb/frontends/xc5000.h @@ -45,7 +45,8 @@ struct xc5000_config { /* xc5000 callback command */ #define XC5000_TUNER_RESET 0 -#if defined(CONFIG_DVB_TUNER_XC5000) || defined(CONFIG_DVB_TUNER_XC5000_MODULE) +#if defined(CONFIG_DVB_TUNER_XC5000) || \ + (defined(CONFIG_DVB_TUNER_XC5000_MODULE) && defined(MODULE)) extern struct dvb_frontend* xc5000_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, struct xc5000_config *cfg); diff --git a/drivers/media/dvb/ttpci/av7110_av.c b/drivers/media/dvb/ttpci/av7110_av.c index aef6e36d7c5..3e6b650fbb8 100644 --- a/drivers/media/dvb/ttpci/av7110_av.c +++ b/drivers/media/dvb/ttpci/av7110_av.c @@ -966,6 +966,7 @@ static u8 iframe_header[] = { 0x00, 0x00, 0x01, 0xe0, 0x00, 0x00, 0x80, 0x00, 0x static int play_iframe(struct av7110 *av7110, char __user *buf, unsigned int len, int nonblock) { int i, n; + int progressive = 0; dprintk(2, "av7110:%p, \n", av7110); @@ -974,6 +975,14 @@ static int play_iframe(struct av7110 *av7110, char __user *buf, unsigned int len return -EBUSY; } + for (i = 0; i < len - 5; i++) { + /* get progressive flag from picture extension */ + if (buf[i] == 0x00 && buf[i+1] == 0x00 && + buf[i+2] == 0x01 && (unsigned char)buf[i+3] == 0xb5 && + (buf[i+4] & 0xf0) == 0x10) + progressive = buf[i+5] & 0x08; + } + /* setting n always > 1, fixes problems when playing stillframes consisting of I- and P-Frames */ n = MIN_IFRAME / len + 1; @@ -985,7 +994,11 @@ static int play_iframe(struct av7110 *av7110, char __user *buf, unsigned int len dvb_play(av7110, buf, len, 0, 1); av7110_ipack_flush(&av7110->ipack[1]); - return 0; + + if (progressive) + return vidcom(av7110, AV_VIDEO_CMD_FREEZE, 1); + else + return 0; } diff --git a/drivers/media/dvb/ttpci/budget-av.c b/drivers/media/dvb/ttpci/budget-av.c index 3439c9864f6..2d64d557b97 100644 --- a/drivers/media/dvb/ttpci/budget-av.c +++ b/drivers/media/dvb/ttpci/budget-av.c @@ -896,6 +896,7 @@ static u8 read_pwm(struct budget_av *budget_av) #define SUBID_DVBS_CINERGY1200 0x1154 #define SUBID_DVBS_CYNERGY1200N 0x1155 #define SUBID_DVBS_TV_STAR 0x0014 +#define SUBID_DVBS_TV_STAR_PLUS_X4 0x0015 #define SUBID_DVBS_TV_STAR_CI 0x0016 #define SUBID_DVBS_EASYWATCH_1 0x001a #define SUBID_DVBS_EASYWATCH_2 0x001b @@ -910,6 +911,7 @@ static u8 read_pwm(struct budget_av *budget_av) #define SUBID_DVBC_CINERGY1200 0x1156 #define SUBID_DVBC_CINERGY1200_MK3 0x1176 +#define SUBID_DVBT_EASYWATCH 0x003a #define SUBID_DVBT_KNC1_PLUS 0x0031 #define SUBID_DVBT_KNC1 0x0030 #define SUBID_DVBT_CINERGY1200 0x1157 @@ -957,6 +959,7 @@ static void frontend_init(struct budget_av *budget_av) break; case SUBID_DVBS_TV_STAR: + case SUBID_DVBS_TV_STAR_PLUS_X4: case SUBID_DVBS_TV_STAR_CI: case SUBID_DVBS_CYNERGY1200N: case SUBID_DVBS_EASYWATCH: @@ -1018,6 +1021,7 @@ static void frontend_init(struct budget_av *budget_av) } break; + case SUBID_DVBT_EASYWATCH: case SUBID_DVBT_KNC1: case SUBID_DVBT_KNC1_PLUS: case SUBID_DVBT_CINERGY1200: @@ -1248,7 +1252,9 @@ MAKE_BUDGET_INFO(satewpls1, "Satelco EasyWatch DVB-S light", BUDGET_KNC1S); MAKE_BUDGET_INFO(satewps, "Satelco EasyWatch DVB-S", BUDGET_KNC1S); MAKE_BUDGET_INFO(satewplc, "Satelco EasyWatch DVB-C", BUDGET_KNC1CP); MAKE_BUDGET_INFO(satewcmk3, "Satelco EasyWatch DVB-C MK3", BUDGET_KNC1C_MK3); +MAKE_BUDGET_INFO(satewt, "Satelco EasyWatch DVB-T", BUDGET_KNC1T); MAKE_BUDGET_INFO(knc1sp, "KNC1 DVB-S Plus", BUDGET_KNC1SP); +MAKE_BUDGET_INFO(knc1spx4, "KNC1 DVB-S Plus X4", BUDGET_KNC1SP); MAKE_BUDGET_INFO(knc1cp, "KNC1 DVB-C Plus", BUDGET_KNC1CP); MAKE_BUDGET_INFO(knc1cmk3, "KNC1 DVB-C MK3", BUDGET_KNC1C_MK3); MAKE_BUDGET_INFO(knc1cpmk3, "KNC1 DVB-C Plus MK3", BUDGET_KNC1CP_MK3); @@ -1266,12 +1272,14 @@ static struct pci_device_id pci_tbl[] = { MAKE_EXTENSION_PCI(knc1sp, 0x1131, 0x0011), MAKE_EXTENSION_PCI(knc1sp, 0x1894, 0x0011), MAKE_EXTENSION_PCI(kncxs, 0x1894, 0x0014), + MAKE_EXTENSION_PCI(knc1spx4, 0x1894, 0x0015), MAKE_EXTENSION_PCI(kncxs, 0x1894, 0x0016), MAKE_EXTENSION_PCI(satewpls, 0x1894, 0x001e), MAKE_EXTENSION_PCI(satewpls1, 0x1894, 0x001a), MAKE_EXTENSION_PCI(satewps, 0x1894, 0x001b), MAKE_EXTENSION_PCI(satewplc, 0x1894, 0x002a), MAKE_EXTENSION_PCI(satewcmk3, 0x1894, 0x002c), + MAKE_EXTENSION_PCI(satewt, 0x1894, 0x003a), MAKE_EXTENSION_PCI(knc1c, 0x1894, 0x0020), MAKE_EXTENSION_PCI(knc1cp, 0x1894, 0x0021), MAKE_EXTENSION_PCI(knc1cmk3, 0x1894, 0x0022), diff --git a/drivers/media/dvb/ttpci/budget.c b/drivers/media/dvb/ttpci/budget.c index 9268a82bada..14b00f57b5d 100644 --- a/drivers/media/dvb/ttpci/budget.c +++ b/drivers/media/dvb/ttpci/budget.c @@ -351,6 +351,7 @@ static struct s5h1420_config s5h1420_config = { static struct tda10086_config tda10086_config = { .demod_address = 0x0e, .invert = 0, + .diseqc_tone = 1, }; static u8 read_pwm(struct budget* budget) diff --git a/drivers/media/radio/Kconfig b/drivers/media/radio/Kconfig index 8d5214f18cf..1b41b3f77cf 100644 --- a/drivers/media/radio/Kconfig +++ b/drivers/media/radio/Kconfig @@ -4,12 +4,12 @@ menuconfig RADIO_ADAPTERS bool "Radio Adapters" - depends on VIDEO_DEV + depends on VIDEO_V4L2 default y ---help--- Say Y here to enable selecting AM/FM radio adapters. -if RADIO_ADAPTERS && VIDEO_DEV +if RADIO_ADAPTERS && VIDEO_V4L2 config RADIO_CADET tristate "ADS Cadet AM/FM Tuner" diff --git a/drivers/media/radio/radio-sf16fmi.c b/drivers/media/radio/radio-sf16fmi.c index 3118bdab318..53e11485737 100644 --- a/drivers/media/radio/radio-sf16fmi.c +++ b/drivers/media/radio/radio-sf16fmi.c @@ -361,6 +361,7 @@ static int __init fmi_init(void) } if (!request_region(io, 2, "radio-sf16fmi")) { printk(KERN_ERR "radio-sf16fmi: port 0x%x already in use\n", io); + pnp_device_detach(dev); return -EBUSY; } diff --git a/drivers/media/radio/radio-sf16fmr2.c b/drivers/media/radio/radio-sf16fmr2.c index f7c8b000404..ebc5fbbc38b 100644 --- a/drivers/media/radio/radio-sf16fmr2.c +++ b/drivers/media/radio/radio-sf16fmr2.c @@ -470,9 +470,8 @@ static int __init fmr2_init(void) mutex_init(&lock); - if (request_region(io, 2, "sf16fmr2")) - { - printk(KERN_ERR "fmr2: port 0x%x already in use\n", io); + if (!request_region(io, 2, "sf16fmr2")) { + printk(KERN_ERR "radio-sf16fmr2: request_region failed!\n"); return -EBUSY; } diff --git a/drivers/media/radio/radio-si470x.c b/drivers/media/radio/radio-si470x.c index 8e4bd476904..649f14d2c01 100644 --- a/drivers/media/radio/radio-si470x.c +++ b/drivers/media/radio/radio-si470x.c @@ -62,6 +62,29 @@ * - code cleaned of unnecessary rds_commands * - USB Vendor/Product ID for ADS/Tech FM Radio Receiver verified * (thanks to Guillaume RAMOUSSE) + * 2008-01-27 Tobias Lorenz <tobias.lorenz@gmx.net> + * Version 1.0.5 + * - number of seek_retries changed to tune_timeout + * - fixed problem with incomplete tune operations by own buffers + * - optimization of variables and printf types + * - improved error logging + * 2008-01-31 Tobias Lorenz <tobias.lorenz@gmx.net> + * Oliver Neukum <oliver@neukum.org> + * Version 1.0.6 + * - fixed coverity checker warnings in *_usb_driver_disconnect + * - probe()/open() race by correct ordering in probe() + * - DMA coherency rules by separate allocation of all buffers + * - use of endianness macros + * - abuse of spinlock, replaced by mutex + * - racy handling of timer in disconnect, + * replaced by delayed_work + * - racy interruptible_sleep_on(), + * replaced with wait_event_interruptible() + * - handle signals in read() + * 2008-02-08 Tobias Lorenz <tobias.lorenz@gmx.net> + * Oliver Neukum <oliver@neukum.org> + * Version 1.0.7 + * - usb autosuspend support * * ToDo: * - add seeking support @@ -74,9 +97,10 @@ /* driver definitions */ #define DRIVER_AUTHOR "Tobias Lorenz <tobias.lorenz@gmx.net>" #define DRIVER_NAME "radio-si470x" -#define DRIVER_VERSION KERNEL_VERSION(1, 0, 4) +#define DRIVER_KERNEL_VERSION KERNEL_VERSION(1, 0, 6) #define DRIVER_CARD "Silicon Labs Si470x FM Radio Receiver" #define DRIVER_DESC "USB radio driver for Si470x FM Radio Receivers" +#define DRIVER_VERSION "1.0.6" /* kernel includes */ @@ -89,8 +113,10 @@ #include <linux/hid.h> #include <linux/version.h> #include <linux/videodev2.h> +#include <linux/mutex.h> #include <media/v4l2-common.h> #include <media/rds.h> +#include <asm/unaligned.h> /* USB Device ID List */ @@ -119,56 +145,56 @@ MODULE_PARM_DESC(radio_nr, "Radio Nr"); /* 0: 200 kHz (USA, Australia) */ /* 1: 100 kHz (Europe, Japan) */ /* 2: 50 kHz */ -static int space = 2; -module_param(space, int, 0); +static unsigned short space = 2; +module_param(space, ushort, 0); MODULE_PARM_DESC(radio_nr, "Spacing: 0=200kHz 1=100kHz *2=50kHz*"); /* Bottom of Band (MHz) */ /* 0: 87.5 - 108 MHz (USA, Europe)*/ /* 1: 76 - 108 MHz (Japan wide band) */ /* 2: 76 - 90 MHz (Japan) */ -static int band = 1; -module_param(band, int, 0); +static unsigned short band = 1; +module_param(band, ushort, 0); MODULE_PARM_DESC(radio_nr, "Band: 0=87.5..108MHz *1=76..108MHz* 2=76..90MHz"); /* De-emphasis */ /* 0: 75 us (USA) */ /* 1: 50 us (Europe, Australia, Japan) */ -static int de = 1; -module_param(de, int, 0); +static unsigned short de = 1; +module_param(de, ushort, 0); MODULE_PARM_DESC(radio_nr, "De-emphasis: 0=75us *1=50us*"); /* USB timeout */ -static int usb_timeout = 500; -module_param(usb_timeout, int, 0); +static unsigned int usb_timeout = 500; +module_param(usb_timeout, uint, 0); MODULE_PARM_DESC(usb_timeout, "USB timeout (ms): *500*"); -/* Seek retries */ -static int seek_retries = 100; -module_param(seek_retries, int, 0); -MODULE_PARM_DESC(seek_retries, "Seek retries: *100*"); +/* Tune timeout */ +static unsigned int tune_timeout = 3000; +module_param(tune_timeout, uint, 0); +MODULE_PARM_DESC(tune_timeout, "Tune timeout: *3000*"); /* RDS buffer blocks */ -static int rds_buf = 100; -module_param(rds_buf, int, 0); +static unsigned int rds_buf = 100; +module_param(rds_buf, uint, 0); MODULE_PARM_DESC(rds_buf, "RDS buffer entries: *100*"); /* RDS maximum block errors */ -static int max_rds_errors = 1; +static unsigned short max_rds_errors = 1; /* 0 means 0 errors requiring correction */ /* 1 means 1-2 errors requiring correction (used by original USBRadio.exe) */ /* 2 means 3-5 errors requiring correction */ /* 3 means 6+ errors or errors in checkword, correction not possible */ -module_param(max_rds_errors, int, 0); +module_param(max_rds_errors, ushort, 0); MODULE_PARM_DESC(max_rds_errors, "RDS maximum block errors: *1*"); /* RDS poll frequency */ -static int rds_poll_time = 40; +static unsigned int rds_poll_time = 40; /* 40 is used by the original USBRadio.exe */ /* 50 is used by radio-cadet */ /* 75 should be okay */ /* 80 is the usual RDS receive interval */ -module_param(rds_poll_time, int, 0); +module_param(rds_poll_time, uint, 0); MODULE_PARM_DESC(rds_poll_time, "RDS poll time (ms): *40*"); @@ -393,22 +419,19 @@ MODULE_PARM_DESC(rds_poll_time, "RDS poll time (ms): *40*"); struct si470x_device { /* reference to USB and video device */ struct usb_device *usbdev; + struct usb_interface *intf; struct video_device *videodev; - /* are these really necessary ? */ - int users; - - /* report buffer (maximum 64 bytes) */ - unsigned char buf[64]; + /* driver management */ + unsigned int users; /* Silabs internal registers (0..15) */ unsigned short registers[RADIO_REGISTER_NUM]; /* RDS receive buffer */ - struct work_struct work; + struct delayed_work work; wait_queue_head_t read_queue; - struct timer_list timer; - spinlock_t lock; /* buffer locking */ + struct mutex lock; /* buffer locking */ unsigned char *buffer; /* size is always multiple of three */ unsigned int buf_size; unsigned int rd_index; @@ -434,28 +457,46 @@ struct si470x_device { /* * si470x_get_report - receive a HID report */ -static int si470x_get_report(struct si470x_device *radio, int size) +static int si470x_get_report(struct si470x_device *radio, void *buf, int size) { - return usb_control_msg(radio->usbdev, + unsigned char *report = (unsigned char *) buf; + int retval; + + retval = usb_control_msg(radio->usbdev, usb_rcvctrlpipe(radio->usbdev, 0), HID_REQ_GET_REPORT, USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_IN, - radio->buf[0], 2, - radio->buf, size, usb_timeout); + report[0], 2, + buf, size, usb_timeout); + if (retval < 0) + printk(KERN_WARNING DRIVER_NAME + ": si470x_get_report: usb_control_msg returned %d\n", + retval); + + return retval; } /* * si470x_set_report - send a HID report */ -static int si470x_set_report(struct si470x_device *radio, int size) +static int si470x_set_report(struct si470x_device *radio, void *buf, int size) { - return usb_control_msg(radio->usbdev, + unsigned char *report = (unsigned char *) buf; + int retval; + + retval = usb_control_msg(radio->usbdev, usb_sndctrlpipe(radio->usbdev, 0), HID_REQ_SET_REPORT, USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_OUT, - radio->buf[0], 2, - radio->buf, size, usb_timeout); + report[0], 2, + buf, size, usb_timeout); + if (retval < 0) + printk(KERN_WARNING DRIVER_NAME + ": si470x_set_report: usb_control_msg returned %d\n", + retval); + + return retval; } @@ -464,13 +505,16 @@ static int si470x_set_report(struct si470x_device *radio, int size) */ static int si470x_get_register(struct si470x_device *radio, int regnr) { + unsigned char buf[REGISTER_REPORT_SIZE]; int retval; - radio->buf[0] = REGISTER_REPORT(regnr); + buf[0] = REGISTER_REPORT(regnr); + + retval = si470x_get_report(radio, (void *) &buf, sizeof(buf)); - retval = si470x_get_report(radio, REGISTER_REPORT_SIZE); if (retval >= 0) - radio->registers[regnr] = (radio->buf[1] << 8) | radio->buf[2]; + radio->registers[regnr] = be16_to_cpu(get_unaligned( + (unsigned short *) &buf[1])); return (retval < 0) ? -EINVAL : 0; } @@ -481,13 +525,14 @@ static int si470x_get_register(struct si470x_device *radio, int regnr) */ static int si470x_set_register(struct si470x_device *radio, int regnr) { + unsigned char buf[REGISTER_REPORT_SIZE]; int retval; - radio->buf[0] = REGISTER_REPORT(regnr); - radio->buf[1] = (radio->registers[regnr] & 0xff00) >> 8; - radio->buf[2] = (radio->registers[regnr] & 0x00ff); + buf[0] = REGISTER_REPORT(regnr); + put_unaligned(cpu_to_be16(radio->registers[regnr]), + (unsigned short *) &buf[1]); - retval = si470x_set_report(radio, REGISTER_REPORT_SIZE); + retval = si470x_set_report(radio, (void *) &buf, sizeof(buf)); return (retval < 0) ? -EINVAL : 0; } @@ -498,18 +543,19 @@ static int si470x_set_register(struct si470x_device *radio, int regnr) */ static int si470x_get_all_registers(struct si470x_device *radio) { + unsigned char buf[ENTIRE_REPORT_SIZE]; int retval; - int regnr; + unsigned char regnr; - radio->buf[0] = ENTIRE_REPORT; + buf[0] = ENTIRE_REPORT; - retval = si470x_get_report(radio, ENTIRE_REPORT_SIZE); + retval = si470x_get_report(radio, (void *) &buf, sizeof(buf)); if (retval >= 0) for (regnr = 0; regnr < RADIO_REGISTER_NUM; regnr++) - radio->registers[regnr] = - (radio->buf[regnr * RADIO_REGISTER_SIZE + 1] << 8) | - radio->buf[regnr * RADIO_REGISTER_SIZE + 2]; + radio->registers[regnr] = be16_to_cpu(get_unaligned( + (unsigned short *) + &buf[regnr * RADIO_REGISTER_SIZE + 1])); return (retval < 0) ? -EINVAL : 0; } @@ -520,21 +566,28 @@ static int si470x_get_all_registers(struct si470x_device *radio) */ static int si470x_get_rds_registers(struct si470x_device *radio) { + unsigned char buf[RDS_REPORT_SIZE]; int retval; - int regnr; int size; + unsigned char regnr; - radio->buf[0] = RDS_REPORT; + buf[0] = RDS_REPORT; retval = usb_interrupt_msg(radio->usbdev, - usb_rcvctrlpipe(radio->usbdev, 1), - radio->buf, RDS_REPORT_SIZE, &size, usb_timeout); + usb_rcvintpipe(radio->usbdev, 1), + (void *) &buf, sizeof(buf), &size, usb_timeout); + if (size != sizeof(buf)) + printk(KERN_WARNING DRIVER_NAME ": si470x_get_rds_register: " + "return size differs: %d != %zu\n", size, sizeof(buf)); + if (retval < 0) + printk(KERN_WARNING DRIVER_NAME ": si470x_get_rds_registers: " + "usb_interrupt_msg returned %d\n", retval); if (retval >= 0) for (regnr = 0; regnr < RDS_REGISTER_NUM; regnr++) radio->registers[STATUSRSSI + regnr] = - (radio->buf[regnr * RADIO_REGISTER_SIZE + 1] << 8) | - radio->buf[regnr * RADIO_REGISTER_SIZE + 2]; + be16_to_cpu(get_unaligned((unsigned short *) + &buf[regnr * RADIO_REGISTER_SIZE + 1])); return (retval < 0) ? -EINVAL : 0; } @@ -543,9 +596,11 @@ static int si470x_get_rds_registers(struct si470x_device *radio) /* * si470x_set_chan - set the channel */ -static int si470x_set_chan(struct si470x_device *radio, int chan) +static int si470x_set_chan(struct si470x_device *radio, unsigned short chan) { - int retval, i; + int retval; + unsigned long timeout; + bool timed_out = 0; /* start tuning */ radio->registers[CHANNEL] &= ~CHANNEL_CHAN; @@ -555,16 +610,17 @@ static int si470x_set_chan(struct si470x_device *radio, int chan) return retval; /* wait till seek operation has completed */ - i = 0; + timeout = jiffies + msecs_to_jiffies(tune_timeout); do { retval = si470x_get_register(radio, STATUSRSSI); if (retval < 0) return retval; - } while ((radio->registers[STATUSRSSI] & STATUSRSSI_STC) && - (++i < seek_retries)); - if (i >= seek_retries) + timed_out = time_after(jiffies, timeout); + } while (((radio->registers[STATUSRSSI] & STATUSRSSI_STC) == 0) && + (!timed_out)); + if (timed_out) printk(KERN_WARNING DRIVER_NAME - ": seek does not finish after %d tries\n", i); + ": seek does not finish after %u ms\n", tune_timeout); /* stop tuning */ radio->registers[CHANNEL] &= ~CHANNEL_TUNE; @@ -575,9 +631,10 @@ static int si470x_set_chan(struct si470x_device *radio, int chan) /* * si470x_get_freq - get the frequency */ -static int si470x_get_freq(struct si470x_device *radio) +static unsigned int si470x_get_freq(struct si470x_device *radio) { - int spacing, band_bottom, chan, freq; + unsigned int spacing, band_bottom, freq; + unsigned short chan; int retval; /* Spacing (kHz) */ @@ -616,9 +673,10 @@ static int si470x_get_freq(struct si470x_device *radio) /* * si470x_set_freq - set the frequency */ -static int si470x_set_freq(struct si470x_device *radio, int freq) +static int si470x_set_freq(struct si470x_device *radio, unsigned int freq) { - int spacing, band_bottom, chan; + unsigned int spacing, band_bottom; + unsigned short chan; /* Spacing (kHz) */ switch (space) { @@ -709,9 +767,17 @@ static int si470x_stop(struct si470x_device *radio) */ static int si470x_rds_on(struct si470x_device *radio) { + int retval; + /* sysconfig 1 */ + mutex_lock(&radio->lock); radio->registers[SYSCONFIG1] |= SYSCONFIG1_RDS; - return si470x_set_register(radio, SYSCONFIG1); + retval = si470x_set_register(radio, SYSCONFIG1); + if (retval < 0) + radio->registers[SYSCONFIG1] &= ~SYSCONFIG1_RDS; + mutex_unlock(&radio->lock); + + return retval; } @@ -725,11 +791,10 @@ static int si470x_rds_on(struct si470x_device *radio) */ static void si470x_rds(struct si470x_device *radio) { - unsigned char tmpbuf[3]; unsigned char blocknum; - unsigned char bler; /* rds block errors */ + unsigned short bler; /* rds block errors */ unsigned short rds; - unsigned int i; + unsigned char tmpbuf[3]; /* get rds blocks */ if (si470x_get_rds_registers(radio) < 0) @@ -743,63 +808,58 @@ static void si470x_rds(struct si470x_device *radio) return; } - /* copy four RDS blocks to internal buffer */ - if (spin_trylock(&radio->lock)) { - /* process each rds block */ - for (blocknum = 0; blocknum < 4; blocknum++) { - switch (blocknum) { - default: - bler = (radio->registers[STATUSRSSI] & - STATUSRSSI_BLERA) >> 9; - rds = radio->registers[RDSA]; - break; - case 1: - bler = (radio->registers[READCHAN] & - READCHAN_BLERB) >> 14; - rds = radio->registers[RDSB]; - break; - case 2: - bler = (radio->registers[READCHAN] & - READCHAN_BLERC) >> 12; - rds = radio->registers[RDSC]; - break; - case 3: - bler = (radio->registers[READCHAN] & - READCHAN_BLERD) >> 10; - rds = radio->registers[RDSD]; - break; - }; - - /* Fill the V4L2 RDS buffer */ - tmpbuf[0] = rds & 0x00ff; /* LSB */ - tmpbuf[1] = (rds & 0xff00) >> 8;/* MSB */ - tmpbuf[2] = blocknum; /* offset name */ - tmpbuf[2] |= blocknum << 3; /* received offset */ - if (bler > max_rds_errors) - tmpbuf[2] |= 0x80; /* uncorrectable errors */ - else if (bler > 0) - tmpbuf[2] |= 0x40; /* corrected error(s) */ - - /* copy RDS block to internal buffer */ - for (i = 0; i < 3; i++) { - radio->buffer[radio->wr_index] = tmpbuf[i]; - radio->wr_index++; - } - - /* wrap write pointer */ - if (radio->wr_index >= radio->buf_size) - radio->wr_index = 0; - - /* check for overflow */ - if (radio->wr_index == radio->rd_index) { - /* increment and wrap read pointer */ - radio->rd_index += 3; - if (radio->rd_index >= radio->buf_size) - radio->rd_index = 0; - } + /* copy all four RDS blocks to internal buffer */ + mutex_lock(&radio->lock); + for (blocknum = 0; blocknum < 4; blocknum++) { + switch (blocknum) { + default: + bler = (radio->registers[STATUSRSSI] & + STATUSRSSI_BLERA) >> 9; + rds = radio->registers[RDSA]; + break; + case 1: + bler = (radio->registers[READCHAN] & + READCHAN_BLERB) >> 14; + rds = radio->registers[RDSB]; + break; + case 2: + bler = (radio->registers[READCHAN] & + READCHAN_BLERC) >> 12; + rds = radio->registers[RDSC]; + break; + case 3: + bler = (radio->registers[READCHAN] & + READCHAN_BLERD) >> 10; + rds = radio->registers[RDSD]; + break; + }; + + /* Fill the V4L2 RDS buffer */ + put_unaligned(cpu_to_le16(rds), (unsigned short *) &tmpbuf); + tmpbuf[2] = blocknum; /* offset name */ + tmpbuf[2] |= blocknum << 3; /* received offset */ + if (bler > max_rds_errors) + tmpbuf[2] |= 0x80; /* uncorrectable errors */ + else if (bler > 0) + tmpbuf[2] |= 0x40; /* corrected error(s) */ + + /* copy RDS block to internal buffer */ + memcpy(&radio->buffer[radio->wr_index], &tmpbuf, 3); + radio->wr_index += 3; + + /* wrap write pointer */ + if (radio->wr_index >= radio->buf_size) + radio->wr_index = 0; + + /* check for overflow */ + if (radio->wr_index == radio->rd_index) { + /* increment and wrap read pointer */ + radio->rd_index += 3; + if (radio->rd_index >= radio->buf_size) + radio->rd_index = 0; } - spin_unlock(&radio->lock); } + mutex_unlock(&radio->lock); /* wake up read queue */ if (radio->wr_index != radio->rd_index) @@ -808,29 +868,18 @@ static void si470x_rds(struct si470x_device *radio) /* - * si470x_timer - rds timer function - */ -static void si470x_timer(unsigned long data) -{ - struct si470x_device *radio = (struct si470x_device *) data; - - schedule_work(&radio->work); -} - - -/* * si470x_work - rds work function */ static void si470x_work(struct work_struct *work) { struct si470x_device *radio = container_of(work, struct si470x_device, - work); + work.work); if ((radio->registers[SYSCONFIG1] & SYSCONFIG1_RDS) == 0) return; si470x_rds(radio); - mod_timer(&radio->timer, jiffies + msecs_to_jiffies(rds_poll_time)); + schedule_delayed_work(&radio->work, msecs_to_jiffies(rds_poll_time)); } @@ -852,44 +901,44 @@ static ssize_t si470x_fops_read(struct file *file, char __user *buf, /* switch on rds reception */ if ((radio->registers[SYSCONFIG1] & SYSCONFIG1_RDS) == 0) { si470x_rds_on(radio); - schedule_work(&radio->work); + schedule_delayed_work(&radio->work, + msecs_to_jiffies(rds_poll_time)); } /* block if no new data available */ while (radio->wr_index == radio->rd_index) { if (file->f_flags & O_NONBLOCK) return -EWOULDBLOCK; - interruptible_sleep_on(&radio->read_queue); + if (wait_event_interruptible(radio->read_queue, + radio->wr_index != radio->rd_index) < 0) + return -EINTR; } /* calculate block count from byte count */ count /= 3; /* copy RDS block out of internal buffer and to user buffer */ - if (spin_trylock(&radio->lock)) { - while (block_count < count) { - if (radio->rd_index == radio->wr_index) - break; - - /* always transfer rds complete blocks */ - if (copy_to_user(buf, - &radio->buffer[radio->rd_index], 3)) - /* retval = -EFAULT; */ - break; - - /* increment and wrap read pointer */ - radio->rd_index += 3; - if (radio->rd_index >= radio->buf_size) - radio->rd_index = 0; - - /* increment counters */ - block_count++; - buf += 3; - retval += 3; - } - - spin_unlock(&radio->lock); + mutex_lock(&radio->lock); + while (block_count < count) { + if (radio->rd_index == radio->wr_index) + break; + + /* always transfer rds complete blocks */ + if (copy_to_user(buf, &radio->buffer[radio->rd_index], 3)) + /* retval = -EFAULT; */ + break; + + /* increment and wrap read pointer */ + radio->rd_index += 3; + if (radio->rd_index >= radio->buf_size) + radio->rd_index = 0; + + /* increment counters */ + block_count++; + buf += 3; + retval += 3; } + mutex_unlock(&radio->lock); return retval; } @@ -906,7 +955,8 @@ static unsigned int si470x_fops_poll(struct file *file, /* switch on rds reception */ if ((radio->registers[SYSCONFIG1] & SYSCONFIG1_RDS) == 0) { si470x_rds_on(radio); - schedule_work(&radio->work); + schedule_delayed_work(&radio->work, + msecs_to_jiffies(rds_poll_time)); } poll_wait(file, &radio->read_queue, pts); @@ -924,10 +974,22 @@ static unsigned int si470x_fops_poll(struct file *file, static int si470x_fops_open(struct inode *inode, struct file *file) { struct si470x_device *radio = video_get_drvdata(video_devdata(file)); + int retval; radio->users++; - if (radio->users == 1) - return si470x_start(radio); + + retval = usb_autopm_get_interface(radio->intf); + if (retval < 0) { + radio->users--; + return -EIO; + } + + if (radio->users == 1) { + retval = si470x_start(radio); + if (retval < 0) + usb_autopm_put_interface(radio->intf); + return retval; + } return 0; } @@ -939,6 +1001,7 @@ static int si470x_fops_open(struct inode *inode, struct file *file) static int si470x_fops_release(struct inode *inode, struct file *file) { struct si470x_device *radio = video_get_drvdata(video_devdata(file)); + int retval; if (!radio) return -ENODEV; @@ -946,13 +1009,14 @@ static int si470x_fops_release(struct inode *inode, struct file *file) radio->users--; if (radio->users == 0) { /* stop rds reception */ - del_timer_sync(&radio->timer); - flush_scheduled_work(); + cancel_delayed_work_sync(&radio->work); /* cancel read processes */ wake_up_interruptible(&radio->read_queue); - return si470x_stop(radio); + retval = si470x_stop(radio); + usb_autopm_put_interface(radio->intf); + return retval; } return 0; @@ -1030,7 +1094,7 @@ static int si470x_vidioc_querycap(struct file *file, void *priv, strlcpy(capability->driver, DRIVER_NAME, sizeof(capability->driver)); strlcpy(capability->card, DRIVER_CARD, sizeof(capability->card)); sprintf(capability->bus_info, "USB"); - capability->version = DRIVER_VERSION; + capability->version = DRIVER_KERNEL_VERSION; capability->capabilities = V4L2_CAP_TUNER | V4L2_CAP_RADIO; return 0; @@ -1067,16 +1131,21 @@ static int si470x_vidioc_s_input(struct file *filp, void *priv, unsigned int i) static int si470x_vidioc_queryctrl(struct file *file, void *priv, struct v4l2_queryctrl *qc) { - int i; + unsigned char i; + int retval = -EINVAL; for (i = 0; i < ARRAY_SIZE(si470x_v4l2_queryctrl); i++) { if (qc->id && qc->id == si470x_v4l2_queryctrl[i].id) { memcpy(qc, &(si470x_v4l2_queryctrl[i]), sizeof(*qc)); - return 0; + retval = 0; + break; } } + if (retval < 0) + printk(KERN_WARNING DRIVER_NAME + ": query control failed with %d\n", retval); - return -EINVAL; + return retval; } @@ -1110,21 +1179,29 @@ static int si470x_vidioc_s_ctrl(struct file *file, void *priv, struct v4l2_control *ctrl) { struct si470x_device *radio = video_get_drvdata(video_devdata(file)); + int retval; switch (ctrl->id) { case V4L2_CID_AUDIO_VOLUME: radio->registers[SYSCONFIG2] &= ~SYSCONFIG2_VOLUME; radio->registers[SYSCONFIG2] |= ctrl->value; - return si470x_set_register(radio, SYSCONFIG2); + retval = si470x_set_register(radio, SYSCONFIG2); + break; case V4L2_CID_AUDIO_MUTE: if (ctrl->value == 1) radio->registers[POWERCFG] &= ~POWERCFG_DMUTE; else radio->registers[POWERCFG] |= POWERCFG_DMUTE; - return si470x_set_register(radio, POWERCFG); + retval = si470x_set_register(radio, POWERCFG); + break; + default: + retval = -EINVAL; } + if (retval < 0) + printk(KERN_WARNING DRIVER_NAME + ": set control failed with %d\n", retval); - return -EINVAL; + return retval; } @@ -1163,8 +1240,8 @@ static int si470x_vidioc_s_audio(struct file *file, void *priv, static int si470x_vidioc_g_tuner(struct file *file, void *priv, struct v4l2_tuner *tuner) { - int retval; struct si470x_device *radio = video_get_drvdata(video_devdata(file)); + int retval; if (tuner->index > 0) return -EINVAL; @@ -1220,6 +1297,7 @@ static int si470x_vidioc_s_tuner(struct file *file, void *priv, struct v4l2_tuner *tuner) { struct si470x_device *radio = video_get_drvdata(video_devdata(file)); + int retval; if (tuner->index > 0) return -EINVAL; @@ -1229,7 +1307,12 @@ static int si470x_vidioc_s_tuner(struct file *file, void *priv, else radio->registers[POWERCFG] &= ~POWERCFG_MONO; /* try stereo */ - return si470x_set_register(radio, POWERCFG); + retval = si470x_set_register(radio, POWERCFG); + if (retval < 0) + printk(KERN_WARNING DRIVER_NAME + ": set tuner failed with %d\n", retval); + + return retval; } @@ -1255,11 +1338,17 @@ static int si470x_vidioc_s_frequency(struct file *file, void *priv, struct v4l2_frequency *freq) { struct si470x_device *radio = video_get_drvdata(video_devdata(file)); + int retval; if (freq->type != V4L2_TUNER_RADIO) return -EINVAL; - return si470x_set_freq(radio, freq->frequency); + retval = si470x_set_freq(radio, freq->frequency); + if (retval < 0) + printk(KERN_WARNING DRIVER_NAME + ": set frequency failed with %d\n", retval); + + return 0; } @@ -1299,71 +1388,116 @@ static int si470x_usb_driver_probe(struct usb_interface *intf, const struct usb_device_id *id) { struct si470x_device *radio; + int retval = -ENOMEM; - /* memory and interface allocations */ - radio = kmalloc(sizeof(struct si470x_device), GFP_KERNEL); + /* private data allocation */ + radio = kzalloc(sizeof(struct si470x_device), GFP_KERNEL); if (!radio) - return -ENOMEM; + goto err_initial; + + /* video device allocation */ radio->videodev = video_device_alloc(); - if (!radio->videodev) { - kfree(radio); - return -ENOMEM; - } + if (!radio->videodev) + goto err_radio; + + /* initial configuration */ memcpy(radio->videodev, &si470x_viddev_template, sizeof(si470x_viddev_template)); radio->users = 0; radio->usbdev = interface_to_usbdev(intf); + radio->intf = intf; + mutex_init(&radio->lock); video_set_drvdata(radio->videodev, radio); - if (video_register_device(radio->videodev, VFL_TYPE_RADIO, radio_nr)) { - printk(KERN_WARNING DRIVER_NAME - ": Could not register video device\n"); - video_device_release(radio->videodev); - kfree(radio); - return -EIO; - } - usb_set_intfdata(intf, radio); /* show some infos about the specific device */ - if (si470x_get_all_registers(radio) < 0) { - video_device_release(radio->videodev); - kfree(radio); - return -EIO; - } - printk(KERN_INFO DRIVER_NAME ": DeviceID=0x%4.4x ChipID=0x%4.4x\n", + retval = -EIO; + if (si470x_get_all_registers(radio) < 0) + goto err_all; + printk(KERN_INFO DRIVER_NAME ": DeviceID=0x%4.4hx ChipID=0x%4.4hx\n", radio->registers[DEVICEID], radio->registers[CHIPID]); /* check if firmware is current */ if ((radio->registers[CHIPID] & CHIPID_FIRMWARE) - < RADIO_SW_VERSION_CURRENT) + < RADIO_SW_VERSION_CURRENT) { + printk(KERN_WARNING DRIVER_NAME + ": This driver is known to work with " + "firmware version %hu,\n", RADIO_SW_VERSION_CURRENT); + printk(KERN_WARNING DRIVER_NAME + ": but the device has firmware version %hu.\n", + radio->registers[CHIPID] & CHIPID_FIRMWARE); + printk(KERN_WARNING DRIVER_NAME + ": If you have some trouble using this driver,\n"); printk(KERN_WARNING DRIVER_NAME - ": This driver is known to work with chip version %d, " - "but the device has firmware %d.\n" - DRIVER_NAME - "If you have some trouble using this driver, please " - "report to V4L ML at video4linux-list@redhat.com\n", - radio->registers[CHIPID] & CHIPID_FIRMWARE, - RADIO_SW_VERSION_CURRENT); + ": please report to V4L ML at " + "video4linux-list@redhat.com\n"); + } /* set initial frequency */ si470x_set_freq(radio, 87.5 * FREQ_MUL); /* available in all regions */ - /* rds initialization */ + /* rds buffer allocation */ radio->buf_size = rds_buf * 3; radio->buffer = kmalloc(radio->buf_size, GFP_KERNEL); - if (!radio->buffer) { - video_device_release(radio->videodev); - kfree(radio); - return -ENOMEM; - } + if (!radio->buffer) + goto err_all; + + /* rds buffer configuration */ radio->wr_index = 0; radio->rd_index = 0; init_waitqueue_head(&radio->read_queue); - /* prepare polling via eventd */ - INIT_WORK(&radio->work, si470x_work); - init_timer(&radio->timer); - radio->timer.function = si470x_timer; - radio->timer.data = (unsigned long) radio; + /* prepare rds work function */ + INIT_DELAYED_WORK(&radio->work, si470x_work); + + /* register video device */ + if (video_register_device(radio->videodev, VFL_TYPE_RADIO, radio_nr)) { + printk(KERN_WARNING DRIVER_NAME + ": Could not register video device\n"); + goto err_all; + } + usb_set_intfdata(intf, radio); + + return 0; +err_all: + video_device_release(radio->videodev); + kfree(radio->buffer); +err_radio: + kfree(radio); +err_initial: + return retval; +} + + +/* + * si470x_usb_driver_suspend - suspend the device + */ +static int si470x_usb_driver_suspend(struct usb_interface *intf, + pm_message_t message) +{ + struct si470x_device *radio = usb_get_intfdata(intf); + + printk(KERN_INFO DRIVER_NAME ": suspending now...\n"); + + cancel_delayed_work_sync(&radio->work); + + return 0; +} + + +/* + * si470x_usb_driver_resume - resume the device + */ +static int si470x_usb_driver_resume(struct usb_interface *intf) +{ + struct si470x_device *radio = usb_get_intfdata(intf); + + printk(KERN_INFO DRIVER_NAME ": resuming now...\n"); + + mutex_lock(&radio->lock); + if (radio->users && radio->registers[SYSCONFIG1] & SYSCONFIG1_RDS) + schedule_delayed_work(&radio->work, + msecs_to_jiffies(rds_poll_time)); + mutex_unlock(&radio->lock); return 0; } @@ -1376,15 +1510,11 @@ static void si470x_usb_driver_disconnect(struct usb_interface *intf) { struct si470x_device *radio = usb_get_intfdata(intf); - del_timer_sync(&radio->timer); - flush_scheduled_work(); - + cancel_delayed_work_sync(&radio->work); usb_set_intfdata(intf, NULL); - if (radio) { - video_unregister_device(radio->videodev); - kfree(radio->buffer); - kfree(radio); - } + video_unregister_device(radio->videodev); + kfree(radio->buffer); + kfree(radio); } @@ -1392,10 +1522,13 @@ static void si470x_usb_driver_disconnect(struct usb_interface *intf) * si470x_usb_driver - usb driver interface */ static struct usb_driver si470x_usb_driver = { - .name = DRIVER_NAME, - .probe = si470x_usb_driver_probe, - .disconnect = si470x_usb_driver_disconnect, - .id_table = si470x_usb_driver_id_table, + .name = DRIVER_NAME, + .probe = si470x_usb_driver_probe, + .disconnect = si470x_usb_driver_disconnect, + .suspend = si470x_usb_driver_suspend, + .resume = si470x_usb_driver_resume, + .id_table = si470x_usb_driver_id_table, + .supports_autosuspend = 1, }; @@ -1409,7 +1542,7 @@ static struct usb_driver si470x_usb_driver = { */ static int __init si470x_module_init(void) { - printk(KERN_INFO DRIVER_DESC "\n"); + printk(KERN_INFO DRIVER_DESC ", Version " DRIVER_VERSION "\n"); return usb_register(&si470x_usb_driver); } @@ -1429,4 +1562,4 @@ module_exit(si470x_module_exit); MODULE_LICENSE("GPL"); MODULE_AUTHOR(DRIVER_AUTHOR); MODULE_DESCRIPTION(DRIVER_DESC); -MODULE_VERSION("1.0.4"); +MODULE_VERSION(DRIVER_VERSION); diff --git a/drivers/media/video/Kconfig b/drivers/media/video/Kconfig index a2e8987a619..37072a21d8c 100644 --- a/drivers/media/video/Kconfig +++ b/drivers/media/video/Kconfig @@ -4,14 +4,14 @@ menuconfig VIDEO_CAPTURE_DRIVERS bool "Video capture adapters" - depends on VIDEO_DEV + depends on VIDEO_V4L2 default y ---help--- Say Y here to enable selecting the video adapters for webcams, analog TV, and hybrid analog/digital TV. Some of those devices also supports FM radio. -if VIDEO_CAPTURE_DRIVERS && VIDEO_DEV +if VIDEO_CAPTURE_DRIVERS && VIDEO_V4L2 config VIDEO_ADV_DEBUG bool "Enable advanced debug functionality" diff --git a/drivers/media/video/Makefile b/drivers/media/video/Makefile index 850b8c6f457..3f209b32eea 100644 --- a/drivers/media/video/Makefile +++ b/drivers/media/video/Makefile @@ -10,8 +10,9 @@ msp3400-objs := msp3400-driver.o msp3400-kthreads.o stkwebcam-objs := stk-webcam.o stk-sensor.o -obj-$(CONFIG_VIDEO_DEV) += videodev.o v4l2-common.o compat_ioctl32.o \ - v4l2-int-device.o +obj-$(CONFIG_VIDEO_DEV) += videodev.o compat_ioctl32.o v4l2-int-device.o + +obj-$(CONFIG_VIDEO_V4L2_COMMON) += v4l2-common.o ifeq ($(CONFIG_VIDEO_V4L1_COMPAT),y) obj-$(CONFIG_VIDEO_DEV) += v4l1-compat.o diff --git a/drivers/media/video/bt8xx/bttv-driver.c b/drivers/media/video/bt8xx/bttv-driver.c index 907dc62c178..5404fcc5276 100644 --- a/drivers/media/video/bt8xx/bttv-driver.c +++ b/drivers/media/video/bt8xx/bttv-driver.c @@ -2354,8 +2354,8 @@ static int setup_window(struct bttv_fh *fh, struct bttv *btv, BUG(); } - mutex_lock(&fh->cap.lock); - kfree(fh->ov.clips); + mutex_lock(&fh->cap.vb_lock); + kfree(fh->ov.clips); fh->ov.clips = clips; fh->ov.nclips = n; @@ -2376,7 +2376,7 @@ static int setup_window(struct bttv_fh *fh, struct bttv *btv, bttv_overlay_risc(btv, &fh->ov, fh->ovfmt, new); retval = bttv_switch_overlay(btv,fh,new); } - mutex_unlock(&fh->cap.lock); + mutex_unlock(&fh->cap.vb_lock); return retval; } @@ -2576,7 +2576,7 @@ static int bttv_s_fmt_cap(struct file *file, void *priv, fmt = format_by_fourcc(f->fmt.pix.pixelformat); /* update our state informations */ - mutex_lock(&fh->cap.lock); + mutex_lock(&fh->cap.vb_lock); fh->fmt = fmt; fh->cap.field = f->fmt.pix.field; fh->cap.last = V4L2_FIELD_NONE; @@ -2585,7 +2585,7 @@ static int bttv_s_fmt_cap(struct file *file, void *priv, btv->init.fmt = fmt; btv->init.width = f->fmt.pix.width; btv->init.height = f->fmt.pix.height; - mutex_unlock(&fh->cap.lock); + mutex_unlock(&fh->cap.vb_lock); return 0; } @@ -2611,11 +2611,11 @@ static int vidiocgmbuf(struct file *file, void *priv, struct video_mbuf *mbuf) unsigned int i; struct bttv_fh *fh = priv; - mutex_lock(&fh->cap.lock); + mutex_lock(&fh->cap.vb_lock); retval = videobuf_mmap_setup(&fh->cap, gbuffers, gbufsize, V4L2_MEMORY_MMAP); if (retval < 0) { - mutex_unlock(&fh->cap.lock); + mutex_unlock(&fh->cap.vb_lock); return retval; } @@ -2627,7 +2627,7 @@ static int vidiocgmbuf(struct file *file, void *priv, struct video_mbuf *mbuf) for (i = 0; i < gbuffers; i++) mbuf->offsets[i] = i * gbufsize; - mutex_unlock(&fh->cap.lock); + mutex_unlock(&fh->cap.vb_lock); return 0; } #endif @@ -2756,10 +2756,11 @@ static int bttv_overlay(struct file *file, void *f, unsigned int on) if (!check_alloc_btres(btv, fh, RESOURCE_OVERLAY)) return -EBUSY; - mutex_lock(&fh->cap.lock); + mutex_lock(&fh->cap.vb_lock); if (on) { fh->ov.tvnorm = btv->tvnorm; new = videobuf_pci_alloc(sizeof(*new)); + new->crop = btv->crop[!!fh->do_crop].rect; bttv_overlay_risc(btv, &fh->ov, fh->ovfmt, new); } else { new = NULL; @@ -2767,7 +2768,7 @@ static int bttv_overlay(struct file *file, void *f, unsigned int on) /* switch over */ retval = bttv_switch_overlay(btv, fh, new); - mutex_unlock(&fh->cap.lock); + mutex_unlock(&fh->cap.vb_lock); return retval; } @@ -2806,7 +2807,7 @@ static int bttv_s_fbuf(struct file *file, void *f, } /* ok, accept it */ - mutex_lock(&fh->cap.lock); + mutex_lock(&fh->cap.vb_lock); btv->fbuf.base = fb->base; btv->fbuf.fmt.width = fb->fmt.width; btv->fbuf.fmt.height = fb->fmt.height; @@ -2838,7 +2839,7 @@ static int bttv_s_fbuf(struct file *file, void *f, retval = bttv_switch_overlay(btv, fh, new); } } - mutex_unlock(&fh->cap.lock); + mutex_unlock(&fh->cap.vb_lock); return retval; } @@ -3090,7 +3091,7 @@ static int bttv_s_crop(struct file *file, void *f, struct v4l2_crop *crop) fh->do_crop = 1; - mutex_lock(&fh->cap.lock); + mutex_lock(&fh->cap.vb_lock); if (fh->width < c.min_scaled_width) { fh->width = c.min_scaled_width; @@ -3108,7 +3109,7 @@ static int bttv_s_crop(struct file *file, void *f, struct v4l2_crop *crop) btv->init.height = c.max_scaled_height; } - mutex_unlock(&fh->cap.lock); + mutex_unlock(&fh->cap.vb_lock); return 0; } @@ -3177,30 +3178,25 @@ static unsigned int bttv_poll(struct file *file, poll_table *wait) buf = list_entry(fh->cap.stream.next,struct bttv_buffer,vb.stream); } else { /* read() capture */ - mutex_lock(&fh->cap.lock); + mutex_lock(&fh->cap.vb_lock); if (NULL == fh->cap.read_buf) { /* need to capture a new frame */ - if (locked_btres(fh->btv,RESOURCE_VIDEO_STREAM)) { - mutex_unlock(&fh->cap.lock); - return POLLERR; - } + if (locked_btres(fh->btv,RESOURCE_VIDEO_STREAM)) + goto err; fh->cap.read_buf = videobuf_pci_alloc(fh->cap.msize); - if (NULL == fh->cap.read_buf) { - mutex_unlock(&fh->cap.lock); - return POLLERR; - } + if (NULL == fh->cap.read_buf) + goto err; fh->cap.read_buf->memory = V4L2_MEMORY_USERPTR; field = videobuf_next_field(&fh->cap); if (0 != fh->cap.ops->buf_prepare(&fh->cap,fh->cap.read_buf,field)) { kfree (fh->cap.read_buf); fh->cap.read_buf = NULL; - mutex_unlock(&fh->cap.lock); - return POLLERR; + goto err; } fh->cap.ops->buf_queue(&fh->cap,fh->cap.read_buf); fh->cap.read_off = 0; } - mutex_unlock(&fh->cap.lock); + mutex_unlock(&fh->cap.vb_lock); buf = (struct bttv_buffer*)fh->cap.read_buf; } @@ -3209,6 +3205,9 @@ static unsigned int bttv_poll(struct file *file, poll_table *wait) buf->vb.state == VIDEOBUF_ERROR) return POLLIN|POLLRDNORM; return 0; +err: + mutex_unlock(&fh->cap.vb_lock); + return POLLERR; } static int bttv_open(struct inode *inode, struct file *file) diff --git a/drivers/media/video/bt8xx/bttv-vbi.c b/drivers/media/video/bt8xx/bttv-vbi.c index 1f0cc79e2a3..75fa82c7c73 100644 --- a/drivers/media/video/bt8xx/bttv-vbi.c +++ b/drivers/media/video/bt8xx/bttv-vbi.c @@ -352,13 +352,13 @@ int bttv_s_fmt_vbi(struct file *file, void *f, struct v4l2_format *frt) because vbi_fmt.end counts field lines times two. */ end = max(frt->fmt.vbi.start[0], start1) * 2 + 2; - mutex_lock(&fh->vbi.lock); + mutex_lock(&fh->vbi.vb_lock); fh->vbi_fmt.fmt = frt->fmt.vbi; fh->vbi_fmt.tvnorm = tvnorm; fh->vbi_fmt.end = end; - mutex_unlock(&fh->vbi.lock); + mutex_unlock(&fh->vbi.vb_lock); rc = 0; diff --git a/drivers/media/video/cx88/cx88-mpeg.c b/drivers/media/video/cx88/cx88-mpeg.c index 0aedbeaf94c..e357f415db0 100644 --- a/drivers/media/video/cx88/cx88-mpeg.c +++ b/drivers/media/video/cx88/cx88-mpeg.c @@ -609,13 +609,19 @@ static int cx8802_request_acquire(struct cx8802_driver *drv) struct cx88_core *core = drv->core; /* Fail a request for hardware if the device is busy. */ - if (core->active_type_id != CX88_BOARD_NONE) + if (core->active_type_id != CX88_BOARD_NONE && + core->active_type_id != drv->type_id) return -EBUSY; if (drv->advise_acquire) { - core->active_type_id = drv->type_id; - drv->advise_acquire(drv); + mutex_lock(&drv->core->lock); + core->active_ref++; + if (core->active_type_id == CX88_BOARD_NONE) { + core->active_type_id = drv->type_id; + drv->advise_acquire(drv); + } + mutex_unlock(&drv->core->lock); mpeg_dbg(1,"%s() Post acquire GPIO=%x\n", __FUNCTION__, cx_read(MO_GP0_IO)); } @@ -628,12 +634,14 @@ static int cx8802_request_release(struct cx8802_driver *drv) { struct cx88_core *core = drv->core; - if (drv->advise_release) + mutex_lock(&drv->core->lock); + if (drv->advise_release && --core->active_ref == 0) { drv->advise_release(drv); core->active_type_id = CX88_BOARD_NONE; mpeg_dbg(1,"%s() Post release GPIO=%x\n", __FUNCTION__, cx_read(MO_GP0_IO)); } + mutex_unlock(&drv->core->lock); return 0; } diff --git a/drivers/media/video/cx88/cx88.h b/drivers/media/video/cx88/cx88.h index 4e823f2a539..37e6d2e4002 100644 --- a/drivers/media/video/cx88/cx88.h +++ b/drivers/media/video/cx88/cx88.h @@ -336,6 +336,7 @@ struct cx88_core { /* cx88-video needs to access cx8802 for hybrid tuner pll access. */ struct cx8802_dev *dvbdev; enum cx88_board_type active_type_id; + int active_ref; }; struct cx8800_dev; diff --git a/drivers/media/video/em28xx/em28xx-audio.c b/drivers/media/video/em28xx/em28xx-audio.c index 941357c4f3f..8c67f678266 100644 --- a/drivers/media/video/em28xx/em28xx-audio.c +++ b/drivers/media/video/em28xx/em28xx-audio.c @@ -35,7 +35,6 @@ #include <linux/vmalloc.h> #include <linux/proc_fs.h> #include <linux/module.h> -#include <sound/driver.h> #include <sound/core.h> #include <sound/pcm.h> #include <sound/pcm_params.h> @@ -270,8 +269,11 @@ static int snd_em28xx_capture_open(struct snd_pcm_substream *substream) dprintk("opening device and trying to acquire exclusive lock\n"); /* Sets volume, mute, etc */ + dev->mute = 0; + mutex_lock(&dev->lock); ret = em28xx_audio_analog_set(dev); + mutex_unlock(&dev->lock); if (ret < 0) goto err; @@ -303,7 +305,9 @@ static int snd_em28xx_pcm_close(struct snd_pcm_substream *substream) dprintk("closing device\n"); dev->mute = 1; + mutex_lock(&dev->lock); em28xx_audio_analog_set(dev); + mutex_unlock(&dev->lock); if (dev->adev->users == 0 && dev->adev->shutdown == 1) { dprintk("audio users: %d\n", dev->adev->users); diff --git a/drivers/media/video/em28xx/em28xx-cards.c b/drivers/media/video/em28xx/em28xx-cards.c index 2159d0160df..aae7753fef1 100644 --- a/drivers/media/video/em28xx/em28xx-cards.c +++ b/drivers/media/video/em28xx/em28xx-cards.c @@ -393,15 +393,15 @@ struct em28xx_board em28xx_boards[] = { .input = { { .type = EM28XX_VMUX_TELEVISION, .vmux = SAA7115_COMPOSITE2, - .amux = 1, + .amux = EM28XX_AMUX_LINE_IN, }, { .type = EM28XX_VMUX_COMPOSITE1, .vmux = SAA7115_COMPOSITE0, - .amux = 1, + .amux = EM28XX_AMUX_LINE_IN, }, { .type = EM28XX_VMUX_SVIDEO, .vmux = SAA7115_SVIDEO3, - .amux = 1, + .amux = EM28XX_AMUX_LINE_IN, } }, }, }; @@ -441,6 +441,8 @@ struct usb_device_id em28xx_id_table [] = { .driver_info = EM2820_BOARD_PINNACLE_DVC_90 }, { USB_DEVICE(0x2040, 0x6500), .driver_info = EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900 }, + { USB_DEVICE(0x2040, 0x6502), + .driver_info = EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900 }, { USB_DEVICE(0x2040, 0x6513), .driver_info = EM2880_BOARD_HAUPPAUGE_WINTV_HVR_950 }, { USB_DEVICE(0x0ccd, 0x0042), diff --git a/drivers/media/video/em28xx/em28xx-core.c b/drivers/media/video/em28xx/em28xx-core.c index f6b78357f0e..7d1537cab86 100644 --- a/drivers/media/video/em28xx/em28xx-core.c +++ b/drivers/media/video/em28xx/em28xx-core.c @@ -72,7 +72,8 @@ u32 em28xx_request_buffers(struct em28xx *dev, u32 count) const size_t imagesize = PAGE_ALIGN(dev->frame_size); /*needs to be page aligned cause the buffers can be mapped individually! */ void *buff = NULL; u32 i; - em28xx_coredbg("requested %i buffers with size %zi", count, imagesize); + em28xx_coredbg("requested %i buffers with size %zi\n", + count, imagesize); if (count > EM28XX_NUM_FRAMES) count = EM28XX_NUM_FRAMES; @@ -150,7 +151,7 @@ int em28xx_read_reg_req_len(struct em28xx *dev, u8 req, u16 reg, if (reg_debug){ printk(ret < 0 ? " failed!\n" : "%02x values: ", ret); for (byte = 0; byte < len; byte++) { - printk(" %02x", buf[byte]); + printk(" %02x", (unsigned char)buf[byte]); } printk("\n"); } @@ -177,7 +178,8 @@ int em28xx_read_reg_req(struct em28xx *dev, u8 req, u16 reg) 0x0000, reg, &val, 1, HZ); if (reg_debug) - printk(ret < 0 ? " failed!\n" : "%02x\n", val); + printk(ret < 0 ? " failed!\n" : + "%02x\n", (unsigned char) val); if (ret < 0) return ret; @@ -237,7 +239,7 @@ int em28xx_write_regs(struct em28xx *dev, u16 reg, char *buf, int len) * sets only some bits (specified by bitmask) of a register, by first reading * the actual value */ -int em28xx_write_reg_bits(struct em28xx *dev, u16 reg, u8 val, +static int em28xx_write_reg_bits(struct em28xx *dev, u16 reg, u8 val, u8 bitmask) { int oldval; @@ -254,26 +256,31 @@ int em28xx_write_reg_bits(struct em28xx *dev, u16 reg, u8 val, */ static int em28xx_write_ac97(struct em28xx *dev, u8 reg, u8 *val) { - int ret; + int ret, i; u8 addr = reg & 0x7f; if ((ret = em28xx_write_regs(dev, AC97LSB_REG, val, 2)) < 0) return ret; if ((ret = em28xx_write_regs(dev, AC97ADDR_REG, &addr, 1)) < 0) return ret; - if ((ret = em28xx_read_reg(dev, AC97BUSY_REG)) < 0) - return ret; - else if (((u8) ret) & 0x01) { - em28xx_warn ("AC97 command still being executed: not handled properly!\n"); + + /* Wait up to 50 ms for AC97 command to complete */ + for (i = 0; i < 10; i++) { + if ((ret = em28xx_read_reg(dev, AC97BUSY_REG)) < 0) + return ret; + if (!((u8) ret) & 0x01) + return 0; + msleep(5); } + em28xx_warn ("AC97 command still being executed: not handled properly!\n"); return 0; } -int em28xx_set_audio_source(struct em28xx *dev) +static int em28xx_set_audio_source(struct em28xx *dev) { static char *enable = "\x08\x08"; static char *disable = "\x08\x88"; char *video = enable, *line = disable; - int ret, no_ac97; + int ret; u8 input; if (dev->is_em2800) { @@ -293,11 +300,9 @@ int em28xx_set_audio_source(struct em28xx *dev) switch (dev->ctl_ainput) { case EM28XX_AMUX_VIDEO: input = EM28XX_AUDIO_SRC_TUNER; - no_ac97 = 1; break; case EM28XX_AMUX_LINE_IN: input = EM28XX_AUDIO_SRC_LINE; - no_ac97 = 1; break; case EM28XX_AMUX_AC97_VIDEO: input = EM28XX_AUDIO_SRC_LINE; @@ -313,12 +318,11 @@ int em28xx_set_audio_source(struct em28xx *dev) ret = em28xx_write_reg_bits(dev, AUDIOSRC_REG, input, 0xc0); if (ret < 0) return ret; + msleep(5); - if (no_ac97) - return 0; - - /* Sets AC97 mixer registers */ - + /* Sets AC97 mixer registers + This is seems to be needed, even for non-ac97 configs + */ ret = em28xx_write_ac97(dev, VIDEO_AC97, video); if (ret < 0) return ret; @@ -337,9 +341,10 @@ int em28xx_audio_analog_set(struct em28xx *dev) s[0] |= 0x1f - dev->volume; s[1] |= 0x1f - dev->volume; - if (dev->mute) - s[1] |= 0x80; + /* Mute */ + s[1] |= 0x80; ret = em28xx_write_ac97(dev, MASTER_AC97, s); + if (ret < 0) return ret; @@ -357,6 +362,11 @@ int em28xx_audio_analog_set(struct em28xx *dev) /* Selects the proper audio input */ ret = em28xx_set_audio_source(dev); + /* Unmute device */ + if (!dev->mute) + s[1] &= ~0x80; + ret = em28xx_write_ac97(dev, MASTER_AC97, s); + return ret; } EXPORT_SYMBOL_GPL(em28xx_audio_analog_set); @@ -667,7 +677,7 @@ static void em28xx_isocIrq(struct urb *urb) continue; } if (urb->iso_frame_desc[i].actual_length > - dev->max_pkt_size) { + urb->iso_frame_desc[i].length) { em28xx_isocdbg("packet bigger than packet size"); continue; } @@ -713,8 +723,11 @@ void em28xx_uninit_isoc(struct em28xx *dev) for (i = 0; i < EM28XX_NUM_BUFS; i++) { if (dev->urb[i]) { usb_kill_urb(dev->urb[i]); - if (dev->transfer_buffer[i]){ - usb_buffer_free(dev->udev,(EM28XX_NUM_PACKETS*dev->max_pkt_size),dev->transfer_buffer[i],dev->urb[i]->transfer_dma); + if (dev->transfer_buffer[i]) { + usb_buffer_free(dev->udev, + dev->urb[i]->transfer_buffer_length, + dev->transfer_buffer[i], + dev->urb[i]->transfer_dma); } usb_free_urb(dev->urb[i]); } @@ -732,7 +745,10 @@ int em28xx_init_isoc(struct em28xx *dev) { /* change interface to 3 which allows the biggest packet sizes */ int i, errCode; - const int sb_size = EM28XX_NUM_PACKETS * dev->max_pkt_size; + int sb_size; + + em28xx_set_alternate(dev); + sb_size = EM28XX_NUM_PACKETS * dev->max_pkt_size; /* reset streaming vars */ dev->frame_current = NULL; @@ -741,7 +757,7 @@ int em28xx_init_isoc(struct em28xx *dev) /* allocate urbs */ for (i = 0; i < EM28XX_NUM_BUFS; i++) { struct urb *urb; - int j, k; + int j; /* allocate transfer buffer */ urb = usb_alloc_urb(EM28XX_NUM_PACKETS, GFP_KERNEL); if (!urb){ @@ -749,7 +765,9 @@ int em28xx_init_isoc(struct em28xx *dev) em28xx_uninit_isoc(dev); return -ENOMEM; } - dev->transfer_buffer[i] = usb_buffer_alloc(dev->udev, sb_size, GFP_KERNEL,&urb->transfer_dma); + dev->transfer_buffer[i] = usb_buffer_alloc(dev->udev, sb_size, + GFP_KERNEL, + &urb->transfer_dma); if (!dev->transfer_buffer[i]) { em28xx_errdev ("unable to allocate %i bytes for transfer buffer %i\n", @@ -762,22 +780,22 @@ int em28xx_init_isoc(struct em28xx *dev) urb->dev = dev->udev; urb->context = dev; urb->pipe = usb_rcvisocpipe(dev->udev, 0x82); - urb->transfer_flags = URB_ISO_ASAP; + urb->transfer_flags = URB_ISO_ASAP | URB_NO_TRANSFER_DMA_MAP; urb->interval = 1; urb->transfer_buffer = dev->transfer_buffer[i]; urb->complete = em28xx_isocIrq; urb->number_of_packets = EM28XX_NUM_PACKETS; urb->transfer_buffer_length = sb_size; - for (j = k = 0; j < EM28XX_NUM_PACKETS; - j++, k += dev->max_pkt_size) { - urb->iso_frame_desc[j].offset = k; - urb->iso_frame_desc[j].length = - dev->max_pkt_size; + for (j = 0; j < EM28XX_NUM_PACKETS; j++) { + urb->iso_frame_desc[j].offset = j * dev->max_pkt_size; + urb->iso_frame_desc[j].length = dev->max_pkt_size; } dev->urb[i] = urb; } /* submit urbs */ + em28xx_coredbg("Submitting %d urbs of %d packets (%d each)\n", + EM28XX_NUM_BUFS, EM28XX_NUM_PACKETS, dev->max_pkt_size); for (i = 0; i < EM28XX_NUM_BUFS; i++) { errCode = usb_submit_urb(dev->urb[i], GFP_KERNEL); if (errCode) { @@ -794,22 +812,31 @@ int em28xx_init_isoc(struct em28xx *dev) int em28xx_set_alternate(struct em28xx *dev) { int errCode, prev_alt = dev->alt; - dev->alt = alt; - if (dev->alt == 0) { - int i; - for(i=0;i< dev->num_alt; i++) - if(dev->alt_max_pkt_size[i]>dev->alt_max_pkt_size[dev->alt]) - dev->alt=i; - } + int i; + unsigned int min_pkt_size = dev->bytesperline+4; + + /* When image size is bigger than a ceirtain value, + the frame size should be increased, otherwise, only + green screen will be received. + */ + if (dev->frame_size > 720*240*2) + min_pkt_size *= 2; + + for (i = 0; i < dev->num_alt; i++) + if (dev->alt_max_pkt_size[i] >= min_pkt_size) + break; + dev->alt = i; if (dev->alt != prev_alt) { + em28xx_coredbg("minimum isoc packet size: %u (alt=%d)\n", + min_pkt_size, dev->alt); dev->max_pkt_size = dev->alt_max_pkt_size[dev->alt]; - em28xx_coredbg("setting alternate %d with wMaxPacketSize=%u\n", dev->alt, - dev->max_pkt_size); + em28xx_coredbg("setting alternate %d with wMaxPacketSize=%u\n", + dev->alt, dev->max_pkt_size); errCode = usb_set_interface(dev->udev, 0, dev->alt); if (errCode < 0) { em28xx_errdev ("cannot change alternate number to %d (error=%i)\n", - dev->alt, errCode); + dev->alt, errCode); return errCode; } } diff --git a/drivers/media/video/em28xx/em28xx-video.c b/drivers/media/video/em28xx/em28xx-video.c index a0c33467248..4abe6701a77 100644 --- a/drivers/media/video/em28xx/em28xx-video.c +++ b/drivers/media/video/em28xx/em28xx-video.c @@ -189,7 +189,7 @@ static void video_mux(struct em28xx *dev, int index) em28xx_i2c_call_clients(dev, VIDIOC_INT_S_AUDIO_ROUTING, &route); } - em28xx_set_audio_source(dev); + em28xx_audio_analog_set(dev); } /* Usage lock check functions */ @@ -830,6 +830,63 @@ static int vidioc_s_frequency(struct file *file, void *priv, return 0; } +#ifdef CONFIG_VIDEO_ADV_DEBUG +static int em28xx_reg_len(int reg) +{ + switch (reg) { + case AC97LSB_REG: + case HSCALELOW_REG: + case VSCALELOW_REG: + return 2; + default: + return 1; + } +} + +static int vidioc_g_register(struct file *file, void *priv, + struct v4l2_register *reg) +{ + struct em28xx_fh *fh = priv; + struct em28xx *dev = fh->dev; + int ret; + + if (!v4l2_chip_match_host(reg->match_type, reg->match_chip)) + return -EINVAL; + + if (em28xx_reg_len(reg->reg) == 1) { + ret = em28xx_read_reg(dev, reg->reg); + if (ret < 0) + return ret; + + reg->val = ret; + } else { + u64 val = 0; + ret = em28xx_read_reg_req_len(dev, USB_REQ_GET_STATUS, + reg->reg, (char *)&val, 2); + if (ret < 0) + return ret; + + reg->val = cpu_to_le64((__u64)val); + } + + return 0; +} + +static int vidioc_s_register(struct file *file, void *priv, + struct v4l2_register *reg) +{ + struct em28xx_fh *fh = priv; + struct em28xx *dev = fh->dev; + u64 buf; + + buf = le64_to_cpu((__u64)reg->val); + + return em28xx_write_regs(dev, reg->reg, (char *)&buf, + em28xx_reg_len(reg->reg)); +} +#endif + + static int vidioc_cropcap(struct file *file, void *priv, struct v4l2_cropcap *cc) { @@ -1295,8 +1352,6 @@ static int em28xx_v4l2_open(struct inode *inode, struct file *filp) filp->private_data = fh; if (dev->type == V4L2_BUF_TYPE_VIDEO_CAPTURE && dev->users == 0) { - em28xx_set_alternate(dev); - dev->width = norm_maxw(dev); dev->height = norm_maxh(dev); dev->frame_size = dev->width * dev->height * 2; @@ -1305,6 +1360,7 @@ static int em28xx_v4l2_open(struct inode *inode, struct file *filp) dev->hscale = 0; dev->vscale = 0; + em28xx_set_alternate(dev); em28xx_capture_start(dev, 1); em28xx_resolution_set(dev); @@ -1730,6 +1786,10 @@ static const struct video_device em28xx_video_template = { .vidioc_s_tuner = vidioc_s_tuner, .vidioc_g_frequency = vidioc_g_frequency, .vidioc_s_frequency = vidioc_s_frequency, +#ifdef CONFIG_VIDEO_ADV_DEBUG + .vidioc_g_register = vidioc_g_register, + .vidioc_s_register = vidioc_s_register, +#endif .tvnorms = V4L2_STD_ALL, .current_norm = V4L2_STD_PAL, @@ -1752,6 +1812,10 @@ static struct video_device em28xx_radio_template = { .vidioc_s_ctrl = vidioc_s_ctrl, .vidioc_g_frequency = vidioc_g_frequency, .vidioc_s_frequency = vidioc_s_frequency, +#ifdef CONFIG_VIDEO_ADV_DEBUG + .vidioc_g_register = vidioc_g_register, + .vidioc_s_register = vidioc_s_register, +#endif }; /******************************** usb interface *****************************************/ @@ -1796,10 +1860,10 @@ void em28xx_unregister_extension(struct em28xx_ops *ops) } EXPORT_SYMBOL(em28xx_unregister_extension); -struct video_device *em28xx_vdev_init(struct em28xx *dev, - const struct video_device *template, - const int type, - const char *type_name) +static struct video_device *em28xx_vdev_init(struct em28xx *dev, + const struct video_device *template, + const int type, + const char *type_name) { struct video_device *vfd; @@ -2064,6 +2128,7 @@ static int em28xx_usb_probe(struct usb_interface *interface, snprintf(dev->name, 29, "em28xx #%d", nr); dev->devno = nr; dev->model = id->driver_info; + dev->alt = -1; /* Checks if audio is provided by some interface */ for (i = 0; i < udev->config->desc.bNumInterfaces; i++) { diff --git a/drivers/media/video/em28xx/em28xx.h b/drivers/media/video/em28xx/em28xx.h index f3bad0c1c51..04e0e48ecab 100644 --- a/drivers/media/video/em28xx/em28xx.h +++ b/drivers/media/video/em28xx/em28xx.h @@ -33,7 +33,7 @@ #define UNSET -1 /* maximum number of em28xx boards */ -#define EM28XX_MAXBOARDS 1 /*FIXME: should be bigger */ +#define EM28XX_MAXBOARDS 4 /*FIXME: should be bigger */ /* maximum number of frames that can be queued */ #define EM28XX_NUM_FRAMES 5 @@ -345,9 +345,6 @@ int em28xx_read_reg(struct em28xx *dev, u16 reg); int em28xx_write_regs_req(struct em28xx *dev, u8 req, u16 reg, char *buf, int len); int em28xx_write_regs(struct em28xx *dev, u16 reg, char *buf, int len); -int em28xx_write_reg_bits(struct em28xx *dev, u16 reg, u8 val, - u8 bitmask); -int em28xx_set_audio_source(struct em28xx *dev); int em28xx_audio_analog_set(struct em28xx *dev); int em28xx_colorlevels_set_default(struct em28xx *dev); diff --git a/drivers/media/video/saa7134/saa7134-cards.c b/drivers/media/video/saa7134/saa7134-cards.c index 7d7f383b404..262830da08c 100644 --- a/drivers/media/video/saa7134/saa7134-cards.c +++ b/drivers/media/video/saa7134/saa7134-cards.c @@ -928,27 +928,38 @@ struct saa7134_board saa7134_boards[] = { .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, .tda9887_conf = TDA9887_PRESENT, + .gpiomask = 0x03, .inputs = {{ .name = name_tv, .vmux = 1, .amux = TV, .tv = 1, - },{ + .gpio = 0x00, + }, { .name = name_comp1, - .vmux = 0, - .amux = LINE2, - },{ - .name = name_comp2, .vmux = 3, - .amux = LINE2, - },{ + .amux = LINE1, + .gpio = 0x02, + }, { + .name = name_comp2, + .vmux = 0, + .amux = LINE1, + .gpio = 0x02, + }, { .name = name_svideo, .vmux = 8, - .amux = LINE2, - }}, + .amux = LINE1, + .gpio = 0x02, + } }, .radio = { .name = name_radio, - .amux = LINE2, + .amux = LINE1, + .gpio = 0x01, + }, + .mute = { + .name = name_mute, + .amux = TV, + .gpio = 0x00, }, }, [SAA7134_BOARD_BMK_MPEX_TUNER] = { @@ -3912,6 +3923,74 @@ struct saa7134_board saa7134_boards[] = { }, .mpeg = SAA7134_MPEG_EMPRESS, }, + [SAA7134_BOARD_TWINHAN_DTV_DVB_3056] = { + .name = "Twinhan Hybrid DTV-DVB 3056 PCI", + .audio_clock = 0x00187de7, + .tuner_type = TUNER_PHILIPS_TDA8290, + .radio_type = UNSET, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, + .tuner_config = 2, + .mpeg = SAA7134_MPEG_DVB, + .gpiomask = 0x0200000, + .inputs = {{ + .name = name_tv, + .vmux = 1, + .amux = TV, + .tv = 1, + }, { + .name = name_comp1, + .vmux = 3, + .amux = LINE1, + }, { + .name = name_svideo, + .vmux = 8, /* untested */ + .amux = LINE1, + } }, + .radio = { + .name = name_radio, + .amux = TV, + .gpio = 0x0200000, + }, + }, + [SAA7134_BOARD_GENIUS_TVGO_A11MCE] = { + /* Adrian Pardini <pardo.bsso@gmail.com> */ + .name = "Genius TVGO AM11MCE", + .audio_clock = 0x00200000, + .tuner_type = TUNER_TNF_5335MF, + .radio_type = UNSET, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, + .gpiomask = 0xf000, + .inputs = {{ + .name = name_tv_mono, + .vmux = 1, + .amux = LINE2, + .gpio = 0x0000, + .tv = 1, + }, { + .name = name_comp1, + .vmux = 3, + .amux = LINE1, + .gpio = 0x2000, + .tv = 1 + }, { + .name = name_svideo, + .vmux = 8, + .amux = LINE1, + .gpio = 0x2000, + } }, + .radio = { + .name = name_radio, + .amux = LINE2, + .gpio = 0x1000, + }, + .mute = { + .name = name_mute, + .amux = LINE2, + .gpio = 0x6000, + }, + }, }; const unsigned int saa7134_bcount = ARRAY_SIZE(saa7134_boards); @@ -4511,6 +4590,12 @@ struct pci_device_id saa7134_pci_tbl[] = { },{ .vendor = PCI_VENDOR_ID_PHILIPS, .device = PCI_DEVICE_ID_PHILIPS_SAA7133, + .subvendor = 0x5168, + .subdevice = 0x3307, /* FlyDVB-T Hybrid Mini PCI */ + .driver_data = SAA7134_BOARD_FLYDVBT_HYBRID_CARDBUS, + }, { + .vendor = PCI_VENDOR_ID_PHILIPS, + .device = PCI_DEVICE_ID_PHILIPS_SAA7133, .subvendor = 0x16be, .subdevice = 0x0007, .driver_data = SAA7134_BOARD_MEDION_MD8800_QUADRO, @@ -4523,6 +4608,12 @@ struct pci_device_id saa7134_pci_tbl[] = { },{ .vendor = PCI_VENDOR_ID_PHILIPS, .device = PCI_DEVICE_ID_PHILIPS_SAA7133, + .subvendor = 0x16be, + .subdevice = 0x000d, /* triple CTX948_V1.1.1 */ + .driver_data = SAA7134_BOARD_MEDION_MD8800_QUADRO, + }, { + .vendor = PCI_VENDOR_ID_PHILIPS, + .device = PCI_DEVICE_ID_PHILIPS_SAA7133, .subvendor = 0x1461, .subdevice = 0x2c05, .driver_data = SAA7134_BOARD_AVERMEDIA_777, @@ -4843,7 +4934,13 @@ struct pci_device_id saa7134_pci_tbl[] = { .device = PCI_DEVICE_ID_PHILIPS_SAA7133, .subvendor = 0x4e42, .subdevice = 0x3502, - .driver_data = SAA7134_BOARD_FLYDVBT_HYBRID_CARDBUS + .driver_data = SAA7134_BOARD_FLYDVBT_HYBRID_CARDBUS, + }, { + .vendor = PCI_VENDOR_ID_PHILIPS, + .device = PCI_DEVICE_ID_PHILIPS_SAA7133, + .subvendor = 0x1822, /*Twinhan Technology Co. Ltd*/ + .subdevice = 0x0022, + .driver_data = SAA7134_BOARD_TWINHAN_DTV_DVB_3056, },{ /* --- boards without eeprom + subsystem ID --- */ .vendor = PCI_VENDOR_ID_PHILIPS, @@ -4995,6 +5092,7 @@ int saa7134_board_init1(struct saa7134_dev *dev) case SAA7134_BOARD_BEHOLD_409: case SAA7134_BOARD_BEHOLD_505FM: case SAA7134_BOARD_BEHOLD_507_9FM: + case SAA7134_BOARD_GENIUS_TVGO_A11MCE: dev->has_remote = SAA7134_REMOTE_GPIO; break; case SAA7134_BOARD_FLYDVBS_LR300: @@ -5232,7 +5330,8 @@ int saa7134_board_init2(struct saa7134_dev *dev) case SAA7134_BOARD_ASUSTeK_P7131_DUAL: case SAA7134_BOARD_ASUSTeK_P7131_HYBRID_LNA: case SAA7134_BOARD_MEDION_MD8800_QUADRO: - case SAA7134_BOARD_AVERMEDIA_SUPER_007: + case SAA7134_BOARD_AVERMEDIA_SUPER_007: + case SAA7134_BOARD_TWINHAN_DTV_DVB_3056: /* this is a hybrid board, initialize to analog mode * and configure firmware eeprom address */ diff --git a/drivers/media/video/saa7134/saa7134-dvb.c b/drivers/media/video/saa7134/saa7134-dvb.c index a9ca5730826..ea2be9eceeb 100644 --- a/drivers/media/video/saa7134/saa7134-dvb.c +++ b/drivers/media/video/saa7134/saa7134-dvb.c @@ -779,6 +779,21 @@ static struct tda1004x_config avermedia_super_007_config = { .request_firmware = philips_tda1004x_request_firmware }; +static struct tda1004x_config twinhan_dtv_dvb_3056_config = { + .demod_address = 0x08, + .invert = 1, + .invert_oclk = 0, + .xtal_freq = TDA10046_XTAL_16M, + .agc_config = TDA10046_AGC_TDA827X, + .gpio_config = TDA10046_GP01_I, + .if_freq = TDA10046_FREQ_045, + .i2c_gate = 0x42, + .tuner_address = 0x61, + .tuner_config = 2, + .antenna_switch = 1, + .request_firmware = philips_tda1004x_request_firmware +}; + /* ------------------------------------------------------------------ * special case: this card uses saa713x GPIO22 for the mode switch */ @@ -826,6 +841,7 @@ static struct tda1004x_config ads_tech_duo_config = { static struct tda10086_config flydvbs = { .demod_address = 0x0e, .invert = 0, + .diseqc_tone = 0, }; /* ================================================================== @@ -940,9 +956,9 @@ static int dvb_init(struct saa7134_dev *dev) configure_tda827x_fe(dev, &tda827x_lifeview_config); break; case SAA7134_BOARD_FLYDVB_TRIO: - if(! use_frontend) { //terrestrial + if(! use_frontend) { /* terrestrial */ configure_tda827x_fe(dev, &lifeview_trio_config); - } else { //satellite + } else { /* satellite */ dev->dvb.frontend = dvb_attach(tda10086_attach, &flydvbs, &dev->i2c_adap); if (dev->dvb.frontend) { if (dvb_attach(tda826x_attach, dev->dvb.frontend, 0x63, @@ -1007,8 +1023,9 @@ static int dvb_init(struct saa7134_dev *dev) } break; case SAA7134_BOARD_ASUS_EUROPA2_HYBRID: - dev->dvb.frontend = tda10046_attach(&medion_cardbus, - &dev->i2c_adap); + dev->dvb.frontend = dvb_attach(tda10046_attach, + &medion_cardbus, + &dev->i2c_adap); if (dev->dvb.frontend) { dev->original_demod_sleep = dev->dvb.frontend->ops.sleep; dev->dvb.frontend->ops.sleep = philips_europa_demod_sleep; @@ -1044,6 +1061,9 @@ static int dvb_init(struct saa7134_dev *dev) case SAA7134_BOARD_AVERMEDIA_SUPER_007: configure_tda827x_fe(dev, &avermedia_super_007_config); break; + case SAA7134_BOARD_TWINHAN_DTV_DVB_3056: + configure_tda827x_fe(dev, &twinhan_dtv_dvb_3056_config); + break; default: wprintk("Huh? unknown DVB card?\n"); break; diff --git a/drivers/media/video/saa7134/saa7134-empress.c b/drivers/media/video/saa7134/saa7134-empress.c index b1b01fa8672..3d2ec30de22 100644 --- a/drivers/media/video/saa7134/saa7134-empress.c +++ b/drivers/media/video/saa7134/saa7134-empress.c @@ -87,7 +87,7 @@ static int ts_open(struct inode *inode, struct file *file) dprintk("open minor=%d\n",minor); err = -EBUSY; - if (!mutex_trylock(&dev->empress_tsq.lock)) + if (!mutex_trylock(&dev->empress_tsq.vb_lock)) goto done; if (dev->empress_users) goto done_up; @@ -101,7 +101,7 @@ static int ts_open(struct inode *inode, struct file *file) err = 0; done_up: - mutex_unlock(&dev->empress_tsq.lock); + mutex_unlock(&dev->empress_tsq.vb_lock); done: return err; } @@ -110,7 +110,6 @@ static int ts_release(struct inode *inode, struct file *file) { struct saa7134_dev *dev = file->private_data; - mutex_lock(&dev->empress_tsq.lock); videobuf_stop(&dev->empress_tsq); videobuf_mmap_free(&dev->empress_tsq); dev->empress_users--; @@ -122,7 +121,6 @@ static int ts_release(struct inode *inode, struct file *file) saa_writeb(SAA7134_AUDIO_MUTE_CTRL, saa_readb(SAA7134_AUDIO_MUTE_CTRL) | (1 << 6)); - mutex_unlock(&dev->empress_tsq.lock); return 0; } diff --git a/drivers/media/video/saa7134/saa7134-input.c b/drivers/media/video/saa7134/saa7134-input.c index 0db955c2d9b..b4188819782 100644 --- a/drivers/media/video/saa7134/saa7134-input.c +++ b/drivers/media/video/saa7134/saa7134-input.c @@ -406,6 +406,12 @@ int saa7134_input_init1(struct saa7134_dev *dev) mask_keyup = 0x8000000; polling = 50; //ms break; + case SAA7134_BOARD_GENIUS_TVGO_A11MCE: + ir_codes = ir_codes_genius_tvgo_a11mce; + mask_keycode = 0xff; + mask_keydown = 0xf00000; + polling = 50; /* ms */ + break; } if (NULL == ir_codes) { printk("%s: Oops: IR config error [card=%d]\n", diff --git a/drivers/media/video/saa7134/saa7134-video.c b/drivers/media/video/saa7134/saa7134-video.c index 1184d359e84..39c41ad97d0 100644 --- a/drivers/media/video/saa7134/saa7134-video.c +++ b/drivers/media/video/saa7134/saa7134-video.c @@ -1414,21 +1414,17 @@ video_poll(struct file *file, struct poll_table_struct *wait) if (!list_empty(&fh->cap.stream)) buf = list_entry(fh->cap.stream.next, struct videobuf_buffer, stream); } else { - mutex_lock(&fh->cap.lock); + mutex_lock(&fh->cap.vb_lock); if (UNSET == fh->cap.read_off) { /* need to capture a new frame */ - if (res_locked(fh->dev,RESOURCE_VIDEO)) { - mutex_unlock(&fh->cap.lock); - return POLLERR; - } - if (0 != fh->cap.ops->buf_prepare(&fh->cap,fh->cap.read_buf,fh->cap.field)) { - mutex_unlock(&fh->cap.lock); - return POLLERR; - } + if (res_locked(fh->dev,RESOURCE_VIDEO)) + goto err; + if (0 != fh->cap.ops->buf_prepare(&fh->cap,fh->cap.read_buf,fh->cap.field)) + goto err; fh->cap.ops->buf_queue(&fh->cap,fh->cap.read_buf); fh->cap.read_off = 0; } - mutex_unlock(&fh->cap.lock); + mutex_unlock(&fh->cap.vb_lock); buf = fh->cap.read_buf; } @@ -1440,6 +1436,10 @@ video_poll(struct file *file, struct poll_table_struct *wait) buf->state == VIDEOBUF_ERROR) return POLLIN|POLLRDNORM; return 0; + +err: + mutex_unlock(&fh->cap.vb_lock); + return POLLERR; } static int video_release(struct inode *inode, struct file *file) diff --git a/drivers/media/video/saa7134/saa7134.h b/drivers/media/video/saa7134/saa7134.h index b88ca995faf..f940d025479 100644 --- a/drivers/media/video/saa7134/saa7134.h +++ b/drivers/media/video/saa7134/saa7134.h @@ -252,6 +252,8 @@ struct saa7134_format { #define SAA7134_BOARD_BEHOLD_COLUMBUS_TVFM 128 #define SAA7134_BOARD_BEHOLD_607_9FM 129 #define SAA7134_BOARD_BEHOLD_M6 130 +#define SAA7134_BOARD_TWINHAN_DTV_DVB_3056 131 +#define SAA7134_BOARD_GENIUS_TVGO_A11MCE 132 #define SAA7134_MAXBOARDS 8 #define SAA7134_INPUT_MAX 8 diff --git a/drivers/media/video/stk-sensor.c b/drivers/media/video/stk-sensor.c index 4a9a0b62efa..e546b014d7a 100644 --- a/drivers/media/video/stk-sensor.c +++ b/drivers/media/video/stk-sensor.c @@ -225,7 +225,7 @@ /* Returns 0 if OK */ -int stk_sensor_outb(struct stk_camera *dev, u8 reg, u8 val) +static int stk_sensor_outb(struct stk_camera *dev, u8 reg, u8 val) { int i = 0; int tmpval = 0; @@ -250,7 +250,7 @@ int stk_sensor_outb(struct stk_camera *dev, u8 reg, u8 val) return 0; } -int stk_sensor_inb(struct stk_camera *dev, u8 reg, u8 *val) +static int stk_sensor_inb(struct stk_camera *dev, u8 reg, u8 *val) { int i = 0; int tmpval = 0; @@ -380,7 +380,7 @@ int stk_sensor_init(struct stk_camera *dev) STK_ERROR("Strange error reading sensor ID\n"); return -ENODEV; } - if (idh != 0x7F || idl != 0xA2) { + if (idh != 0x7f || idl != 0xa2) { STK_ERROR("Huh? you don't have a sensor from ovt\n"); return -ENODEV; } @@ -409,6 +409,19 @@ static struct regval ov_fmt_uyvy[] = { {REG_COM15, COM15_R00FF }, {0xff, 0xff}, /* END MARKER */ }; +/* V4L2_PIX_FMT_YUYV */ +static struct regval ov_fmt_yuyv[] = { + {REG_TSLB, 0 }, + { 0x4f, 0x80 }, /* "matrix coefficient 1" */ + { 0x50, 0x80 }, /* "matrix coefficient 2" */ + { 0x51, 0 }, /* vb */ + { 0x52, 0x22 }, /* "matrix coefficient 4" */ + { 0x53, 0x5e }, /* "matrix coefficient 5" */ + { 0x54, 0x80 }, /* "matrix coefficient 6" */ + {REG_COM13, COM13_UVSAT|COM13_CMATRIX}, + {REG_COM15, COM15_R00FF }, + {0xff, 0xff}, /* END MARKER */ +}; /* V4L2_PIX_FMT_RGB565X rrrrrggg gggbbbbb */ static struct regval ov_fmt_rgbr[] = { @@ -519,6 +532,10 @@ int stk_sensor_configure(struct stk_camera *dev) com7 |= COM7_YUV; rv = ov_fmt_uyvy; break; + case V4L2_PIX_FMT_YUYV: + com7 |= COM7_YUV; + rv = ov_fmt_yuyv; + break; case V4L2_PIX_FMT_RGB565: com7 |= COM7_RGB; rv = ov_fmt_rgbp; diff --git a/drivers/media/video/stk-webcam.c b/drivers/media/video/stk-webcam.c index d37e5e2594b..ceba45ad029 100644 --- a/drivers/media/video/stk-webcam.c +++ b/drivers/media/video/stk-webcam.c @@ -63,7 +63,7 @@ static struct usb_device_id stkwebcam_table[] = { }; MODULE_DEVICE_TABLE(usb, stkwebcam_table); -void stk_camera_cleanup(struct kref *kref) +static void stk_camera_cleanup(struct kref *kref) { struct stk_camera *dev = to_stk_camera(kref); @@ -682,6 +682,7 @@ static int v4l_stk_open(struct inode *inode, struct file *fp) return -ENXIO; fp->private_data = vdev; kref_get(&dev->kref); + usb_autopm_get_interface(dev->interface); return 0; } @@ -703,6 +704,7 @@ static int v4l_stk_release(struct inode *inode, struct file *fp) } if (dev->owner != fp) { + usb_autopm_put_interface(dev->interface); kref_put(&dev->kref, stk_camera_cleanup); return 0; } @@ -713,6 +715,7 @@ static int v4l_stk_release(struct inode *inode, struct file *fp) dev->owner = NULL; + usb_autopm_put_interface(dev->interface); kref_put(&dev->kref, stk_camera_cleanup); return 0; @@ -993,6 +996,10 @@ static int stk_vidioc_enum_fmt_cap(struct file *filp, fmtd->pixelformat = V4L2_PIX_FMT_SBGGR8; strcpy(fmtd->description, "Raw bayer"); break; + case 4: + fmtd->pixelformat = V4L2_PIX_FMT_YUYV; + strcpy(fmtd->description, "yuv4:2:2"); + break; default: return -EINVAL; } @@ -1048,6 +1055,7 @@ static int stk_vidioc_try_fmt_cap(struct file *filp, case V4L2_PIX_FMT_RGB565: case V4L2_PIX_FMT_RGB565X: case V4L2_PIX_FMT_UYVY: + case V4L2_PIX_FMT_YUYV: case V4L2_PIX_FMT_SBGGR8: break; default: @@ -1080,6 +1088,42 @@ static int stk_vidioc_try_fmt_cap(struct file *filp, return 0; } +static int stk_setup_format(struct stk_camera *dev) +{ + int i = 0; + int depth; + if (dev->vsettings.palette == V4L2_PIX_FMT_SBGGR8) + depth = 1; + else + depth = 2; + while (stk_sizes[i].m != dev->vsettings.mode + && i < ARRAY_SIZE(stk_sizes)) + i++; + if (i == ARRAY_SIZE(stk_sizes)) { + STK_ERROR("Something is broken in %s\n", __FUNCTION__); + return -EFAULT; + } + /* This registers controls some timings, not sure of what. */ + stk_camera_write_reg(dev, 0x001b, 0x0e); + if (dev->vsettings.mode == MODE_SXGA) + stk_camera_write_reg(dev, 0x001c, 0x0e); + else + stk_camera_write_reg(dev, 0x001c, 0x46); + /* + * Registers 0x0115 0x0114 are the size of each line (bytes), + * regs 0x0117 0x0116 are the heigth of the image. + */ + stk_camera_write_reg(dev, 0x0115, + ((stk_sizes[i].w * depth) >> 8) & 0xff); + stk_camera_write_reg(dev, 0x0114, + (stk_sizes[i].w * depth) & 0xff); + stk_camera_write_reg(dev, 0x0117, + (stk_sizes[i].h >> 8) & 0xff); + stk_camera_write_reg(dev, 0x0116, + stk_sizes[i].h & 0xff); + return stk_sensor_configure(dev); +} + static int stk_vidioc_s_fmt_cap(struct file *filp, void *priv, struct v4l2_format *fmtd) { @@ -1094,10 +1138,10 @@ static int stk_vidioc_s_fmt_cap(struct file *filp, return -EBUSY; if (dev->owner && dev->owner != filp) return -EBUSY; - dev->owner = filp; ret = stk_vidioc_try_fmt_cap(filp, priv, fmtd); if (ret) return ret; + dev->owner = filp; dev->vsettings.palette = fmtd->fmt.pix.pixelformat; stk_free_buffers(dev); @@ -1105,25 +1149,7 @@ static int stk_vidioc_s_fmt_cap(struct file *filp, dev->vsettings.mode = stk_sizes[fmtd->fmt.pix.priv].m; stk_initialise(dev); - /* This registers controls some timings, not sure of what. */ - stk_camera_write_reg(dev, 0x001b, 0x0e); - if (dev->vsettings.mode == MODE_SXGA) - stk_camera_write_reg(dev, 0x001c, 0x0e); - else - stk_camera_write_reg(dev, 0x001c, 0x46); - /* - * Registers 0x0115 0x0114 are the size of each line (bytes), - * regs 0x0117 0x0116 are the heigth of the image. - */ - stk_camera_write_reg(dev, 0x0115, - (fmtd->fmt.pix.bytesperline >> 8) & 0xff); - stk_camera_write_reg(dev, 0x0114, - fmtd->fmt.pix.bytesperline & 0xff); - stk_camera_write_reg(dev, 0x0117, - (fmtd->fmt.pix.height >> 8) & 0xff); - stk_camera_write_reg(dev, 0x0116, - fmtd->fmt.pix.height & 0xff); - return stk_sensor_configure(dev); + return stk_setup_format(dev); } static int stk_vidioc_reqbufs(struct file *filp, @@ -1288,6 +1314,9 @@ static struct file_operations v4l_stk_fops = { .poll = v4l_stk_poll, .mmap = v4l_stk_mmap, .ioctl = video_ioctl2, +#ifdef CONFIG_COMPAT + .compat_ioctl = v4l_compat_ioctl32, +#endif .llseek = no_llseek }; @@ -1403,7 +1432,7 @@ static int stk_camera_probe(struct usb_interface *interface, dev->vsettings.brightness = 0x7fff; dev->vsettings.palette = V4L2_PIX_FMT_RGB565; dev->vsettings.mode = MODE_VGA; - dev->frame_size = 640*480*2; + dev->frame_size = 640 * 480 * 2; INIT_LIST_HEAD(&dev->sio_avail); INIT_LIST_HEAD(&dev->sio_full); @@ -1417,6 +1446,7 @@ static int stk_camera_probe(struct usb_interface *interface, } stk_create_sysfs_files(&dev->vdev); + usb_autopm_enable(dev->interface); return 0; } @@ -1434,11 +1464,41 @@ static void stk_camera_disconnect(struct usb_interface *interface) kref_put(&dev->kref, stk_camera_cleanup); } +#ifdef CONFIG_PM +int stk_camera_suspend(struct usb_interface *intf, pm_message_t message) +{ + struct stk_camera *dev = usb_get_intfdata(intf); + if (is_streaming(dev)) { + stk_stop_stream(dev); + /* yes, this is ugly */ + set_streaming(dev); + } + return 0; +} + +int stk_camera_resume(struct usb_interface *intf) +{ + struct stk_camera *dev = usb_get_intfdata(intf); + if (!is_initialised(dev)) + return 0; + unset_initialised(dev); + stk_initialise(dev); + stk_setup_format(dev); + if (is_streaming(dev)) + stk_start_stream(dev); + return 0; +} +#endif + static struct usb_driver stk_camera_driver = { .name = "stkwebcam", .probe = stk_camera_probe, .disconnect = stk_camera_disconnect, .id_table = stkwebcam_table, +#ifdef CONFIG_PM + .suspend = stk_camera_suspend, + .resume = stk_camera_resume, +#endif }; diff --git a/drivers/media/video/stk-webcam.h b/drivers/media/video/stk-webcam.h index 7e989d1ac1e..df4dfefc532 100644 --- a/drivers/media/video/stk-webcam.h +++ b/drivers/media/video/stk-webcam.h @@ -79,6 +79,7 @@ enum stk_status { #define unset_present(dev) ((dev)->status &= \ ~(S_PRESENT|S_INITIALISED|S_STREAMING)) #define set_initialised(dev) ((dev)->status |= S_INITIALISED) +#define unset_initialised(dev) ((dev)->status &= ~S_INITIALISED) #define set_memallocd(dev) ((dev)->status |= S_MEMALLOCD) #define unset_memallocd(dev) ((dev)->status &= ~S_MEMALLOCD) #define set_streaming(dev) ((dev)->status |= S_STREAMING) @@ -127,8 +128,6 @@ void stk_camera_delete(struct kref *); int stk_camera_write_reg(struct stk_camera *, u16, u8); int stk_camera_read_reg(struct stk_camera *, u16, int *); -int stk_sensor_outb(struct stk_camera *dev, u8 reg, u8 val); -int stk_sensor_inb(struct stk_camera *dev, u8 reg, u8 *val); int stk_sensor_init(struct stk_camera *); int stk_sensor_configure(struct stk_camera *); int stk_sensor_sleep(struct stk_camera *dev); diff --git a/drivers/media/video/tcm825x.c b/drivers/media/video/tcm825x.c index 41cd6a0b048..fb895f6684a 100644 --- a/drivers/media/video/tcm825x.c +++ b/drivers/media/video/tcm825x.c @@ -851,7 +851,7 @@ static int tcm825x_probe(struct i2c_client *client) sensor->platform_data = client->dev.platform_data; if (sensor->platform_data == NULL - && !sensor->platform_data->is_okay()) + || !sensor->platform_data->is_okay()) return -ENODEV; sensor->v4l2_int_device = &tcm825x_int_device; diff --git a/drivers/media/video/tuner-core.c b/drivers/media/video/tuner-core.c index ba538f6fbcc..78a09a2a485 100644 --- a/drivers/media/video/tuner-core.c +++ b/drivers/media/video/tuner-core.c @@ -1038,7 +1038,7 @@ static int tuner_resume(struct i2c_client *c) /* ---------------------------------------------------------------------- */ -LIST_HEAD(tuner_list); +static LIST_HEAD(tuner_list); /* Search for existing radio and/or TV tuners on the given I2C adapter. Note that when this function is called from tuner_probe you can be diff --git a/drivers/media/video/tuner-xc2028.c b/drivers/media/video/tuner-xc2028.c index f191f6a4807..50cf876f020 100644 --- a/drivers/media/video/tuner-xc2028.c +++ b/drivers/media/video/tuner-xc2028.c @@ -754,6 +754,9 @@ skip_std_specific: goto check_device; } + if (new_fw.type & FM) + goto check_device; + /* Load SCODE firmware, if exists */ tuner_dbg("Trying to load scode %d\n", new_fw.scode_nr); diff --git a/drivers/media/video/tvaudio.c b/drivers/media/video/tvaudio.c index a75560540e7..01ebcec040c 100644 --- a/drivers/media/video/tvaudio.c +++ b/drivers/media/video/tvaudio.c @@ -1571,14 +1571,14 @@ static int tvaudio_get_ctrl(struct CHIPSTATE *chip, ctrl->value=chip->muted; return 0; case V4L2_CID_AUDIO_VOLUME: - if (!desc->flags & CHIP_HAS_VOLUME) + if (!(desc->flags & CHIP_HAS_VOLUME)) break; ctrl->value = max(chip->left,chip->right); return 0; case V4L2_CID_AUDIO_BALANCE: { int volume; - if (!desc->flags & CHIP_HAS_VOLUME) + if (!(desc->flags & CHIP_HAS_VOLUME)) break; volume = max(chip->left,chip->right); if (volume) @@ -1621,7 +1621,7 @@ static int tvaudio_set_ctrl(struct CHIPSTATE *chip, { int volume,balance; - if (!desc->flags & CHIP_HAS_VOLUME) + if (!(desc->flags & CHIP_HAS_VOLUME)) break; volume = max(chip->left,chip->right); @@ -1642,7 +1642,7 @@ static int tvaudio_set_ctrl(struct CHIPSTATE *chip, case V4L2_CID_AUDIO_BALANCE: { int volume, balance; - if (!desc->flags & CHIP_HAS_VOLUME) + if (!(desc->flags & CHIP_HAS_VOLUME)) break; volume = max(chip->left,chip->right); @@ -1702,7 +1702,7 @@ static int chip_command(struct i2c_client *client, break; case V4L2_CID_AUDIO_VOLUME: case V4L2_CID_AUDIO_BALANCE: - if (!desc->flags & CHIP_HAS_VOLUME) + if (!(desc->flags & CHIP_HAS_VOLUME)) return -EINVAL; break; case V4L2_CID_AUDIO_BASS: diff --git a/drivers/media/video/tveeprom.c b/drivers/media/video/tveeprom.c index 0b8fbad3c72..dc0da44a5af 100644 --- a/drivers/media/video/tveeprom.c +++ b/drivers/media/video/tveeprom.c @@ -242,7 +242,7 @@ hauppauge_tuner[] = { TUNER_ABSENT, "TCL M2523_3DBH_E"}, { TUNER_ABSENT, "TCL M2523_3DIH_E"}, { TUNER_ABSENT, "TCL MFPE05_2_U"}, - { TUNER_ABSENT, "Philips FMD1216MEX"}, + { TUNER_PHILIPS_FMD1216ME_MK3, "Philips FMD1216MEX"}, { TUNER_ABSENT, "Philips FRH2036B"}, { TUNER_ABSENT, "Panasonic ENGF75_01GF"}, { TUNER_ABSENT, "MaxLinear MXL5005"}, diff --git a/drivers/media/video/v4l2-common.c b/drivers/media/video/v4l2-common.c index c056ff6d810..34deb68ae56 100644 --- a/drivers/media/video/v4l2-common.c +++ b/drivers/media/video/v4l2-common.c @@ -56,7 +56,6 @@ #include <asm/pgtable.h> #include <asm/io.h> #include <asm/div64.h> -#include <linux/video_decoder.h> #define __OLD_VIDIOC_ /* To allow fixing old calls*/ #include <media/v4l2-common.h> #include <media/v4l2-chip-ident.h> @@ -82,108 +81,6 @@ MODULE_LICENSE("GPL"); */ -char *v4l2_norm_to_name(v4l2_std_id id) -{ - char *name; - u32 myid = id; - - /* HACK: ppc32 architecture doesn't have __ucmpdi2 function to handle - 64 bit comparations. So, on that architecture, with some gcc variants, - compilation fails. Currently, the max value is 30bit wide. - */ - BUG_ON(myid != id); - - switch (myid) { - case V4L2_STD_PAL: - name="PAL"; break; - case V4L2_STD_PAL_BG: - name="PAL-BG"; break; - case V4L2_STD_PAL_DK: - name="PAL-DK"; break; - case V4L2_STD_PAL_B: - name="PAL-B"; break; - case V4L2_STD_PAL_B1: - name="PAL-B1"; break; - case V4L2_STD_PAL_G: - name="PAL-G"; break; - case V4L2_STD_PAL_H: - name="PAL-H"; break; - case V4L2_STD_PAL_I: - name="PAL-I"; break; - case V4L2_STD_PAL_D: - name="PAL-D"; break; - case V4L2_STD_PAL_D1: - name="PAL-D1"; break; - case V4L2_STD_PAL_K: - name="PAL-K"; break; - case V4L2_STD_PAL_M: - name="PAL-M"; break; - case V4L2_STD_PAL_N: - name="PAL-N"; break; - case V4L2_STD_PAL_Nc: - name="PAL-Nc"; break; - case V4L2_STD_PAL_60: - name="PAL-60"; break; - case V4L2_STD_NTSC: - name="NTSC"; break; - case V4L2_STD_NTSC_M: - name="NTSC-M"; break; - case V4L2_STD_NTSC_M_JP: - name="NTSC-M-JP"; break; - case V4L2_STD_NTSC_443: - name="NTSC-443"; break; - case V4L2_STD_NTSC_M_KR: - name="NTSC-M-KR"; break; - case V4L2_STD_SECAM: - name="SECAM"; break; - case V4L2_STD_SECAM_DK: - name="SECAM-DK"; break; - case V4L2_STD_SECAM_B: - name="SECAM-B"; break; - case V4L2_STD_SECAM_D: - name="SECAM-D"; break; - case V4L2_STD_SECAM_G: - name="SECAM-G"; break; - case V4L2_STD_SECAM_H: - name="SECAM-H"; break; - case V4L2_STD_SECAM_K: - name="SECAM-K"; break; - case V4L2_STD_SECAM_K1: - name="SECAM-K1"; break; - case V4L2_STD_SECAM_L: - name="SECAM-L"; break; - case V4L2_STD_SECAM_LC: - name="SECAM-LC"; break; - default: - name="Unknown"; break; - } - - return name; -} - -/* Fill in the fields of a v4l2_standard structure according to the - 'id' and 'transmission' parameters. Returns negative on error. */ -int v4l2_video_std_construct(struct v4l2_standard *vs, - int id, char *name) -{ - u32 index = vs->index; - - memset(vs, 0, sizeof(struct v4l2_standard)); - vs->index = index; - vs->id = id; - if (id & V4L2_STD_525_60) { - vs->frameperiod.numerator = 1001; - vs->frameperiod.denominator = 30000; - vs->framelines = 525; - } else { - vs->frameperiod.numerator = 1; - vs->frameperiod.denominator = 25; - vs->framelines = 625; - } - strlcpy(vs->name,name,sizeof(vs->name)); - return 0; -} - /* ----------------------------------------------------------------- */ /* priority handling */ @@ -196,6 +93,7 @@ int v4l2_prio_init(struct v4l2_prio_state *global) memset(global,0,sizeof(*global)); return 0; } +EXPORT_SYMBOL(v4l2_prio_init); int v4l2_prio_change(struct v4l2_prio_state *global, enum v4l2_priority *local, enum v4l2_priority new) @@ -211,11 +109,13 @@ int v4l2_prio_change(struct v4l2_prio_state *global, enum v4l2_priority *local, *local = new; return 0; } +EXPORT_SYMBOL(v4l2_prio_change); int v4l2_prio_open(struct v4l2_prio_state *global, enum v4l2_priority *local) { return v4l2_prio_change(global,local,V4L2_PRIORITY_DEFAULT); } +EXPORT_SYMBOL(v4l2_prio_open); int v4l2_prio_close(struct v4l2_prio_state *global, enum v4l2_priority *local) { @@ -223,6 +123,7 @@ int v4l2_prio_close(struct v4l2_prio_state *global, enum v4l2_priority *local) atomic_dec(&global->prios[*local]); return 0; } +EXPORT_SYMBOL(v4l2_prio_close); enum v4l2_priority v4l2_prio_max(struct v4l2_prio_state *global) { @@ -234,6 +135,7 @@ enum v4l2_priority v4l2_prio_max(struct v4l2_prio_state *global) return V4L2_PRIORITY_BACKGROUND; return V4L2_PRIORITY_UNSET; } +EXPORT_SYMBOL(v4l2_prio_max); int v4l2_prio_check(struct v4l2_prio_state *global, enum v4l2_priority *local) { @@ -241,225 +143,7 @@ int v4l2_prio_check(struct v4l2_prio_state *global, enum v4l2_priority *local) return -EBUSY; return 0; } - - -/* ----------------------------------------------------------------- */ -/* some arrays for pretty-printing debug messages of enum types */ - -char *v4l2_field_names[] = { - [V4L2_FIELD_ANY] = "any", - [V4L2_FIELD_NONE] = "none", - [V4L2_FIELD_TOP] = "top", - [V4L2_FIELD_BOTTOM] = "bottom", - [V4L2_FIELD_INTERLACED] = "interlaced", - [V4L2_FIELD_SEQ_TB] = "seq-tb", - [V4L2_FIELD_SEQ_BT] = "seq-bt", - [V4L2_FIELD_ALTERNATE] = "alternate", - [V4L2_FIELD_INTERLACED_TB] = "interlaced-tb", - [V4L2_FIELD_INTERLACED_BT] = "interlaced-bt", -}; - -char *v4l2_type_names[] = { - [V4L2_BUF_TYPE_VIDEO_CAPTURE] = "video-cap", - [V4L2_BUF_TYPE_VIDEO_OVERLAY] = "video-over", - [V4L2_BUF_TYPE_VIDEO_OUTPUT] = "video-out", - [V4L2_BUF_TYPE_VBI_CAPTURE] = "vbi-cap", - [V4L2_BUF_TYPE_VBI_OUTPUT] = "vbi-out", - [V4L2_BUF_TYPE_SLICED_VBI_CAPTURE] = "sliced-vbi-cap", - [V4L2_BUF_TYPE_SLICED_VBI_OUTPUT] = "sliced-vbi-out", - [V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY] = "video-out-over", -}; - - -#define prt_names(a,arr) (((a)>=0)&&((a)<ARRAY_SIZE(arr)))?arr[a]:"unknown" - -/* ------------------------------------------------------------------ */ -/* debug help functions */ - -#ifdef CONFIG_VIDEO_V4L1_COMPAT -static const char *v4l1_ioctls[] = { - [_IOC_NR(VIDIOCGCAP)] = "VIDIOCGCAP", - [_IOC_NR(VIDIOCGCHAN)] = "VIDIOCGCHAN", - [_IOC_NR(VIDIOCSCHAN)] = "VIDIOCSCHAN", - [_IOC_NR(VIDIOCGTUNER)] = "VIDIOCGTUNER", - [_IOC_NR(VIDIOCSTUNER)] = "VIDIOCSTUNER", - [_IOC_NR(VIDIOCGPICT)] = "VIDIOCGPICT", - [_IOC_NR(VIDIOCSPICT)] = "VIDIOCSPICT", - [_IOC_NR(VIDIOCCAPTURE)] = "VIDIOCCAPTURE", - [_IOC_NR(VIDIOCGWIN)] = "VIDIOCGWIN", - [_IOC_NR(VIDIOCSWIN)] = "VIDIOCSWIN", - [_IOC_NR(VIDIOCGFBUF)] = "VIDIOCGFBUF", - [_IOC_NR(VIDIOCSFBUF)] = "VIDIOCSFBUF", - [_IOC_NR(VIDIOCKEY)] = "VIDIOCKEY", - [_IOC_NR(VIDIOCGFREQ)] = "VIDIOCGFREQ", - [_IOC_NR(VIDIOCSFREQ)] = "VIDIOCSFREQ", - [_IOC_NR(VIDIOCGAUDIO)] = "VIDIOCGAUDIO", - [_IOC_NR(VIDIOCSAUDIO)] = "VIDIOCSAUDIO", - [_IOC_NR(VIDIOCSYNC)] = "VIDIOCSYNC", - [_IOC_NR(VIDIOCMCAPTURE)] = "VIDIOCMCAPTURE", - [_IOC_NR(VIDIOCGMBUF)] = "VIDIOCGMBUF", - [_IOC_NR(VIDIOCGUNIT)] = "VIDIOCGUNIT", - [_IOC_NR(VIDIOCGCAPTURE)] = "VIDIOCGCAPTURE", - [_IOC_NR(VIDIOCSCAPTURE)] = "VIDIOCSCAPTURE", - [_IOC_NR(VIDIOCSPLAYMODE)] = "VIDIOCSPLAYMODE", - [_IOC_NR(VIDIOCSWRITEMODE)] = "VIDIOCSWRITEMODE", - [_IOC_NR(VIDIOCGPLAYINFO)] = "VIDIOCGPLAYINFO", - [_IOC_NR(VIDIOCSMICROCODE)] = "VIDIOCSMICROCODE", - [_IOC_NR(VIDIOCGVBIFMT)] = "VIDIOCGVBIFMT", - [_IOC_NR(VIDIOCSVBIFMT)] = "VIDIOCSVBIFMT" -}; -#define V4L1_IOCTLS ARRAY_SIZE(v4l1_ioctls) -#endif - -static const char *v4l2_ioctls[] = { - [_IOC_NR(VIDIOC_QUERYCAP)] = "VIDIOC_QUERYCAP", - [_IOC_NR(VIDIOC_RESERVED)] = "VIDIOC_RESERVED", - [_IOC_NR(VIDIOC_ENUM_FMT)] = "VIDIOC_ENUM_FMT", - [_IOC_NR(VIDIOC_G_FMT)] = "VIDIOC_G_FMT", - [_IOC_NR(VIDIOC_S_FMT)] = "VIDIOC_S_FMT", - [_IOC_NR(VIDIOC_REQBUFS)] = "VIDIOC_REQBUFS", - [_IOC_NR(VIDIOC_QUERYBUF)] = "VIDIOC_QUERYBUF", - [_IOC_NR(VIDIOC_G_FBUF)] = "VIDIOC_G_FBUF", - [_IOC_NR(VIDIOC_S_FBUF)] = "VIDIOC_S_FBUF", - [_IOC_NR(VIDIOC_OVERLAY)] = "VIDIOC_OVERLAY", - [_IOC_NR(VIDIOC_QBUF)] = "VIDIOC_QBUF", - [_IOC_NR(VIDIOC_DQBUF)] = "VIDIOC_DQBUF", - [_IOC_NR(VIDIOC_STREAMON)] = "VIDIOC_STREAMON", - [_IOC_NR(VIDIOC_STREAMOFF)] = "VIDIOC_STREAMOFF", - [_IOC_NR(VIDIOC_G_PARM)] = "VIDIOC_G_PARM", - [_IOC_NR(VIDIOC_S_PARM)] = "VIDIOC_S_PARM", - [_IOC_NR(VIDIOC_G_STD)] = "VIDIOC_G_STD", - [_IOC_NR(VIDIOC_S_STD)] = "VIDIOC_S_STD", - [_IOC_NR(VIDIOC_ENUMSTD)] = "VIDIOC_ENUMSTD", - [_IOC_NR(VIDIOC_ENUMINPUT)] = "VIDIOC_ENUMINPUT", - [_IOC_NR(VIDIOC_G_CTRL)] = "VIDIOC_G_CTRL", - [_IOC_NR(VIDIOC_S_CTRL)] = "VIDIOC_S_CTRL", - [_IOC_NR(VIDIOC_G_TUNER)] = "VIDIOC_G_TUNER", - [_IOC_NR(VIDIOC_S_TUNER)] = "VIDIOC_S_TUNER", - [_IOC_NR(VIDIOC_G_AUDIO)] = "VIDIOC_G_AUDIO", - [_IOC_NR(VIDIOC_S_AUDIO)] = "VIDIOC_S_AUDIO", - [_IOC_NR(VIDIOC_QUERYCTRL)] = "VIDIOC_QUERYCTRL", - [_IOC_NR(VIDIOC_QUERYMENU)] = "VIDIOC_QUERYMENU", - [_IOC_NR(VIDIOC_G_INPUT)] = "VIDIOC_G_INPUT", - [_IOC_NR(VIDIOC_S_INPUT)] = "VIDIOC_S_INPUT", - [_IOC_NR(VIDIOC_G_OUTPUT)] = "VIDIOC_G_OUTPUT", - [_IOC_NR(VIDIOC_S_OUTPUT)] = "VIDIOC_S_OUTPUT", - [_IOC_NR(VIDIOC_ENUMOUTPUT)] = "VIDIOC_ENUMOUTPUT", - [_IOC_NR(VIDIOC_G_AUDOUT)] = "VIDIOC_G_AUDOUT", - [_IOC_NR(VIDIOC_S_AUDOUT)] = "VIDIOC_S_AUDOUT", - [_IOC_NR(VIDIOC_G_MODULATOR)] = "VIDIOC_G_MODULATOR", - [_IOC_NR(VIDIOC_S_MODULATOR)] = "VIDIOC_S_MODULATOR", - [_IOC_NR(VIDIOC_G_FREQUENCY)] = "VIDIOC_G_FREQUENCY", - [_IOC_NR(VIDIOC_S_FREQUENCY)] = "VIDIOC_S_FREQUENCY", - [_IOC_NR(VIDIOC_CROPCAP)] = "VIDIOC_CROPCAP", - [_IOC_NR(VIDIOC_G_CROP)] = "VIDIOC_G_CROP", - [_IOC_NR(VIDIOC_S_CROP)] = "VIDIOC_S_CROP", - [_IOC_NR(VIDIOC_G_JPEGCOMP)] = "VIDIOC_G_JPEGCOMP", - [_IOC_NR(VIDIOC_S_JPEGCOMP)] = "VIDIOC_S_JPEGCOMP", - [_IOC_NR(VIDIOC_QUERYSTD)] = "VIDIOC_QUERYSTD", - [_IOC_NR(VIDIOC_TRY_FMT)] = "VIDIOC_TRY_FMT", - [_IOC_NR(VIDIOC_ENUMAUDIO)] = "VIDIOC_ENUMAUDIO", - [_IOC_NR(VIDIOC_ENUMAUDOUT)] = "VIDIOC_ENUMAUDOUT", - [_IOC_NR(VIDIOC_G_PRIORITY)] = "VIDIOC_G_PRIORITY", - [_IOC_NR(VIDIOC_S_PRIORITY)] = "VIDIOC_S_PRIORITY", - [_IOC_NR(VIDIOC_G_SLICED_VBI_CAP)] = "VIDIOC_G_SLICED_VBI_CAP", - [_IOC_NR(VIDIOC_LOG_STATUS)] = "VIDIOC_LOG_STATUS", - [_IOC_NR(VIDIOC_G_EXT_CTRLS)] = "VIDIOC_G_EXT_CTRLS", - [_IOC_NR(VIDIOC_S_EXT_CTRLS)] = "VIDIOC_S_EXT_CTRLS", - [_IOC_NR(VIDIOC_TRY_EXT_CTRLS)] = "VIDIOC_TRY_EXT_CTRLS", -#if 1 - [_IOC_NR(VIDIOC_ENUM_FRAMESIZES)] = "VIDIOC_ENUM_FRAMESIZES", - [_IOC_NR(VIDIOC_ENUM_FRAMEINTERVALS)] = "VIDIOC_ENUM_FRAMEINTERVALS", - [_IOC_NR(VIDIOC_G_ENC_INDEX)] = "VIDIOC_G_ENC_INDEX", - [_IOC_NR(VIDIOC_ENCODER_CMD)] = "VIDIOC_ENCODER_CMD", - [_IOC_NR(VIDIOC_TRY_ENCODER_CMD)] = "VIDIOC_TRY_ENCODER_CMD", - - [_IOC_NR(VIDIOC_DBG_S_REGISTER)] = "VIDIOC_DBG_S_REGISTER", - [_IOC_NR(VIDIOC_DBG_G_REGISTER)] = "VIDIOC_DBG_G_REGISTER", - - [_IOC_NR(VIDIOC_G_CHIP_IDENT)] = "VIDIOC_G_CHIP_IDENT", -#endif -}; -#define V4L2_IOCTLS ARRAY_SIZE(v4l2_ioctls) - -static const char *v4l2_int_ioctls[] = { -#ifdef CONFIG_VIDEO_V4L1_COMPAT - [_IOC_NR(DECODER_GET_CAPABILITIES)] = "DECODER_GET_CAPABILITIES", - [_IOC_NR(DECODER_GET_STATUS)] = "DECODER_GET_STATUS", - [_IOC_NR(DECODER_SET_NORM)] = "DECODER_SET_NORM", - [_IOC_NR(DECODER_SET_INPUT)] = "DECODER_SET_INPUT", - [_IOC_NR(DECODER_SET_OUTPUT)] = "DECODER_SET_OUTPUT", - [_IOC_NR(DECODER_ENABLE_OUTPUT)] = "DECODER_ENABLE_OUTPUT", - [_IOC_NR(DECODER_SET_PICTURE)] = "DECODER_SET_PICTURE", - [_IOC_NR(DECODER_SET_GPIO)] = "DECODER_SET_GPIO", - [_IOC_NR(DECODER_INIT)] = "DECODER_INIT", - [_IOC_NR(DECODER_SET_VBI_BYPASS)] = "DECODER_SET_VBI_BYPASS", - [_IOC_NR(DECODER_DUMP)] = "DECODER_DUMP", -#endif - [_IOC_NR(AUDC_SET_RADIO)] = "AUDC_SET_RADIO", - - [_IOC_NR(TUNER_SET_TYPE_ADDR)] = "TUNER_SET_TYPE_ADDR", - [_IOC_NR(TUNER_SET_STANDBY)] = "TUNER_SET_STANDBY", - [_IOC_NR(TUNER_SET_CONFIG)] = "TUNER_SET_CONFIG", - - [_IOC_NR(VIDIOC_INT_S_TUNER_MODE)] = "VIDIOC_INT_S_TUNER_MODE", - [_IOC_NR(VIDIOC_INT_RESET)] = "VIDIOC_INT_RESET", - [_IOC_NR(VIDIOC_INT_AUDIO_CLOCK_FREQ)] = "VIDIOC_INT_AUDIO_CLOCK_FREQ", - [_IOC_NR(VIDIOC_INT_DECODE_VBI_LINE)] = "VIDIOC_INT_DECODE_VBI_LINE", - [_IOC_NR(VIDIOC_INT_S_VBI_DATA)] = "VIDIOC_INT_S_VBI_DATA", - [_IOC_NR(VIDIOC_INT_G_VBI_DATA)] = "VIDIOC_INT_G_VBI_DATA", - [_IOC_NR(VIDIOC_INT_I2S_CLOCK_FREQ)] = "VIDIOC_INT_I2S_CLOCK_FREQ", - [_IOC_NR(VIDIOC_INT_S_STANDBY)] = "VIDIOC_INT_S_STANDBY", - [_IOC_NR(VIDIOC_INT_S_AUDIO_ROUTING)] = "VIDIOC_INT_S_AUDIO_ROUTING", - [_IOC_NR(VIDIOC_INT_G_AUDIO_ROUTING)] = "VIDIOC_INT_G_AUDIO_ROUTING", - [_IOC_NR(VIDIOC_INT_S_VIDEO_ROUTING)] = "VIDIOC_INT_S_VIDEO_ROUTING", - [_IOC_NR(VIDIOC_INT_G_VIDEO_ROUTING)] = "VIDIOC_INT_G_VIDEO_ROUTING", - [_IOC_NR(VIDIOC_INT_S_CRYSTAL_FREQ)] = "VIDIOC_INT_S_CRYSTAL_FREQ", - [_IOC_NR(VIDIOC_INT_INIT)] = "VIDIOC_INT_INIT", - [_IOC_NR(VIDIOC_INT_G_STD_OUTPUT)] = "VIDIOC_INT_G_STD_OUTPUT", - [_IOC_NR(VIDIOC_INT_S_STD_OUTPUT)] = "VIDIOC_INT_S_STD_OUTPUT", -}; -#define V4L2_INT_IOCTLS ARRAY_SIZE(v4l2_int_ioctls) - - -/* Common ioctl debug function. This function can be used by - external ioctl messages as well as internal V4L ioctl */ -void v4l_printk_ioctl(unsigned int cmd) -{ - char *dir; - - switch (_IOC_DIR(cmd)) { - case _IOC_NONE: dir = "--"; break; - case _IOC_READ: dir = "r-"; break; - case _IOC_WRITE: dir = "-w"; break; - case _IOC_READ | _IOC_WRITE: dir = "rw"; break; - default: dir = "*ERR*"; break; - } - switch (_IOC_TYPE(cmd)) { - case 'd': - printk("v4l2_int ioctl %s, dir=%s (0x%08x)\n", - (_IOC_NR(cmd) < V4L2_INT_IOCTLS) ? - v4l2_int_ioctls[_IOC_NR(cmd)] : "UNKNOWN", dir, cmd); - break; -#ifdef CONFIG_VIDEO_V4L1_COMPAT - case 'v': - printk("v4l1 ioctl %s, dir=%s (0x%08x)\n", - (_IOC_NR(cmd) < V4L1_IOCTLS) ? - v4l1_ioctls[_IOC_NR(cmd)] : "UNKNOWN", dir, cmd); - break; -#endif - case 'V': - printk("v4l2 ioctl %s, dir=%s (0x%08x)\n", - (_IOC_NR(cmd) < V4L2_IOCTLS) ? - v4l2_ioctls[_IOC_NR(cmd)] : "UNKNOWN", dir, cmd); - break; - - default: - printk("unknown ioctl '%c', dir=%s, #%d (0x%08x)\n", - _IOC_TYPE(cmd), dir, _IOC_NR(cmd), cmd); - } -} - +EXPORT_SYMBOL(v4l2_prio_check); /* ----------------------------------------------------------------- */ @@ -488,6 +172,7 @@ int v4l2_ctrl_check(struct v4l2_ext_control *ctrl, struct v4l2_queryctrl *qctrl, } return 0; } +EXPORT_SYMBOL(v4l2_ctrl_check); /* Returns NULL or a character pointer array containing the menu for the given control ID. The pointer array ends with a NULL pointer. @@ -648,6 +333,7 @@ const char **v4l2_ctrl_get_menu(u32 id) return NULL; } } +EXPORT_SYMBOL(v4l2_ctrl_get_menu); /* Fill in a struct v4l2_queryctrl */ int v4l2_ctrl_query_fill(struct v4l2_queryctrl *qctrl, s32 min, s32 max, s32 step, s32 def) @@ -770,6 +456,7 @@ int v4l2_ctrl_query_fill(struct v4l2_queryctrl *qctrl, s32 min, s32 max, s32 ste snprintf(qctrl->name, sizeof(qctrl->name), name); return 0; } +EXPORT_SYMBOL(v4l2_ctrl_query_fill); /* Fill in a struct v4l2_queryctrl with standard values based on the control ID. */ @@ -904,6 +591,7 @@ int v4l2_ctrl_query_fill_std(struct v4l2_queryctrl *qctrl) return -EINVAL; } } +EXPORT_SYMBOL(v4l2_ctrl_query_fill_std); /* Fill in a struct v4l2_querymenu based on the struct v4l2_queryctrl and the menu. The qctrl pointer may be NULL, in which case it is ignored. */ @@ -922,6 +610,7 @@ int v4l2_ctrl_query_menu(struct v4l2_querymenu *qmenu, struct v4l2_queryctrl *qc qmenu->reserved = 0; return 0; } +EXPORT_SYMBOL(v4l2_ctrl_query_menu); /* ctrl_classes points to an array of u32 pointers, the last element is a NULL pointer. Each u32 array is a 0-terminated array of control IDs. @@ -972,7 +661,20 @@ u32 v4l2_ctrl_next(const u32 * const * ctrl_classes, u32 id) return 0; return **ctrl_classes; } +EXPORT_SYMBOL(v4l2_ctrl_next); +int v4l2_chip_match_host(u32 match_type, u32 match_chip) +{ + switch (match_type) { + case V4L2_CHIP_MATCH_HOST: + return match_chip == 0; + default: + return 0; + } +} +EXPORT_SYMBOL(v4l2_chip_match_host); + +#if defined(CONFIG_I2C) || (defined(CONFIG_I2C_MODULE) && defined(MODULE)) int v4l2_chip_match_i2c_client(struct i2c_client *c, u32 match_type, u32 match_chip) { switch (match_type) { @@ -984,6 +686,7 @@ int v4l2_chip_match_i2c_client(struct i2c_client *c, u32 match_type, u32 match_c return 0; } } +EXPORT_SYMBOL(v4l2_chip_match_i2c_client); int v4l2_chip_ident_i2c_client(struct i2c_client *c, struct v4l2_chip_ident *chip, u32 ident, u32 revision) @@ -1000,16 +703,7 @@ int v4l2_chip_ident_i2c_client(struct i2c_client *c, struct v4l2_chip_ident *chi } return 0; } - -int v4l2_chip_match_host(u32 match_type, u32 match_chip) -{ - switch (match_type) { - case V4L2_CHIP_MATCH_HOST: - return match_chip == 0; - default: - return 0; - } -} +EXPORT_SYMBOL(v4l2_chip_ident_i2c_client); /* ----------------------------------------------------------------- */ @@ -1038,38 +732,5 @@ int v4l2_i2c_attach(struct i2c_adapter *adapter, int address, struct i2c_driver } return err != -ENOMEM ? 0 : err; } - -/* ----------------------------------------------------------------- */ - -EXPORT_SYMBOL(v4l2_norm_to_name); -EXPORT_SYMBOL(v4l2_video_std_construct); - -EXPORT_SYMBOL(v4l2_prio_init); -EXPORT_SYMBOL(v4l2_prio_change); -EXPORT_SYMBOL(v4l2_prio_open); -EXPORT_SYMBOL(v4l2_prio_close); -EXPORT_SYMBOL(v4l2_prio_max); -EXPORT_SYMBOL(v4l2_prio_check); - -EXPORT_SYMBOL(v4l2_field_names); -EXPORT_SYMBOL(v4l2_type_names); -EXPORT_SYMBOL(v4l_printk_ioctl); - -EXPORT_SYMBOL(v4l2_ctrl_next); -EXPORT_SYMBOL(v4l2_ctrl_check); -EXPORT_SYMBOL(v4l2_ctrl_get_menu); -EXPORT_SYMBOL(v4l2_ctrl_query_menu); -EXPORT_SYMBOL(v4l2_ctrl_query_fill); -EXPORT_SYMBOL(v4l2_ctrl_query_fill_std); - -EXPORT_SYMBOL(v4l2_chip_match_i2c_client); -EXPORT_SYMBOL(v4l2_chip_ident_i2c_client); -EXPORT_SYMBOL(v4l2_chip_match_host); - EXPORT_SYMBOL(v4l2_i2c_attach); - -/* - * Local variables: - * c-basic-offset: 8 - * End: - */ +#endif diff --git a/drivers/media/video/videobuf-core.c b/drivers/media/video/videobuf-core.c index 80a14da9ace..eab79ffdf56 100644 --- a/drivers/media/video/videobuf-core.c +++ b/drivers/media/video/videobuf-core.c @@ -147,7 +147,7 @@ void videobuf_queue_core_init(struct videobuf_queue *q, /* Having implementations for abstract methods are mandatory */ BUG_ON(!q->int_ops); - mutex_init(&q->lock); + mutex_init(&q->vb_lock); INIT_LIST_HEAD(&q->stream); } @@ -189,7 +189,7 @@ int videobuf_queue_is_busy(struct videobuf_queue *q) return 0; } -/* Locking: Caller holds q->lock */ +/* Locking: Caller holds q->vb_lock */ void videobuf_queue_cancel(struct videobuf_queue *q) { unsigned long flags = 0; @@ -220,7 +220,7 @@ void videobuf_queue_cancel(struct videobuf_queue *q) /* --------------------------------------------------------------------- */ -/* Locking: Caller holds q->lock */ +/* Locking: Caller holds q->vb_lock */ enum v4l2_field videobuf_next_field(struct videobuf_queue *q) { enum v4l2_field field = q->field; @@ -239,7 +239,7 @@ enum v4l2_field videobuf_next_field(struct videobuf_queue *q) return field; } -/* Locking: Caller holds q->lock */ +/* Locking: Caller holds q->vb_lock */ static void videobuf_status(struct videobuf_queue *q, struct v4l2_buffer *b, struct videobuf_buffer *vb, enum v4l2_buf_type type) { @@ -295,7 +295,7 @@ static void videobuf_status(struct videobuf_queue *q, struct v4l2_buffer *b, b->sequence = vb->field_count >> 1; } -/* Locking: Caller holds q->lock */ +/* Locking: Caller holds q->vb_lock */ static int __videobuf_mmap_free(struct videobuf_queue *q) { int i; @@ -328,13 +328,13 @@ static int __videobuf_mmap_free(struct videobuf_queue *q) int videobuf_mmap_free(struct videobuf_queue *q) { int ret; - mutex_lock(&q->lock); + mutex_lock(&q->vb_lock); ret = __videobuf_mmap_free(q); - mutex_unlock(&q->lock); + mutex_unlock(&q->vb_lock); return ret; } -/* Locking: Caller holds q->lock */ +/* Locking: Caller holds q->vb_lock */ static int __videobuf_mmap_setup(struct videobuf_queue *q, unsigned int bcount, unsigned int bsize, enum v4l2_memory memory) @@ -384,9 +384,9 @@ int videobuf_mmap_setup(struct videobuf_queue *q, enum v4l2_memory memory) { int ret; - mutex_lock(&q->lock); + mutex_lock(&q->vb_lock); ret = __videobuf_mmap_setup(q, bcount, bsize, memory); - mutex_unlock(&q->lock); + mutex_unlock(&q->vb_lock); return ret; } @@ -408,7 +408,7 @@ int videobuf_reqbufs(struct videobuf_queue *q, return -EINVAL; } - mutex_lock(&q->lock); + mutex_lock(&q->vb_lock); if (req->type != q->type) { dprintk(1, "reqbufs: queue type invalid\n"); retval = -EINVAL; @@ -444,7 +444,7 @@ int videobuf_reqbufs(struct videobuf_queue *q, req->count = retval; done: - mutex_unlock(&q->lock); + mutex_unlock(&q->vb_lock); return retval; } @@ -452,7 +452,7 @@ int videobuf_querybuf(struct videobuf_queue *q, struct v4l2_buffer *b) { int ret = -EINVAL; - mutex_lock(&q->lock); + mutex_lock(&q->vb_lock); if (unlikely(b->type != q->type)) { dprintk(1, "querybuf: Wrong type.\n"); goto done; @@ -470,7 +470,7 @@ int videobuf_querybuf(struct videobuf_queue *q, struct v4l2_buffer *b) ret = 0; done: - mutex_unlock(&q->lock); + mutex_unlock(&q->vb_lock); return ret; } @@ -487,7 +487,7 @@ int videobuf_qbuf(struct videobuf_queue *q, if (b->memory == V4L2_MEMORY_MMAP) down_read(¤t->mm->mmap_sem); - mutex_lock(&q->lock); + mutex_lock(&q->vb_lock); retval = -EBUSY; if (q->reading) { dprintk(1, "qbuf: Reading running...\n"); @@ -573,7 +573,7 @@ int videobuf_qbuf(struct videobuf_queue *q, retval = 0; done: - mutex_unlock(&q->lock); + mutex_unlock(&q->vb_lock); if (b->memory == V4L2_MEMORY_MMAP) up_read(¤t->mm->mmap_sem); @@ -589,7 +589,7 @@ int videobuf_dqbuf(struct videobuf_queue *q, MAGIC_CHECK(q->int_ops->magic, MAGIC_QTYPE_OPS); - mutex_lock(&q->lock); + mutex_lock(&q->vb_lock); retval = -EBUSY; if (q->reading) { dprintk(1, "dqbuf: Reading running...\n"); @@ -632,7 +632,7 @@ int videobuf_dqbuf(struct videobuf_queue *q, videobuf_status(q, b, buf, q->type); done: - mutex_unlock(&q->lock); + mutex_unlock(&q->vb_lock); return retval; } @@ -642,7 +642,7 @@ int videobuf_streamon(struct videobuf_queue *q) unsigned long flags = 0; int retval; - mutex_lock(&q->lock); + mutex_lock(&q->vb_lock); retval = -EBUSY; if (q->reading) goto done; @@ -659,11 +659,11 @@ int videobuf_streamon(struct videobuf_queue *q) spin_unlock_irqrestore(q->irqlock, flags); done: - mutex_unlock(&q->lock); + mutex_unlock(&q->vb_lock); return retval; } -/* Locking: Caller holds q->lock */ +/* Locking: Caller holds q->vb_lock */ static int __videobuf_streamoff(struct videobuf_queue *q) { if (!q->streaming) @@ -679,14 +679,14 @@ int videobuf_streamoff(struct videobuf_queue *q) { int retval; - mutex_lock(&q->lock); + mutex_lock(&q->vb_lock); retval = __videobuf_streamoff(q); - mutex_unlock(&q->lock); + mutex_unlock(&q->vb_lock); return retval; } -/* Locking: Caller holds q->lock */ +/* Locking: Caller holds q->vb_lock */ static ssize_t videobuf_read_zerocopy(struct videobuf_queue *q, char __user *data, size_t count, loff_t *ppos) @@ -745,7 +745,7 @@ ssize_t videobuf_read_one(struct videobuf_queue *q, MAGIC_CHECK(q->int_ops->magic, MAGIC_QTYPE_OPS); - mutex_lock(&q->lock); + mutex_lock(&q->vb_lock); nbufs = 1; size = 0; q->ops->buf_setup(q, &nbufs, &size); @@ -817,11 +817,11 @@ ssize_t videobuf_read_one(struct videobuf_queue *q, } done: - mutex_unlock(&q->lock); + mutex_unlock(&q->vb_lock); return retval; } -/* Locking: Caller holds q->lock */ +/* Locking: Caller holds q->vb_lock */ static int __videobuf_read_start(struct videobuf_queue *q) { enum v4l2_field field; @@ -882,23 +882,23 @@ int videobuf_read_start(struct videobuf_queue *q) { int rc; - mutex_lock(&q->lock); + mutex_lock(&q->vb_lock); rc = __videobuf_read_start(q); - mutex_unlock(&q->lock); + mutex_unlock(&q->vb_lock); return rc; } void videobuf_read_stop(struct videobuf_queue *q) { - mutex_lock(&q->lock); + mutex_lock(&q->vb_lock); __videobuf_read_stop(q); - mutex_unlock(&q->lock); + mutex_unlock(&q->vb_lock); } void videobuf_stop(struct videobuf_queue *q) { - mutex_lock(&q->lock); + mutex_lock(&q->vb_lock); if (q->streaming) __videobuf_streamoff(q); @@ -906,7 +906,7 @@ void videobuf_stop(struct videobuf_queue *q) if (q->reading) __videobuf_read_stop(q); - mutex_unlock(&q->lock); + mutex_unlock(&q->vb_lock); } @@ -920,7 +920,7 @@ ssize_t videobuf_read_stream(struct videobuf_queue *q, MAGIC_CHECK(q->int_ops->magic, MAGIC_QTYPE_OPS); dprintk(2, "%s\n", __FUNCTION__); - mutex_lock(&q->lock); + mutex_lock(&q->vb_lock); retval = -EBUSY; if (q->streaming) goto done; @@ -980,7 +980,7 @@ ssize_t videobuf_read_stream(struct videobuf_queue *q, } done: - mutex_unlock(&q->lock); + mutex_unlock(&q->vb_lock); return retval; } @@ -991,7 +991,7 @@ unsigned int videobuf_poll_stream(struct file *file, struct videobuf_buffer *buf = NULL; unsigned int rc = 0; - mutex_lock(&q->lock); + mutex_lock(&q->vb_lock); if (q->streaming) { if (!list_empty(&q->stream)) buf = list_entry(q->stream.next, @@ -1019,7 +1019,7 @@ unsigned int videobuf_poll_stream(struct file *file, buf->state == VIDEOBUF_ERROR) rc = POLLIN|POLLRDNORM; } - mutex_unlock(&q->lock); + mutex_unlock(&q->vb_lock); return rc; } @@ -1030,10 +1030,10 @@ int videobuf_mmap_mapper(struct videobuf_queue *q, MAGIC_CHECK(q->int_ops->magic, MAGIC_QTYPE_OPS); - mutex_lock(&q->lock); + mutex_lock(&q->vb_lock); retval = CALL(q, mmap_mapper, q, vma); q->is_mmapped = 1; - mutex_unlock(&q->lock); + mutex_unlock(&q->vb_lock); return retval; } diff --git a/drivers/media/video/videobuf-dma-sg.c b/drivers/media/video/videobuf-dma-sg.c index 98efd7ab1f5..53fed4b74ce 100644 --- a/drivers/media/video/videobuf-dma-sg.c +++ b/drivers/media/video/videobuf-dma-sg.c @@ -356,7 +356,7 @@ videobuf_vm_close(struct vm_area_struct *vma) map->count--; if (0 == map->count) { dprintk(1,"munmap %p q=%p\n",map,q); - mutex_lock(&q->lock); + mutex_lock(&q->vb_lock); for (i = 0; i < VIDEO_MAX_FRAME; i++) { if (NULL == q->bufs[i]) continue; @@ -373,7 +373,7 @@ videobuf_vm_close(struct vm_area_struct *vma) q->bufs[i]->baddr = 0; q->ops->buf_release(q,q->bufs[i]); } - mutex_unlock(&q->lock); + mutex_unlock(&q->vb_lock); kfree(map); } return; diff --git a/drivers/media/video/videobuf-vmalloc.c b/drivers/media/video/videobuf-vmalloc.c index 9b3898347ca..5266ecc91da 100644 --- a/drivers/media/video/videobuf-vmalloc.c +++ b/drivers/media/video/videobuf-vmalloc.c @@ -70,7 +70,7 @@ videobuf_vm_close(struct vm_area_struct *vma) map->count--; if (0 == map->count) { dprintk(1,"munmap %p q=%p\n",map,q); - mutex_lock(&q->lock); + mutex_lock(&q->vb_lock); for (i = 0; i < VIDEO_MAX_FRAME; i++) { if (NULL == q->bufs[i]) continue; @@ -83,7 +83,7 @@ videobuf_vm_close(struct vm_area_struct *vma) q->bufs[i]->map = NULL; q->bufs[i]->baddr = 0; } - mutex_unlock(&q->lock); + mutex_unlock(&q->vb_lock); kfree(map); } return; @@ -107,7 +107,7 @@ static struct vm_operations_struct videobuf_vm_ops = static void *__videobuf_alloc(size_t size) { - struct videbuf_vmalloc_memory *mem; + struct videobuf_vmalloc_memory *mem; struct videobuf_buffer *vb; vb = kzalloc(size+sizeof(*mem),GFP_KERNEL); @@ -127,9 +127,7 @@ static int __videobuf_iolock (struct videobuf_queue* q, struct v4l2_framebuffer *fbuf) { int pages; - - struct videbuf_vmalloc_memory *mem=vb->priv; - + struct videobuf_vmalloc_memory *mem=vb->priv; BUG_ON(!mem); @@ -195,7 +193,7 @@ static int __videobuf_mmap_free(struct videobuf_queue *q) static int __videobuf_mmap_mapper(struct videobuf_queue *q, struct vm_area_struct *vma) { - struct videbuf_vmalloc_memory *mem; + struct videobuf_vmalloc_memory *mem; struct videobuf_mapping *map; unsigned int first; int retval; @@ -267,7 +265,7 @@ static int __videobuf_copy_to_user ( struct videobuf_queue *q, char __user *data, size_t count, int nonblocking ) { - struct videbuf_vmalloc_memory *mem=q->read_buf->priv; + struct videobuf_vmalloc_memory *mem=q->read_buf->priv; BUG_ON (!mem); MAGIC_CHECK(mem->magic,MAGIC_VMAL_MEM); @@ -288,7 +286,7 @@ static int __videobuf_copy_stream ( struct videobuf_queue *q, int vbihack, int nonblocking ) { unsigned int *fc; - struct videbuf_vmalloc_memory *mem=q->read_buf->priv; + struct videobuf_vmalloc_memory *mem=q->read_buf->priv; BUG_ON (!mem); MAGIC_CHECK(mem->magic,MAGIC_VMAL_MEM); @@ -341,7 +339,7 @@ EXPORT_SYMBOL_GPL(videobuf_queue_vmalloc_init); void *videobuf_to_vmalloc (struct videobuf_buffer *buf) { - struct videbuf_vmalloc_memory *mem=buf->priv; + struct videobuf_vmalloc_memory *mem=buf->priv; BUG_ON (!mem); MAGIC_CHECK(mem->magic,MAGIC_VMAL_MEM); @@ -351,7 +349,7 @@ EXPORT_SYMBOL_GPL(videobuf_to_vmalloc); void videobuf_vmalloc_free (struct videobuf_buffer *buf) { - struct videbuf_vmalloc_memory *mem=buf->priv; + struct videobuf_vmalloc_memory *mem=buf->priv; BUG_ON (!mem); MAGIC_CHECK(mem->magic,MAGIC_VMAL_MEM); diff --git a/drivers/media/video/videodev.c b/drivers/media/video/videodev.c index 28655f8983c..0d9b63762a4 100644 --- a/drivers/media/video/videodev.c +++ b/drivers/media/video/videodev.c @@ -46,10 +46,373 @@ #include <linux/videodev.h> #endif #include <media/v4l2-common.h> +#include <linux/video_decoder.h> #define VIDEO_NUM_DEVICES 256 #define VIDEO_NAME "video4linux" +/* video4linux standard ID conversion to standard name + */ +char *v4l2_norm_to_name(v4l2_std_id id) +{ + char *name; + u32 myid = id; + + /* HACK: ppc32 architecture doesn't have __ucmpdi2 function to handle + 64 bit comparations. So, on that architecture, with some gcc + variants, compilation fails. Currently, the max value is 30bit wide. + */ + BUG_ON(myid != id); + + switch (myid) { + case V4L2_STD_PAL: + name = "PAL"; + break; + case V4L2_STD_PAL_BG: + name = "PAL-BG"; + break; + case V4L2_STD_PAL_DK: + name = "PAL-DK"; + break; + case V4L2_STD_PAL_B: + name = "PAL-B"; + break; + case V4L2_STD_PAL_B1: + name = "PAL-B1"; + break; + case V4L2_STD_PAL_G: + name = "PAL-G"; + break; + case V4L2_STD_PAL_H: + name = "PAL-H"; + break; + case V4L2_STD_PAL_I: + name = "PAL-I"; + break; + case V4L2_STD_PAL_D: + name = "PAL-D"; + break; + case V4L2_STD_PAL_D1: + name = "PAL-D1"; + break; + case V4L2_STD_PAL_K: + name = "PAL-K"; + break; + case V4L2_STD_PAL_M: + name = "PAL-M"; + break; + case V4L2_STD_PAL_N: + name = "PAL-N"; + break; + case V4L2_STD_PAL_Nc: + name = "PAL-Nc"; + break; + case V4L2_STD_PAL_60: + name = "PAL-60"; + break; + case V4L2_STD_NTSC: + name = "NTSC"; + break; + case V4L2_STD_NTSC_M: + name = "NTSC-M"; + break; + case V4L2_STD_NTSC_M_JP: + name = "NTSC-M-JP"; + break; + case V4L2_STD_NTSC_443: + name = "NTSC-443"; + break; + case V4L2_STD_NTSC_M_KR: + name = "NTSC-M-KR"; + break; + case V4L2_STD_SECAM: + name = "SECAM"; + break; + case V4L2_STD_SECAM_DK: + name = "SECAM-DK"; + break; + case V4L2_STD_SECAM_B: + name = "SECAM-B"; + break; + case V4L2_STD_SECAM_D: + name = "SECAM-D"; + break; + case V4L2_STD_SECAM_G: + name = "SECAM-G"; + break; + case V4L2_STD_SECAM_H: + name = "SECAM-H"; + break; + case V4L2_STD_SECAM_K: + name = "SECAM-K"; + break; + case V4L2_STD_SECAM_K1: + name = "SECAM-K1"; + break; + case V4L2_STD_SECAM_L: + name = "SECAM-L"; + break; + case V4L2_STD_SECAM_LC: + name = "SECAM-LC"; + break; + default: + name = "Unknown"; + break; + } + + return name; +} +EXPORT_SYMBOL(v4l2_norm_to_name); + +/* Fill in the fields of a v4l2_standard structure according to the + 'id' and 'transmission' parameters. Returns negative on error. */ +int v4l2_video_std_construct(struct v4l2_standard *vs, + int id, char *name) +{ + u32 index = vs->index; + + memset(vs, 0, sizeof(struct v4l2_standard)); + vs->index = index; + vs->id = id; + if (id & V4L2_STD_525_60) { + vs->frameperiod.numerator = 1001; + vs->frameperiod.denominator = 30000; + vs->framelines = 525; + } else { + vs->frameperiod.numerator = 1; + vs->frameperiod.denominator = 25; + vs->framelines = 625; + } + strlcpy(vs->name, name, sizeof(vs->name)); + return 0; +} +EXPORT_SYMBOL(v4l2_video_std_construct); + +/* ----------------------------------------------------------------- */ +/* some arrays for pretty-printing debug messages of enum types */ + +char *v4l2_field_names[] = { + [V4L2_FIELD_ANY] = "any", + [V4L2_FIELD_NONE] = "none", + [V4L2_FIELD_TOP] = "top", + [V4L2_FIELD_BOTTOM] = "bottom", + [V4L2_FIELD_INTERLACED] = "interlaced", + [V4L2_FIELD_SEQ_TB] = "seq-tb", + [V4L2_FIELD_SEQ_BT] = "seq-bt", + [V4L2_FIELD_ALTERNATE] = "alternate", + [V4L2_FIELD_INTERLACED_TB] = "interlaced-tb", + [V4L2_FIELD_INTERLACED_BT] = "interlaced-bt", +}; +EXPORT_SYMBOL(v4l2_field_names); + +char *v4l2_type_names[] = { + [V4L2_BUF_TYPE_VIDEO_CAPTURE] = "video-cap", + [V4L2_BUF_TYPE_VIDEO_OVERLAY] = "video-over", + [V4L2_BUF_TYPE_VIDEO_OUTPUT] = "video-out", + [V4L2_BUF_TYPE_VBI_CAPTURE] = "vbi-cap", + [V4L2_BUF_TYPE_VBI_OUTPUT] = "vbi-out", + [V4L2_BUF_TYPE_SLICED_VBI_CAPTURE] = "sliced-vbi-cap", + [V4L2_BUF_TYPE_SLICED_VBI_OUTPUT] = "sliced-vbi-out", + [V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY] = "video-out-over", +}; +EXPORT_SYMBOL(v4l2_type_names); + +static char *v4l2_memory_names[] = { + [V4L2_MEMORY_MMAP] = "mmap", + [V4L2_MEMORY_USERPTR] = "userptr", + [V4L2_MEMORY_OVERLAY] = "overlay", +}; + +#define prt_names(a, arr) ((((a) >= 0) && ((a) < ARRAY_SIZE(arr))) ? \ + arr[a] : "unknown") + +/* ------------------------------------------------------------------ */ +/* debug help functions */ + +#ifdef CONFIG_VIDEO_V4L1_COMPAT +static const char *v4l1_ioctls[] = { + [_IOC_NR(VIDIOCGCAP)] = "VIDIOCGCAP", + [_IOC_NR(VIDIOCGCHAN)] = "VIDIOCGCHAN", + [_IOC_NR(VIDIOCSCHAN)] = "VIDIOCSCHAN", + [_IOC_NR(VIDIOCGTUNER)] = "VIDIOCGTUNER", + [_IOC_NR(VIDIOCSTUNER)] = "VIDIOCSTUNER", + [_IOC_NR(VIDIOCGPICT)] = "VIDIOCGPICT", + [_IOC_NR(VIDIOCSPICT)] = "VIDIOCSPICT", + [_IOC_NR(VIDIOCCAPTURE)] = "VIDIOCCAPTURE", + [_IOC_NR(VIDIOCGWIN)] = "VIDIOCGWIN", + [_IOC_NR(VIDIOCSWIN)] = "VIDIOCSWIN", + [_IOC_NR(VIDIOCGFBUF)] = "VIDIOCGFBUF", + [_IOC_NR(VIDIOCSFBUF)] = "VIDIOCSFBUF", + [_IOC_NR(VIDIOCKEY)] = "VIDIOCKEY", + [_IOC_NR(VIDIOCGFREQ)] = "VIDIOCGFREQ", + [_IOC_NR(VIDIOCSFREQ)] = "VIDIOCSFREQ", + [_IOC_NR(VIDIOCGAUDIO)] = "VIDIOCGAUDIO", + [_IOC_NR(VIDIOCSAUDIO)] = "VIDIOCSAUDIO", + [_IOC_NR(VIDIOCSYNC)] = "VIDIOCSYNC", + [_IOC_NR(VIDIOCMCAPTURE)] = "VIDIOCMCAPTURE", + [_IOC_NR(VIDIOCGMBUF)] = "VIDIOCGMBUF", + [_IOC_NR(VIDIOCGUNIT)] = "VIDIOCGUNIT", + [_IOC_NR(VIDIOCGCAPTURE)] = "VIDIOCGCAPTURE", + [_IOC_NR(VIDIOCSCAPTURE)] = "VIDIOCSCAPTURE", + [_IOC_NR(VIDIOCSPLAYMODE)] = "VIDIOCSPLAYMODE", + [_IOC_NR(VIDIOCSWRITEMODE)] = "VIDIOCSWRITEMODE", + [_IOC_NR(VIDIOCGPLAYINFO)] = "VIDIOCGPLAYINFO", + [_IOC_NR(VIDIOCSMICROCODE)] = "VIDIOCSMICROCODE", + [_IOC_NR(VIDIOCGVBIFMT)] = "VIDIOCGVBIFMT", + [_IOC_NR(VIDIOCSVBIFMT)] = "VIDIOCSVBIFMT" +}; +#define V4L1_IOCTLS ARRAY_SIZE(v4l1_ioctls) +#endif + +static const char *v4l2_ioctls[] = { + [_IOC_NR(VIDIOC_QUERYCAP)] = "VIDIOC_QUERYCAP", + [_IOC_NR(VIDIOC_RESERVED)] = "VIDIOC_RESERVED", + [_IOC_NR(VIDIOC_ENUM_FMT)] = "VIDIOC_ENUM_FMT", + [_IOC_NR(VIDIOC_G_FMT)] = "VIDIOC_G_FMT", + [_IOC_NR(VIDIOC_S_FMT)] = "VIDIOC_S_FMT", + [_IOC_NR(VIDIOC_REQBUFS)] = "VIDIOC_REQBUFS", + [_IOC_NR(VIDIOC_QUERYBUF)] = "VIDIOC_QUERYBUF", + [_IOC_NR(VIDIOC_G_FBUF)] = "VIDIOC_G_FBUF", + [_IOC_NR(VIDIOC_S_FBUF)] = "VIDIOC_S_FBUF", + [_IOC_NR(VIDIOC_OVERLAY)] = "VIDIOC_OVERLAY", + [_IOC_NR(VIDIOC_QBUF)] = "VIDIOC_QBUF", + [_IOC_NR(VIDIOC_DQBUF)] = "VIDIOC_DQBUF", + [_IOC_NR(VIDIOC_STREAMON)] = "VIDIOC_STREAMON", + [_IOC_NR(VIDIOC_STREAMOFF)] = "VIDIOC_STREAMOFF", + [_IOC_NR(VIDIOC_G_PARM)] = "VIDIOC_G_PARM", + [_IOC_NR(VIDIOC_S_PARM)] = "VIDIOC_S_PARM", + [_IOC_NR(VIDIOC_G_STD)] = "VIDIOC_G_STD", + [_IOC_NR(VIDIOC_S_STD)] = "VIDIOC_S_STD", + [_IOC_NR(VIDIOC_ENUMSTD)] = "VIDIOC_ENUMSTD", + [_IOC_NR(VIDIOC_ENUMINPUT)] = "VIDIOC_ENUMINPUT", + [_IOC_NR(VIDIOC_G_CTRL)] = "VIDIOC_G_CTRL", + [_IOC_NR(VIDIOC_S_CTRL)] = "VIDIOC_S_CTRL", + [_IOC_NR(VIDIOC_G_TUNER)] = "VIDIOC_G_TUNER", + [_IOC_NR(VIDIOC_S_TUNER)] = "VIDIOC_S_TUNER", + [_IOC_NR(VIDIOC_G_AUDIO)] = "VIDIOC_G_AUDIO", + [_IOC_NR(VIDIOC_S_AUDIO)] = "VIDIOC_S_AUDIO", + [_IOC_NR(VIDIOC_QUERYCTRL)] = "VIDIOC_QUERYCTRL", + [_IOC_NR(VIDIOC_QUERYMENU)] = "VIDIOC_QUERYMENU", + [_IOC_NR(VIDIOC_G_INPUT)] = "VIDIOC_G_INPUT", + [_IOC_NR(VIDIOC_S_INPUT)] = "VIDIOC_S_INPUT", + [_IOC_NR(VIDIOC_G_OUTPUT)] = "VIDIOC_G_OUTPUT", + [_IOC_NR(VIDIOC_S_OUTPUT)] = "VIDIOC_S_OUTPUT", + [_IOC_NR(VIDIOC_ENUMOUTPUT)] = "VIDIOC_ENUMOUTPUT", + [_IOC_NR(VIDIOC_G_AUDOUT)] = "VIDIOC_G_AUDOUT", + [_IOC_NR(VIDIOC_S_AUDOUT)] = "VIDIOC_S_AUDOUT", + [_IOC_NR(VIDIOC_G_MODULATOR)] = "VIDIOC_G_MODULATOR", + [_IOC_NR(VIDIOC_S_MODULATOR)] = "VIDIOC_S_MODULATOR", + [_IOC_NR(VIDIOC_G_FREQUENCY)] = "VIDIOC_G_FREQUENCY", + [_IOC_NR(VIDIOC_S_FREQUENCY)] = "VIDIOC_S_FREQUENCY", + [_IOC_NR(VIDIOC_CROPCAP)] = "VIDIOC_CROPCAP", + [_IOC_NR(VIDIOC_G_CROP)] = "VIDIOC_G_CROP", + [_IOC_NR(VIDIOC_S_CROP)] = "VIDIOC_S_CROP", + [_IOC_NR(VIDIOC_G_JPEGCOMP)] = "VIDIOC_G_JPEGCOMP", + [_IOC_NR(VIDIOC_S_JPEGCOMP)] = "VIDIOC_S_JPEGCOMP", + [_IOC_NR(VIDIOC_QUERYSTD)] = "VIDIOC_QUERYSTD", + [_IOC_NR(VIDIOC_TRY_FMT)] = "VIDIOC_TRY_FMT", + [_IOC_NR(VIDIOC_ENUMAUDIO)] = "VIDIOC_ENUMAUDIO", + [_IOC_NR(VIDIOC_ENUMAUDOUT)] = "VIDIOC_ENUMAUDOUT", + [_IOC_NR(VIDIOC_G_PRIORITY)] = "VIDIOC_G_PRIORITY", + [_IOC_NR(VIDIOC_S_PRIORITY)] = "VIDIOC_S_PRIORITY", + [_IOC_NR(VIDIOC_G_SLICED_VBI_CAP)] = "VIDIOC_G_SLICED_VBI_CAP", + [_IOC_NR(VIDIOC_LOG_STATUS)] = "VIDIOC_LOG_STATUS", + [_IOC_NR(VIDIOC_G_EXT_CTRLS)] = "VIDIOC_G_EXT_CTRLS", + [_IOC_NR(VIDIOC_S_EXT_CTRLS)] = "VIDIOC_S_EXT_CTRLS", + [_IOC_NR(VIDIOC_TRY_EXT_CTRLS)] = "VIDIOC_TRY_EXT_CTRLS", +#if 1 + [_IOC_NR(VIDIOC_ENUM_FRAMESIZES)] = "VIDIOC_ENUM_FRAMESIZES", + [_IOC_NR(VIDIOC_ENUM_FRAMEINTERVALS)] = "VIDIOC_ENUM_FRAMEINTERVALS", + [_IOC_NR(VIDIOC_G_ENC_INDEX)] = "VIDIOC_G_ENC_INDEX", + [_IOC_NR(VIDIOC_ENCODER_CMD)] = "VIDIOC_ENCODER_CMD", + [_IOC_NR(VIDIOC_TRY_ENCODER_CMD)] = "VIDIOC_TRY_ENCODER_CMD", + + [_IOC_NR(VIDIOC_DBG_S_REGISTER)] = "VIDIOC_DBG_S_REGISTER", + [_IOC_NR(VIDIOC_DBG_G_REGISTER)] = "VIDIOC_DBG_G_REGISTER", + + [_IOC_NR(VIDIOC_G_CHIP_IDENT)] = "VIDIOC_G_CHIP_IDENT", +#endif +}; +#define V4L2_IOCTLS ARRAY_SIZE(v4l2_ioctls) + +static const char *v4l2_int_ioctls[] = { +#ifdef CONFIG_VIDEO_V4L1_COMPAT + [_IOC_NR(DECODER_GET_CAPABILITIES)] = "DECODER_GET_CAPABILITIES", + [_IOC_NR(DECODER_GET_STATUS)] = "DECODER_GET_STATUS", + [_IOC_NR(DECODER_SET_NORM)] = "DECODER_SET_NORM", + [_IOC_NR(DECODER_SET_INPUT)] = "DECODER_SET_INPUT", + [_IOC_NR(DECODER_SET_OUTPUT)] = "DECODER_SET_OUTPUT", + [_IOC_NR(DECODER_ENABLE_OUTPUT)] = "DECODER_ENABLE_OUTPUT", + [_IOC_NR(DECODER_SET_PICTURE)] = "DECODER_SET_PICTURE", + [_IOC_NR(DECODER_SET_GPIO)] = "DECODER_SET_GPIO", + [_IOC_NR(DECODER_INIT)] = "DECODER_INIT", + [_IOC_NR(DECODER_SET_VBI_BYPASS)] = "DECODER_SET_VBI_BYPASS", + [_IOC_NR(DECODER_DUMP)] = "DECODER_DUMP", +#endif + [_IOC_NR(AUDC_SET_RADIO)] = "AUDC_SET_RADIO", + + [_IOC_NR(TUNER_SET_TYPE_ADDR)] = "TUNER_SET_TYPE_ADDR", + [_IOC_NR(TUNER_SET_STANDBY)] = "TUNER_SET_STANDBY", + [_IOC_NR(TUNER_SET_CONFIG)] = "TUNER_SET_CONFIG", + + [_IOC_NR(VIDIOC_INT_S_TUNER_MODE)] = "VIDIOC_INT_S_TUNER_MODE", + [_IOC_NR(VIDIOC_INT_RESET)] = "VIDIOC_INT_RESET", + [_IOC_NR(VIDIOC_INT_AUDIO_CLOCK_FREQ)] = "VIDIOC_INT_AUDIO_CLOCK_FREQ", + [_IOC_NR(VIDIOC_INT_DECODE_VBI_LINE)] = "VIDIOC_INT_DECODE_VBI_LINE", + [_IOC_NR(VIDIOC_INT_S_VBI_DATA)] = "VIDIOC_INT_S_VBI_DATA", + [_IOC_NR(VIDIOC_INT_G_VBI_DATA)] = "VIDIOC_INT_G_VBI_DATA", + [_IOC_NR(VIDIOC_INT_I2S_CLOCK_FREQ)] = "VIDIOC_INT_I2S_CLOCK_FREQ", + [_IOC_NR(VIDIOC_INT_S_STANDBY)] = "VIDIOC_INT_S_STANDBY", + [_IOC_NR(VIDIOC_INT_S_AUDIO_ROUTING)] = "VIDIOC_INT_S_AUDIO_ROUTING", + [_IOC_NR(VIDIOC_INT_G_AUDIO_ROUTING)] = "VIDIOC_INT_G_AUDIO_ROUTING", + [_IOC_NR(VIDIOC_INT_S_VIDEO_ROUTING)] = "VIDIOC_INT_S_VIDEO_ROUTING", + [_IOC_NR(VIDIOC_INT_G_VIDEO_ROUTING)] = "VIDIOC_INT_G_VIDEO_ROUTING", + [_IOC_NR(VIDIOC_INT_S_CRYSTAL_FREQ)] = "VIDIOC_INT_S_CRYSTAL_FREQ", + [_IOC_NR(VIDIOC_INT_INIT)] = "VIDIOC_INT_INIT", + [_IOC_NR(VIDIOC_INT_G_STD_OUTPUT)] = "VIDIOC_INT_G_STD_OUTPUT", + [_IOC_NR(VIDIOC_INT_S_STD_OUTPUT)] = "VIDIOC_INT_S_STD_OUTPUT", +}; +#define V4L2_INT_IOCTLS ARRAY_SIZE(v4l2_int_ioctls) + +/* Common ioctl debug function. This function can be used by + external ioctl messages as well as internal V4L ioctl */ +void v4l_printk_ioctl(unsigned int cmd) +{ + char *dir; + + switch (_IOC_DIR(cmd)) { + case _IOC_NONE: dir = "--"; break; + case _IOC_READ: dir = "r-"; break; + case _IOC_WRITE: dir = "-w"; break; + case _IOC_READ | _IOC_WRITE: dir = "rw"; break; + default: dir = "*ERR*"; break; + } + switch (_IOC_TYPE(cmd)) { + case 'd': + printk("v4l2_int ioctl %s, dir=%s (0x%08x)\n", + (_IOC_NR(cmd) < V4L2_INT_IOCTLS) ? + v4l2_int_ioctls[_IOC_NR(cmd)] : "UNKNOWN", dir, cmd); + break; +#ifdef CONFIG_VIDEO_V4L1_COMPAT + case 'v': + printk("v4l1 ioctl %s, dir=%s (0x%08x)\n", + (_IOC_NR(cmd) < V4L1_IOCTLS) ? + v4l1_ioctls[_IOC_NR(cmd)] : "UNKNOWN", dir, cmd); + break; +#endif + case 'V': + printk("v4l2 ioctl %s, dir=%s (0x%08x)\n", + (_IOC_NR(cmd) < V4L2_IOCTLS) ? + v4l2_ioctls[_IOC_NR(cmd)] : "UNKNOWN", dir, cmd); + break; + + default: + printk("unknown ioctl '%c', dir=%s, #%d (0x%08x)\n", + _IOC_TYPE(cmd), dir, _IOC_NR(cmd), cmd); + } +} +EXPORT_SYMBOL(v4l_printk_ioctl); + /* * sysfs stuff */ @@ -69,11 +432,13 @@ struct video_device *video_device_alloc(void) vfd = kzalloc(sizeof(*vfd),GFP_KERNEL); return vfd; } +EXPORT_SYMBOL(video_device_alloc); void video_device_release(struct video_device *vfd) { kfree(vfd); } +EXPORT_SYMBOL(video_device_release); static void video_release(struct device *cd) { @@ -110,6 +475,7 @@ struct video_device* video_devdata(struct file *file) { return video_device[iminor(file->f_path.dentry->d_inode)]; } +EXPORT_SYMBOL(video_devdata); /* * Open a video device - FIXME: Obsoleted @@ -278,6 +644,7 @@ out: kfree(mbuf); return err; } +EXPORT_SYMBOL(video_usercopy); /* * open/release helper functions -- handle exclusive opens @@ -297,6 +664,7 @@ int video_exclusive_open(struct inode *inode, struct file *file) mutex_unlock(&vfl->lock); return retval; } +EXPORT_SYMBOL(video_exclusive_open); int video_exclusive_release(struct inode *inode, struct file *file) { @@ -305,41 +673,7 @@ int video_exclusive_release(struct inode *inode, struct file *file) vfl->users--; return 0; } - -static char *v4l2_memory_names[] = { - [V4L2_MEMORY_MMAP] = "mmap", - [V4L2_MEMORY_USERPTR] = "userptr", - [V4L2_MEMORY_OVERLAY] = "overlay", -}; - - -/* FIXME: Those stuff are replicated also on v4l2-common.c */ -static char *v4l2_type_names_FIXME[] = { - [V4L2_BUF_TYPE_VIDEO_CAPTURE] = "video-cap", - [V4L2_BUF_TYPE_VIDEO_OVERLAY] = "video-over", - [V4L2_BUF_TYPE_VIDEO_OUTPUT] = "video-out", - [V4L2_BUF_TYPE_VBI_CAPTURE] = "vbi-cap", - [V4L2_BUF_TYPE_VBI_OUTPUT] = "vbi-out", - [V4L2_BUF_TYPE_SLICED_VBI_OUTPUT] = "sliced-vbi-out", - [V4L2_BUF_TYPE_SLICED_VBI_CAPTURE] = "sliced-vbi-capture", - [V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY] = "video-out-over", - [V4L2_BUF_TYPE_PRIVATE] = "private", -}; - -static char *v4l2_field_names_FIXME[] = { - [V4L2_FIELD_ANY] = "any", - [V4L2_FIELD_NONE] = "none", - [V4L2_FIELD_TOP] = "top", - [V4L2_FIELD_BOTTOM] = "bottom", - [V4L2_FIELD_INTERLACED] = "interlaced", - [V4L2_FIELD_SEQ_TB] = "seq-tb", - [V4L2_FIELD_SEQ_BT] = "seq-bt", - [V4L2_FIELD_ALTERNATE] = "alternate", - [V4L2_FIELD_INTERLACED_TB] = "interlaced-tb", - [V4L2_FIELD_INTERLACED_BT] = "interlaced-bt", -}; - -#define prt_names(a,arr) (((a)>=0)&&((a)<ARRAY_SIZE(arr)))?arr[a]:"unknown" +EXPORT_SYMBOL(video_exclusive_release); static void dbgbuf(unsigned int cmd, struct video_device *vfd, struct v4l2_buffer *p) @@ -354,10 +688,10 @@ static void dbgbuf(unsigned int cmd, struct video_device *vfd, (int)(p->timestamp.tv_sec%60), p->timestamp.tv_usec, p->index, - prt_names(p->type,v4l2_type_names_FIXME), - p->bytesused,p->flags, - p->field,p->sequence, - prt_names(p->memory,v4l2_memory_names), + prt_names(p->type, v4l2_type_names), + p->bytesused, p->flags, + p->field, p->sequence, + prt_names(p->memory, v4l2_memory_names), p->m.userptr, p->length); dbgarg2 ("timecode= %02d:%02d:%02d type=%d, " "flags=0x%08d, frames=%d, userbits=0x%08x\n", @@ -382,8 +716,8 @@ static inline void v4l_print_pix_fmt (struct video_device *vfd, (fmt->pixelformat >> 8) & 0xff, (fmt->pixelformat >> 16) & 0xff, (fmt->pixelformat >> 24) & 0xff, - prt_names(fmt->field,v4l2_field_names_FIXME), - fmt->bytesperline,fmt->sizeimage,fmt->colorspace); + prt_names(fmt->field, v4l2_field_names), + fmt->bytesperline, fmt->sizeimage, fmt->colorspace); }; @@ -597,7 +931,7 @@ static int __video_do_ioctl(struct inode *inode, struct file *file, /* FIXME: Should be one dump per type */ dbgarg (cmd, "type=%s\n", prt_names(type, - v4l2_type_names_FIXME)); + v4l2_type_names)); switch (type) { case V4L2_BUF_TYPE_VIDEO_CAPTURE: @@ -650,7 +984,7 @@ static int __video_do_ioctl(struct inode *inode, struct file *file, /* FIXME: Should be one dump per type */ dbgarg (cmd, "type=%s\n", prt_names(f->type, - v4l2_type_names_FIXME)); + v4l2_type_names)); switch (f->type) { case V4L2_BUF_TYPE_VIDEO_CAPTURE: @@ -702,7 +1036,7 @@ static int __video_do_ioctl(struct inode *inode, struct file *file, /* FIXME: Should be one dump per type */ dbgarg (cmd, "type=%s\n", prt_names(f->type, - v4l2_type_names_FIXME)); + v4l2_type_names)); switch (f->type) { case V4L2_BUF_TYPE_VIDEO_CAPTURE: if (vfd->vidioc_try_fmt_cap) @@ -768,8 +1102,8 @@ static int __video_do_ioctl(struct inode *inode, struct file *file, ret=vfd->vidioc_reqbufs(file, fh, p); dbgarg (cmd, "count=%d, type=%s, memory=%s\n", p->count, - prt_names(p->type,v4l2_type_names_FIXME), - prt_names(p->memory,v4l2_memory_names)); + prt_names(p->type, v4l2_type_names), + prt_names(p->memory, v4l2_memory_names)); break; } case VIDIOC_QUERYBUF: @@ -858,7 +1192,7 @@ static int __video_do_ioctl(struct inode *inode, struct file *file, enum v4l2_buf_type i = *(int *)arg; if (!vfd->vidioc_streamon) break; - dbgarg (cmd, "type=%s\n", prt_names(i,v4l2_type_names_FIXME)); + dbgarg(cmd, "type=%s\n", prt_names(i, v4l2_type_names)); ret=vfd->vidioc_streamon(file, fh,i); break; } @@ -868,7 +1202,7 @@ static int __video_do_ioctl(struct inode *inode, struct file *file, if (!vfd->vidioc_streamoff) break; - dbgarg (cmd, "type=%s\n", prt_names(i,v4l2_type_names_FIXME)); + dbgarg(cmd, "type=%s\n", prt_names(i, v4l2_type_names)); ret=vfd->vidioc_streamoff(file, fh, i); break; } @@ -1624,7 +1958,7 @@ out: kfree(mbuf); return err; } - +EXPORT_SYMBOL(video_ioctl2); static const struct file_operations video_fops; @@ -1743,6 +2077,7 @@ fail_minor: mutex_unlock(&videodev_lock); return ret; } +EXPORT_SYMBOL(video_register_device); /** * video_unregister_device - unregister a video4linux device @@ -1762,6 +2097,7 @@ void video_unregister_device(struct video_device *vfd) device_unregister(&vfd->class_dev); mutex_unlock(&videodev_lock); } +EXPORT_SYMBOL(video_unregister_device); /* * Video fs operations @@ -1806,16 +2142,6 @@ static void __exit videodev_exit(void) module_init(videodev_init) module_exit(videodev_exit) -EXPORT_SYMBOL(video_register_device); -EXPORT_SYMBOL(video_unregister_device); -EXPORT_SYMBOL(video_devdata); -EXPORT_SYMBOL(video_usercopy); -EXPORT_SYMBOL(video_exclusive_open); -EXPORT_SYMBOL(video_exclusive_release); -EXPORT_SYMBOL(video_ioctl2); -EXPORT_SYMBOL(video_device_alloc); -EXPORT_SYMBOL(video_device_release); - MODULE_AUTHOR("Alan Cox, Mauro Carvalho Chehab <mchehab@infradead.org>"); MODULE_DESCRIPTION("Device registrar for Video4Linux drivers v2"); MODULE_LICENSE("GPL"); diff --git a/drivers/media/video/zoran.h b/drivers/media/video/zoran.h index 937c4a616c0..498a43c1f2b 100644 --- a/drivers/media/video/zoran.h +++ b/drivers/media/video/zoran.h @@ -221,15 +221,15 @@ enum zoran_map_mode { }; enum gpio_type { - GPIO_JPEG_SLEEP = 0, - GPIO_JPEG_RESET, - GPIO_JPEG_FRAME, - GPIO_VID_DIR, - GPIO_VID_EN, - GPIO_VID_RESET, - GPIO_CLK_SEL1, - GPIO_CLK_SEL2, - GPIO_MAX, + ZR_GPIO_JPEG_SLEEP = 0, + ZR_GPIO_JPEG_RESET, + ZR_GPIO_JPEG_FRAME, + ZR_GPIO_VID_DIR, + ZR_GPIO_VID_EN, + ZR_GPIO_VID_RESET, + ZR_GPIO_CLK_SEL1, + ZR_GPIO_CLK_SEL2, + ZR_GPIO_MAX, }; enum gpcs_type { @@ -378,11 +378,11 @@ struct card_info { u32 jpeg_int; /* JPEG interrupt */ u32 vsync_int; /* VSYNC interrupt */ - s8 gpio[GPIO_MAX]; + s8 gpio[ZR_GPIO_MAX]; u8 gpcs[GPCS_MAX]; struct vfe_polarity vfe_pol; - u8 gpio_pol[GPIO_MAX]; + u8 gpio_pol[ZR_GPIO_MAX]; /* is the /GWS line conected? */ u8 gws_not_connected; diff --git a/drivers/media/video/zoran_device.c b/drivers/media/video/zoran_device.c index 68c7c505587..f97c2069205 100644 --- a/drivers/media/video/zoran_device.c +++ b/drivers/media/video/zoran_device.c @@ -250,7 +250,7 @@ void jpeg_codec_sleep (struct zoran *zr, int sleep) { - GPIO(zr, zr->card.gpio[GPIO_JPEG_SLEEP], !sleep); + GPIO(zr, zr->card.gpio[ZR_GPIO_JPEG_SLEEP], !sleep); if (!sleep) { dprintk(3, KERN_DEBUG @@ -277,9 +277,9 @@ jpeg_codec_reset (struct zoran *zr) 0); udelay(2); } else { - GPIO(zr, zr->card.gpio[GPIO_JPEG_RESET], 0); + GPIO(zr, zr->card.gpio[ZR_GPIO_JPEG_RESET], 0); udelay(2); - GPIO(zr, zr->card.gpio[GPIO_JPEG_RESET], 1); + GPIO(zr, zr->card.gpio[ZR_GPIO_JPEG_RESET], 1); udelay(2); } @@ -688,7 +688,7 @@ static inline void set_frame (struct zoran *zr, int val) { - GPIO(zr, zr->card.gpio[GPIO_JPEG_FRAME], val); + GPIO(zr, zr->card.gpio[ZR_GPIO_JPEG_FRAME], val); } static void @@ -704,8 +704,8 @@ set_videobus_dir (struct zoran *zr, GPIO(zr, 5, 1); break; default: - GPIO(zr, zr->card.gpio[GPIO_VID_DIR], - zr->card.gpio_pol[GPIO_VID_DIR] ? !val : val); + GPIO(zr, zr->card.gpio[ZR_GPIO_VID_DIR], + zr->card.gpio_pol[ZR_GPIO_VID_DIR] ? !val : val); break; } } diff --git a/drivers/media/video/zr364xx.c b/drivers/media/video/zr364xx.c index 1fdbb46de7f..1b44784d0ef 100644 --- a/drivers/media/video/zr364xx.c +++ b/drivers/media/video/zr364xx.c @@ -93,6 +93,8 @@ static struct usb_device_id device_table[] = { {USB_DEVICE(0x06d6, 0x0034), .driver_info = METHOD0 }, {USB_DEVICE(0x0a17, 0x0062), .driver_info = METHOD2 }, {USB_DEVICE(0x06d6, 0x003b), .driver_info = METHOD0 }, + {USB_DEVICE(0x0a17, 0x004e), .driver_info = METHOD2 }, + {USB_DEVICE(0x041e, 0x405d), .driver_info = METHOD2 }, {} /* Terminating entry */ }; diff --git a/drivers/memstick/host/tifm_ms.c b/drivers/memstick/host/tifm_ms.c index f55b71a4337..4fb24215bd9 100644 --- a/drivers/memstick/host/tifm_ms.c +++ b/drivers/memstick/host/tifm_ms.c @@ -282,7 +282,7 @@ static int tifm_ms_issue_cmd(struct tifm_ms *host) writel(TIFM_MS_SYS_LATCH | readl(sock->addr + SOCK_MS_SYSTEM), - sock + SOCK_MS_SYSTEM); + sock->addr + SOCK_MS_SYSTEM); writel(0, sock->addr + SOCK_MS_DATA); dev_dbg(&sock->dev, "writing %x\n", 0); diff --git a/drivers/message/fusion/mptbase.c b/drivers/message/fusion/mptbase.c index 425f60c21fd..bfda731696f 100644 --- a/drivers/message/fusion/mptbase.c +++ b/drivers/message/fusion/mptbase.c @@ -1470,9 +1470,6 @@ mpt_attach(struct pci_dev *pdev, const struct pci_device_id *id) if (mpt_debug_level) printk(KERN_INFO MYNAM ": mpt_debug_level=%xh\n", mpt_debug_level); - if (pci_enable_device(pdev)) - return r; - ioc = kzalloc(sizeof(MPT_ADAPTER), GFP_ATOMIC); if (ioc == NULL) { printk(KERN_ERR MYNAM ": ERROR - Insufficient memory to add adapter!\n"); @@ -1482,6 +1479,20 @@ mpt_attach(struct pci_dev *pdev, const struct pci_device_id *id) ioc->id = mpt_ids++; sprintf(ioc->name, "ioc%d", ioc->id); + ioc->bars = pci_select_bars(pdev, IORESOURCE_MEM); + if (pci_enable_device_mem(pdev)) { + kfree(ioc); + printk(MYIOC_s_ERR_FMT "pci_enable_device_mem() " + "failed\n", ioc->name); + return r; + } + if (pci_request_selected_regions(pdev, ioc->bars, "mpt")) { + kfree(ioc); + printk(MYIOC_s_ERR_FMT "pci_request_selected_regions() with " + "MEM failed\n", ioc->name); + return r; + } + dinitprintk(ioc, printk(MYIOC_s_INFO_FMT ": mpt_adapter_install\n", ioc->name)); if (!pci_set_dma_mask(pdev, DMA_64BIT_MASK)) { @@ -1658,6 +1669,9 @@ mpt_attach(struct pci_dev *pdev, const struct pci_device_id *id) ioc->active = 0; CHIPREG_WRITE32(&ioc->chip->IntStatus, 0); + /* Set IOC ptr in the pcidev's driver data. */ + pci_set_drvdata(ioc->pcidev, ioc); + /* Set lookup ptr. */ list_add_tail(&ioc->list, &ioc_list); @@ -1791,6 +1805,7 @@ mpt_suspend(struct pci_dev *pdev, pm_message_t state) CHIPREG_WRITE32(&ioc->chip->IntStatus, 0); pci_disable_device(pdev); + pci_release_selected_regions(pdev, ioc->bars); pci_set_power_state(pdev, device_state); return 0; @@ -1807,7 +1822,6 @@ mpt_resume(struct pci_dev *pdev) MPT_ADAPTER *ioc = pci_get_drvdata(pdev); u32 device_state = pdev->current_state; int recovery_state; - int err; printk(MYIOC_s_INFO_FMT "pci-resume: pdev=0x%p, slot=%s, Previous operating state [D%d]\n", @@ -1815,9 +1829,18 @@ mpt_resume(struct pci_dev *pdev) pci_set_power_state(pdev, 0); pci_restore_state(pdev); - err = pci_enable_device(pdev); - if (err) - return err; + if (ioc->facts.Flags & MPI_IOCFACTS_FLAGS_FW_DOWNLOAD_BOOT) { + ioc->bars = pci_select_bars(ioc->pcidev, IORESOURCE_MEM | + IORESOURCE_IO); + if (pci_enable_device(pdev)) + return 0; + } else { + ioc->bars = pci_select_bars(pdev, IORESOURCE_MEM); + if (pci_enable_device_mem(pdev)) + return 0; + } + if (pci_request_selected_regions(pdev, ioc->bars, "mpt")) + return 0; /* enable interrupts */ CHIPREG_WRITE32(&ioc->chip->IntMask, MPI_HIM_DIM); @@ -1878,6 +1901,7 @@ mpt_signal_reset(u8 index, MPT_ADAPTER *ioc, int reset_phase) * -2 if READY but IOCFacts Failed * -3 if READY but PrimeIOCFifos Failed * -4 if READY but IOCInit Failed + * -5 if failed to enable_device and/or request_selected_regions */ static int mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u32 reason, int sleepFlag) @@ -1976,6 +2000,18 @@ mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u32 reason, int sleepFlag) } } + if ((ret == 0) && (reason == MPT_HOSTEVENT_IOC_BRINGUP) && + (ioc->facts.Flags & MPI_IOCFACTS_FLAGS_FW_DOWNLOAD_BOOT)) { + pci_release_selected_regions(ioc->pcidev, ioc->bars); + ioc->bars = pci_select_bars(ioc->pcidev, IORESOURCE_MEM | + IORESOURCE_IO); + if (pci_enable_device(ioc->pcidev)) + return -5; + if (pci_request_selected_regions(ioc->pcidev, ioc->bars, + "mpt")) + return -5; + } + /* * Device is reset now. It must have de-asserted the interrupt line * (if it was asserted) and it should be safe to register for the @@ -1999,7 +2035,6 @@ mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u32 reason, int sleepFlag) irq_allocated = 1; ioc->pci_irq = ioc->pcidev->irq; pci_set_master(ioc->pcidev); /* ?? */ - pci_set_drvdata(ioc->pcidev, ioc); dprintk(ioc, printk(MYIOC_s_INFO_FMT "installed at interrupt " "%d\n", ioc->name, ioc->pcidev->irq)); } @@ -2381,6 +2416,9 @@ mpt_adapter_dispose(MPT_ADAPTER *ioc) ioc->memmap = NULL; } + pci_disable_device(ioc->pcidev); + pci_release_selected_regions(ioc->pcidev, ioc->bars); + #if defined(CONFIG_MTRR) && 0 if (ioc->mtrr_reg > 0) { mtrr_del(ioc->mtrr_reg, 0, 0); diff --git a/drivers/message/fusion/mptbase.h b/drivers/message/fusion/mptbase.h index b49b706c002..d83ea96fe13 100644 --- a/drivers/message/fusion/mptbase.h +++ b/drivers/message/fusion/mptbase.h @@ -629,6 +629,7 @@ typedef struct _MPT_ADAPTER dma_addr_t HostPageBuffer_dma; int mtrr_reg; struct pci_dev *pcidev; /* struct pci_dev pointer */ + int bars; /* bitmask of BAR's that must be configured */ u8 __iomem *memmap; /* mmap address */ struct Scsi_Host *sh; /* Scsi Host pointer */ SpiCfgData spi_data; /* Scsi config. data */ diff --git a/drivers/misc/thinkpad_acpi.c b/drivers/misc/thinkpad_acpi.c index 7ba1acad540..e2c7edd206a 100644 --- a/drivers/misc/thinkpad_acpi.c +++ b/drivers/misc/thinkpad_acpi.c @@ -1689,7 +1689,7 @@ static ssize_t hotkey_wakeup_reason_show(struct device *dev, static struct device_attribute dev_attr_hotkey_wakeup_reason = __ATTR(wakeup_reason, S_IRUGO, hotkey_wakeup_reason_show, NULL); -void hotkey_wakeup_reason_notify_change(void) +static void hotkey_wakeup_reason_notify_change(void) { if (tp_features.hotkey_mask) sysfs_notify(&tpacpi_pdev->dev.kobj, NULL, @@ -1708,7 +1708,7 @@ static struct device_attribute dev_attr_hotkey_wakeup_hotunplug_complete = __ATTR(wakeup_hotunplug_complete, S_IRUGO, hotkey_wakeup_hotunplug_complete_show, NULL); -void hotkey_wakeup_hotunplug_complete_notify_change(void) +static void hotkey_wakeup_hotunplug_complete_notify_change(void) { if (tp_features.hotkey_mask) sysfs_notify(&tpacpi_pdev->dev.kobj, NULL, diff --git a/drivers/mtd/mtdsuper.c b/drivers/mtd/mtdsuper.c index 9b430f20b64..28cc6787a80 100644 --- a/drivers/mtd/mtdsuper.c +++ b/drivers/mtd/mtdsuper.c @@ -184,26 +184,26 @@ int get_sb_mtd(struct file_system_type *fs_type, int flags, ret = path_lookup(dev_name, LOOKUP_FOLLOW, &nd); DEBUG(1, "MTDSB: path_lookup() returned %d, inode %p\n", - ret, nd.dentry ? nd.dentry->d_inode : NULL); + ret, nd.path.dentry ? nd.path.dentry->d_inode : NULL); if (ret) return ret; ret = -EINVAL; - if (!S_ISBLK(nd.dentry->d_inode->i_mode)) + if (!S_ISBLK(nd.path.dentry->d_inode->i_mode)) goto out; - if (nd.mnt->mnt_flags & MNT_NODEV) { + if (nd.path.mnt->mnt_flags & MNT_NODEV) { ret = -EACCES; goto out; } - if (imajor(nd.dentry->d_inode) != MTD_BLOCK_MAJOR) + if (imajor(nd.path.dentry->d_inode) != MTD_BLOCK_MAJOR) goto not_an_MTD_device; - mtdnr = iminor(nd.dentry->d_inode); - path_release(&nd); + mtdnr = iminor(nd.path.dentry->d_inode); + path_put(&nd.path); return get_sb_mtd_nr(fs_type, flags, dev_name, data, mtdnr, fill_super, mnt); @@ -214,7 +214,7 @@ not_an_MTD_device: "MTD: Attempt to mount non-MTD device \"%s\"\n", dev_name); out: - path_release(&nd); + path_put(&nd.path); return ret; } diff --git a/drivers/net/8139too.c b/drivers/net/8139too.c index eef6fecfff2..be6e918456d 100644 --- a/drivers/net/8139too.c +++ b/drivers/net/8139too.c @@ -168,7 +168,7 @@ static int debug = -1; * Warning: 64K ring has hardware issues and may lock up. */ #if defined(CONFIG_SH_DREAMCAST) -#define RX_BUF_IDX 1 /* 16K ring */ +#define RX_BUF_IDX 0 /* 8K ring */ #else #define RX_BUF_IDX 2 /* 32K ring */ #endif diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index 50c2b60e1fe..f337800076c 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -931,6 +931,14 @@ config ENC28J60_WRITEVERIFY Enable the verify after the buffer write useful for debugging purpose. If unsure, say N. +config DM9000_DEBUGLEVEL + int "DM9000 maximum debug level" + depends on DM9000 + default 4 + help + The maximum level of debugging code compiled into the DM9000 + driver. + config SMC911X tristate "SMSC LAN911[5678] support" select CRC32 @@ -2352,6 +2360,16 @@ config GELIC_NET To compile this driver as a module, choose M here: the module will be called ps3_gelic. +config GELIC_WIRELESS + bool "PS3 Wireless support" + depends on GELIC_NET + help + This option adds the support for the wireless feature of PS3. + If you have the wireless-less model of PS3 or have no plan to + use wireless feature, disabling this option saves memory. As + the driver automatically distinguishes the models, you can + safely enable this option even if you have a wireless-less model. + config GIANFAR tristate "Gianfar Ethernet" depends on FSL_SOC diff --git a/drivers/net/Makefile b/drivers/net/Makefile index 9fc7794e88e..3b1ea321dc0 100644 --- a/drivers/net/Makefile +++ b/drivers/net/Makefile @@ -70,7 +70,8 @@ obj-$(CONFIG_BNX2X) += bnx2x.o spidernet-y += spider_net.o spider_net_ethtool.o obj-$(CONFIG_SPIDER_NET) += spidernet.o sungem_phy.o obj-$(CONFIG_GELIC_NET) += ps3_gelic.o -ps3_gelic-objs += ps3_gelic_net.o +gelic_wireless-$(CONFIG_GELIC_WIRELESS) += ps3_gelic_wireless.o +ps3_gelic-objs += ps3_gelic_net.o $(gelic_wireless-y) obj-$(CONFIG_TC35815) += tc35815.o obj-$(CONFIG_SKGE) += skge.o obj-$(CONFIG_SKY2) += sky2.o diff --git a/drivers/net/cxgb3/l2t.c b/drivers/net/cxgb3/l2t.c index 17ed4c3527b..865faee53e1 100644 --- a/drivers/net/cxgb3/l2t.c +++ b/drivers/net/cxgb3/l2t.c @@ -404,7 +404,7 @@ found: if (neigh->nud_state & NUD_FAILED) { arpq = e->arpq_head; e->arpq_head = e->arpq_tail = NULL; - } else if (neigh_is_connected(neigh)) + } else if (neigh->nud_state & (NUD_CONNECTED|NUD_STALE)) setup_l2e_send_pending(dev, NULL, e); } else { e->state = neigh_is_connected(neigh) ? diff --git a/drivers/net/cxgb3/sge.c b/drivers/net/cxgb3/sge.c index 9ca8c66abd1..979f3fc5e76 100644 --- a/drivers/net/cxgb3/sge.c +++ b/drivers/net/cxgb3/sge.c @@ -1059,6 +1059,14 @@ static void write_tx_pkt_wr(struct adapter *adap, struct sk_buff *skb, htonl(V_WR_TID(q->token))); } +static inline void t3_stop_queue(struct net_device *dev, struct sge_qset *qs, + struct sge_txq *q) +{ + netif_stop_queue(dev); + set_bit(TXQ_ETH, &qs->txq_stopped); + q->stops++; +} + /** * eth_xmit - add a packet to the Ethernet Tx queue * @skb: the packet @@ -1090,31 +1098,18 @@ int t3_eth_xmit(struct sk_buff *skb, struct net_device *dev) ndesc = calc_tx_descs(skb); if (unlikely(credits < ndesc)) { - if (!netif_queue_stopped(dev)) { - netif_stop_queue(dev); - set_bit(TXQ_ETH, &qs->txq_stopped); - q->stops++; - dev_err(&adap->pdev->dev, - "%s: Tx ring %u full while queue awake!\n", - dev->name, q->cntxt_id & 7); - } + t3_stop_queue(dev, qs, q); + dev_err(&adap->pdev->dev, + "%s: Tx ring %u full while queue awake!\n", + dev->name, q->cntxt_id & 7); spin_unlock(&q->lock); return NETDEV_TX_BUSY; } q->in_use += ndesc; - if (unlikely(credits - ndesc < q->stop_thres)) { - q->stops++; - netif_stop_queue(dev); - set_bit(TXQ_ETH, &qs->txq_stopped); -#if !USE_GTS - if (should_restart_tx(q) && - test_and_clear_bit(TXQ_ETH, &qs->txq_stopped)) { - q->restarts++; - netif_wake_queue(dev); - } -#endif - } + if (unlikely(credits - ndesc < q->stop_thres)) + if (USE_GTS || !should_restart_tx(q)) + t3_stop_queue(dev, qs, q); gen = q->gen; q->unacked += ndesc; diff --git a/drivers/net/dm9000.c b/drivers/net/dm9000.c index 6a20a5491a9..1fe305ca2cf 100644 --- a/drivers/net/dm9000.c +++ b/drivers/net/dm9000.c @@ -1,7 +1,5 @@ /* - * dm9000.c: Version 1.2 03/18/2003 - * - * A Davicom DM9000 ISA NIC fast Ethernet driver for Linux. + * Davicom DM9000 Fast Ethernet driver for Linux. * Copyright (C) 1997 Sten Wang * * This program is free software; you can redistribute it and/or @@ -14,44 +12,11 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * (C)Copyright 1997-1998 DAVICOM Semiconductor,Inc. All Rights Reserved. - * - * V0.11 06/20/2001 REG_0A bit3=1, default enable BP with DA match - * 06/22/2001 Support DM9801 progrmming - * E3: R25 = ((R24 + NF) & 0x00ff) | 0xf000 - * E4: R25 = ((R24 + NF) & 0x00ff) | 0xc200 - * R17 = (R17 & 0xfff0) | NF + 3 - * E5: R25 = ((R24 + NF - 3) & 0x00ff) | 0xc200 - * R17 = (R17 & 0xfff0) | NF - * - * v1.00 modify by simon 2001.9.5 - * change for kernel 2.4.x - * - * v1.1 11/09/2001 fix force mode bug - * - * v1.2 03/18/2003 Weilun Huang <weilun_huang@davicom.com.tw>: - * Fixed phy reset. - * Added tx/rx 32 bit mode. - * Cleaned up for kernel merge. - * - * 03/03/2004 Sascha Hauer <s.hauer@pengutronix.de> - * Port to 2.6 kernel - * - * 24-Sep-2004 Ben Dooks <ben@simtec.co.uk> - * Cleanup of code to remove ifdefs - * Allowed platform device data to influence access width - * Reformatting areas of code - * - * 17-Mar-2005 Sascha Hauer <s.hauer@pengutronix.de> - * * removed 2.4 style module parameters - * * removed removed unused stat counter and fixed - * net_device_stats - * * introduced tx_timeout function - * * reworked locking + * (C) Copyright 1997-1998 DAVICOM Semiconductor,Inc. All Rights Reserved. * - * 01-Jul-2005 Ben Dooks <ben@simtec.co.uk> - * * fixed spinlock call without pointer - * * ensure spinlock is initialised + * Additional updates, Copyright: + * Ben Dooks <ben@simtec.co.uk> + * Sascha Hauer <s.hauer@pengutronix.de> */ #include <linux/module.h> @@ -63,6 +28,7 @@ #include <linux/spinlock.h> #include <linux/crc32.h> #include <linux/mii.h> +#include <linux/ethtool.h> #include <linux/dm9000.h> #include <linux/delay.h> #include <linux/platform_device.h> @@ -80,30 +46,7 @@ #define CARDNAME "dm9000" #define PFX CARDNAME ": " - -#define DM9000_TIMER_WUT jiffies+(HZ*2) /* timer wakeup time : 2 second */ - -#define DM9000_DEBUG 0 - -#if DM9000_DEBUG > 2 -#define PRINTK3(args...) printk(CARDNAME ": " args) -#else -#define PRINTK3(args...) do { } while(0) -#endif - -#if DM9000_DEBUG > 1 -#define PRINTK2(args...) printk(CARDNAME ": " args) -#else -#define PRINTK2(args...) do { } while(0) -#endif - -#if DM9000_DEBUG > 0 -#define PRINTK1(args...) printk(CARDNAME ": " args) -#define PRINTK(args...) printk(CARDNAME ": " args) -#else -#define PRINTK1(args...) do { } while(0) -#define PRINTK(args...) printk(KERN_DEBUG args) -#endif +#define DRV_VERSION "1.30" #ifdef CONFIG_BLACKFIN #define readsb insb @@ -112,9 +55,9 @@ #define writesb outsb #define writesw outsw #define writesl outsl -#define DM9000_IRQ_FLAGS (IRQF_SHARED | IRQF_TRIGGER_HIGH) +#define DEFAULT_TRIGGER IRQF_TRIGGER_HIGH #else -#define DM9000_IRQ_FLAGS (IRQF_SHARED | IRQT_RISING) +#define DEFAULT_TRIGGER (0) #endif /* @@ -124,6 +67,24 @@ static int watchdog = 5000; module_param(watchdog, int, 0400); MODULE_PARM_DESC(watchdog, "transmit timeout in milliseconds"); +/* DM9000 register address locking. + * + * The DM9000 uses an address register to control where data written + * to the data register goes. This means that the address register + * must be preserved over interrupts or similar calls. + * + * During interrupt and other critical calls, a spinlock is used to + * protect the system, but the calls themselves save the address + * in the address register in case they are interrupting another + * access to the device. + * + * For general accesses a lock is provided so that calls which are + * allowed to sleep are serialised so that the address register does + * not need to be saved. This lock also serves to serialise access + * to the EEPROM and PHY access registers which are shared between + * these two devices. + */ + /* Structure/enum declaration ------------------------------- */ typedef struct board_info { @@ -137,33 +98,52 @@ typedef struct board_info { u16 dbug_cnt; u8 io_mode; /* 0:word, 2:byte */ u8 phy_addr; + unsigned int flags; + unsigned int in_suspend :1; + + int debug_level; void (*inblk)(void __iomem *port, void *data, int length); void (*outblk)(void __iomem *port, void *data, int length); void (*dumpblk)(void __iomem *port, int length); + struct device *dev; /* parent device */ + struct resource *addr_res; /* resources found */ struct resource *data_res; struct resource *addr_req; /* resources requested */ struct resource *data_req; struct resource *irq_res; - struct timer_list timer; - unsigned char srom[128]; + struct mutex addr_lock; /* phy and eeprom access lock */ + spinlock_t lock; struct mii_if_info mii; u32 msg_enable; } board_info_t; +/* debug code */ + +#define dm9000_dbg(db, lev, msg...) do { \ + if ((lev) < CONFIG_DM9000_DEBUGLEVEL && \ + (lev) < db->debug_level) { \ + dev_dbg(db->dev, msg); \ + } \ +} while (0) + +static inline board_info_t *to_dm9000_board(struct net_device *dev) +{ + return dev->priv; +} + /* function declaration ------------------------------------- */ static int dm9000_probe(struct platform_device *); static int dm9000_open(struct net_device *); static int dm9000_start_xmit(struct sk_buff *, struct net_device *); static int dm9000_stop(struct net_device *); +static int dm9000_ioctl(struct net_device *dev, struct ifreq *req, int cmd); - -static void dm9000_timer(unsigned long); static void dm9000_init_dm9000(struct net_device *); static irqreturn_t dm9000_interrupt(int, void *); @@ -171,20 +151,19 @@ static irqreturn_t dm9000_interrupt(int, void *); static int dm9000_phy_read(struct net_device *dev, int phyaddr_unsused, int reg); static void dm9000_phy_write(struct net_device *dev, int phyaddr_unused, int reg, int value); -static u16 read_srom_word(board_info_t *, int); + +static void dm9000_read_eeprom(board_info_t *, int addr, u8 *to); +static void dm9000_write_eeprom(board_info_t *, int addr, u8 *dp); static void dm9000_rx(struct net_device *); static void dm9000_hash_table(struct net_device *); -//#define DM9000_PROGRAM_EEPROM -#ifdef DM9000_PROGRAM_EEPROM -static void program_eeprom(board_info_t * db); -#endif /* DM9000 network board routine ---------------------------- */ static void dm9000_reset(board_info_t * db) { - PRINTK1("dm9000x: resetting\n"); + dev_dbg(db->dev, "resetting device\n"); + /* RESET device */ writeb(DM9000_NCR, db->io_addr); udelay(200); @@ -300,14 +279,10 @@ static void dm9000_set_io(struct board_info *db, int byte_width) db->inblk = dm9000_inblk_8bit; break; - case 2: - db->dumpblk = dm9000_dumpblk_16bit; - db->outblk = dm9000_outblk_16bit; - db->inblk = dm9000_inblk_16bit; - break; case 3: - printk(KERN_ERR PFX ": 3 byte IO, falling back to 16bit\n"); + dev_dbg(db->dev, ": 3 byte IO, falling back to 16bit\n"); + case 2: db->dumpblk = dm9000_dumpblk_16bit; db->outblk = dm9000_outblk_16bit; db->inblk = dm9000_inblk_16bit; @@ -358,6 +333,139 @@ static void dm9000_poll_controller(struct net_device *dev) } #endif +static int dm9000_ioctl(struct net_device *dev, struct ifreq *req, int cmd) +{ + board_info_t *dm = to_dm9000_board(dev); + + if (!netif_running(dev)) + return -EINVAL; + + return generic_mii_ioctl(&dm->mii, if_mii(req), cmd, NULL); +} + +/* ethtool ops */ + +static void dm9000_get_drvinfo(struct net_device *dev, + struct ethtool_drvinfo *info) +{ + board_info_t *dm = to_dm9000_board(dev); + + strcpy(info->driver, CARDNAME); + strcpy(info->version, DRV_VERSION); + strcpy(info->bus_info, to_platform_device(dm->dev)->name); +} + +static u32 dm9000_get_msglevel(struct net_device *dev) +{ + board_info_t *dm = to_dm9000_board(dev); + + return dm->msg_enable; +} + +static void dm9000_set_msglevel(struct net_device *dev, u32 value) +{ + board_info_t *dm = to_dm9000_board(dev); + + dm->msg_enable = value; +} + +static int dm9000_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) +{ + board_info_t *dm = to_dm9000_board(dev); + + mii_ethtool_gset(&dm->mii, cmd); + return 0; +} + +static int dm9000_set_settings(struct net_device *dev, struct ethtool_cmd *cmd) +{ + board_info_t *dm = to_dm9000_board(dev); + + return mii_ethtool_sset(&dm->mii, cmd); +} + +static int dm9000_nway_reset(struct net_device *dev) +{ + board_info_t *dm = to_dm9000_board(dev); + return mii_nway_restart(&dm->mii); +} + +static u32 dm9000_get_link(struct net_device *dev) +{ + board_info_t *dm = to_dm9000_board(dev); + return mii_link_ok(&dm->mii); +} + +#define DM_EEPROM_MAGIC (0x444D394B) + +static int dm9000_get_eeprom_len(struct net_device *dev) +{ + return 128; +} + +static int dm9000_get_eeprom(struct net_device *dev, + struct ethtool_eeprom *ee, u8 *data) +{ + board_info_t *dm = to_dm9000_board(dev); + int offset = ee->offset; + int len = ee->len; + int i; + + /* EEPROM access is aligned to two bytes */ + + if ((len & 1) != 0 || (offset & 1) != 0) + return -EINVAL; + + if (dm->flags & DM9000_PLATF_NO_EEPROM) + return -ENOENT; + + ee->magic = DM_EEPROM_MAGIC; + + for (i = 0; i < len; i += 2) + dm9000_read_eeprom(dm, (offset + i) / 2, data + i); + + return 0; +} + +static int dm9000_set_eeprom(struct net_device *dev, + struct ethtool_eeprom *ee, u8 *data) +{ + board_info_t *dm = to_dm9000_board(dev); + int offset = ee->offset; + int len = ee->len; + int i; + + /* EEPROM access is aligned to two bytes */ + + if ((len & 1) != 0 || (offset & 1) != 0) + return -EINVAL; + + if (dm->flags & DM9000_PLATF_NO_EEPROM) + return -ENOENT; + + if (ee->magic != DM_EEPROM_MAGIC) + return -EINVAL; + + for (i = 0; i < len; i += 2) + dm9000_write_eeprom(dm, (offset + i) / 2, data + i); + + return 0; +} + +static const struct ethtool_ops dm9000_ethtool_ops = { + .get_drvinfo = dm9000_get_drvinfo, + .get_settings = dm9000_get_settings, + .set_settings = dm9000_set_settings, + .get_msglevel = dm9000_get_msglevel, + .set_msglevel = dm9000_set_msglevel, + .nway_reset = dm9000_nway_reset, + .get_link = dm9000_get_link, + .get_eeprom_len = dm9000_get_eeprom_len, + .get_eeprom = dm9000_get_eeprom, + .set_eeprom = dm9000_set_eeprom, +}; + + /* dm9000_release_board * * release a board, and any mapped resources @@ -401,6 +509,7 @@ dm9000_probe(struct platform_device *pdev) struct dm9000_plat_data *pdata = pdev->dev.platform_data; struct board_info *db; /* Point a board information structure */ struct net_device *ndev; + const unsigned char *mac_src; unsigned long base; int ret = 0; int iosize; @@ -410,19 +519,22 @@ dm9000_probe(struct platform_device *pdev) /* Init network device */ ndev = alloc_etherdev(sizeof (struct board_info)); if (!ndev) { - printk("%s: could not allocate device.\n", CARDNAME); + dev_err(&pdev->dev, "could not allocate device.\n"); return -ENOMEM; } SET_NETDEV_DEV(ndev, &pdev->dev); - PRINTK2("dm9000_probe()"); + dev_dbg(&pdev->dev, "dm9000_probe()"); /* setup board info structure */ db = (struct board_info *) ndev->priv; memset(db, 0, sizeof (*db)); + db->dev = &pdev->dev; + spin_lock_init(&db->lock); + mutex_init(&db->addr_lock); if (pdev->num_resources < 2) { ret = -ENODEV; @@ -450,7 +562,7 @@ dm9000_probe(struct platform_device *pdev) if (db->addr_res == NULL || db->data_res == NULL || db->irq_res == NULL) { - printk(KERN_ERR PFX "insufficient resources\n"); + dev_err(db->dev, "insufficient resources\n"); ret = -ENOENT; goto out; } @@ -460,7 +572,7 @@ dm9000_probe(struct platform_device *pdev) pdev->name); if (db->addr_req == NULL) { - printk(KERN_ERR PFX "cannot claim address reg area\n"); + dev_err(db->dev, "cannot claim address reg area\n"); ret = -EIO; goto out; } @@ -468,7 +580,7 @@ dm9000_probe(struct platform_device *pdev) db->io_addr = ioremap(db->addr_res->start, i); if (db->io_addr == NULL) { - printk(KERN_ERR "failed to ioremap address reg\n"); + dev_err(db->dev, "failed to ioremap address reg\n"); ret = -EINVAL; goto out; } @@ -478,7 +590,7 @@ dm9000_probe(struct platform_device *pdev) pdev->name); if (db->data_req == NULL) { - printk(KERN_ERR PFX "cannot claim data reg area\n"); + dev_err(db->dev, "cannot claim data reg area\n"); ret = -EIO; goto out; } @@ -486,7 +598,7 @@ dm9000_probe(struct platform_device *pdev) db->io_data = ioremap(db->data_res->start, iosize); if (db->io_data == NULL) { - printk(KERN_ERR "failed to ioremap data reg\n"); + dev_err(db->dev,"failed to ioremap data reg\n"); ret = -EINVAL; goto out; } @@ -525,12 +637,14 @@ dm9000_probe(struct platform_device *pdev) if (pdata->dumpblk != NULL) db->dumpblk = pdata->dumpblk; + + db->flags = pdata->flags; } dm9000_reset(db); /* try two times, DM9000 sometimes gets the first read wrong */ - for (i = 0; i < 2; i++) { + for (i = 0; i < 8; i++) { id_val = ior(db, DM9000_VIDL); id_val |= (u32)ior(db, DM9000_VIDH) << 8; id_val |= (u32)ior(db, DM9000_PIDL) << 16; @@ -538,11 +652,11 @@ dm9000_probe(struct platform_device *pdev) if (id_val == DM9000_ID) break; - printk("%s: read wrong id 0x%08x\n", CARDNAME, id_val); + dev_err(db->dev, "read wrong id 0x%08x\n", id_val); } if (id_val != DM9000_ID) { - printk("%s: wrong id: 0x%08x\n", CARDNAME, id_val); + dev_err(db->dev, "wrong id: 0x%08x\n", id_val); ret = -ENODEV; goto out; } @@ -558,13 +672,13 @@ dm9000_probe(struct platform_device *pdev) ndev->watchdog_timeo = msecs_to_jiffies(watchdog); ndev->stop = &dm9000_stop; ndev->set_multicast_list = &dm9000_hash_table; + ndev->ethtool_ops = &dm9000_ethtool_ops; + ndev->do_ioctl = &dm9000_ioctl; + #ifdef CONFIG_NET_POLL_CONTROLLER ndev->poll_controller = &dm9000_poll_controller; #endif -#ifdef DM9000_PROGRAM_EEPROM - program_eeprom(db); -#endif db->msg_enable = NETIF_MSG_LINK; db->mii.phy_id_mask = 0x1f; db->mii.reg_num_mask = 0x1f; @@ -574,38 +688,37 @@ dm9000_probe(struct platform_device *pdev) db->mii.mdio_read = dm9000_phy_read; db->mii.mdio_write = dm9000_phy_write; - /* Read SROM content */ - for (i = 0; i < 64; i++) - ((u16 *) db->srom)[i] = read_srom_word(db, i); + mac_src = "eeprom"; - /* Set Node Address */ - for (i = 0; i < 6; i++) - ndev->dev_addr[i] = db->srom[i]; + /* try reading the node address from the attached EEPROM */ + for (i = 0; i < 6; i += 2) + dm9000_read_eeprom(db, i / 2, ndev->dev_addr+i); if (!is_valid_ether_addr(ndev->dev_addr)) { /* try reading from mac */ - + + mac_src = "chip"; for (i = 0; i < 6; i++) ndev->dev_addr[i] = ior(db, i+DM9000_PAR); } if (!is_valid_ether_addr(ndev->dev_addr)) - printk("%s: Invalid ethernet MAC address. Please " - "set using ifconfig\n", ndev->name); + dev_warn(db->dev, "%s: Invalid ethernet MAC address. Please " + "set using ifconfig\n", ndev->name); platform_set_drvdata(pdev, ndev); ret = register_netdev(ndev); if (ret == 0) { DECLARE_MAC_BUF(mac); - printk("%s: dm9000 at %p,%p IRQ %d MAC: %s\n", + printk("%s: dm9000 at %p,%p IRQ %d MAC: %s (%s)\n", ndev->name, db->io_addr, db->io_data, ndev->irq, - print_mac(mac, ndev->dev_addr)); + print_mac(mac, ndev->dev_addr), mac_src); } return 0; out: - printk("%s: not found (%d).\n", CARDNAME, ret); + dev_err(db->dev, "not found (%d).\n", ret); dm9000_release_board(pdev, db); free_netdev(ndev); @@ -621,10 +734,22 @@ static int dm9000_open(struct net_device *dev) { board_info_t *db = (board_info_t *) dev->priv; + unsigned long irqflags = db->irq_res->flags & IRQF_TRIGGER_MASK; - PRINTK2("entering dm9000_open\n"); + if (netif_msg_ifup(db)) + dev_dbg(db->dev, "enabling %s\n", dev->name); - if (request_irq(dev->irq, &dm9000_interrupt, DM9000_IRQ_FLAGS, dev->name, dev)) + /* If there is no IRQ type specified, default to something that + * may work, and tell the user that this is a problem */ + + if (irqflags == IRQF_TRIGGER_NONE) { + dev_warn(db->dev, "WARNING: no IRQ resource flags set.\n"); + irqflags = DEFAULT_TRIGGER; + } + + irqflags |= IRQF_SHARED; + + if (request_irq(dev->irq, &dm9000_interrupt, irqflags, dev->name, dev)) return -EAGAIN; /* Initialize DM9000 board */ @@ -634,13 +759,6 @@ dm9000_open(struct net_device *dev) /* Init driver variable */ db->dbug_cnt = 0; - /* set and active a timer process */ - init_timer(&db->timer); - db->timer.expires = DM9000_TIMER_WUT; - db->timer.data = (unsigned long) dev; - db->timer.function = &dm9000_timer; - add_timer(&db->timer); - mii_check_media(&db->mii, netif_msg_link(db), 1); netif_start_queue(dev); @@ -655,7 +773,7 @@ dm9000_init_dm9000(struct net_device *dev) { board_info_t *db = (board_info_t *) dev->priv; - PRINTK1("entering %s\n",__FUNCTION__); + dm9000_dbg(db, 1, "entering %s\n", __func__); /* I/O mode */ db->io_mode = ior(db, DM9000_ISR) >> 6; /* ISR bit7:6 keeps I/O mode */ @@ -665,6 +783,9 @@ dm9000_init_dm9000(struct net_device *dev) iow(db, DM9000_GPCR, GPCR_GEP_CNTL); /* Let GPIO0 output */ iow(db, DM9000_GPR, 0); /* Enable PHY */ + if (db->flags & DM9000_PLATF_EXT_PHY) + iow(db, DM9000_NCR, NCR_EXT_PHY); + /* Program operating register */ iow(db, DM9000_TCR, 0); /* TX Polling clear */ iow(db, DM9000_BPTR, 0x3f); /* Less 3Kb, 200us */ @@ -698,7 +819,7 @@ dm9000_start_xmit(struct sk_buff *skb, struct net_device *dev) unsigned long flags; board_info_t *db = (board_info_t *) dev->priv; - PRINTK3("dm9000_start_xmit\n"); + dm9000_dbg(db, 3, "%s:\n", __func__); if (db->tx_pkt_cnt > 1) return 1; @@ -715,8 +836,8 @@ dm9000_start_xmit(struct sk_buff *skb, struct net_device *dev) /* TX control: First packet immediately send, second packet queue */ if (db->tx_pkt_cnt == 1) { /* Set TX length to DM9000 */ - iow(db, DM9000_TXPLL, skb->len & 0xff); - iow(db, DM9000_TXPLH, (skb->len >> 8) & 0xff); + iow(db, DM9000_TXPLL, skb->len); + iow(db, DM9000_TXPLH, skb->len >> 8); /* Issue TX polling command */ iow(db, DM9000_TCR, TCR_TXREQ); /* Cleared after TX complete */ @@ -757,10 +878,8 @@ dm9000_stop(struct net_device *ndev) { board_info_t *db = (board_info_t *) ndev->priv; - PRINTK1("entering %s\n",__FUNCTION__); - - /* deleted timer */ - del_timer(&db->timer); + if (netif_msg_ifdown(db)) + dev_dbg(db->dev, "shutting down %s\n", ndev->name); netif_stop_queue(ndev); netif_carrier_off(ndev); @@ -788,10 +907,13 @@ dm9000_tx_done(struct net_device *dev, board_info_t * db) db->tx_pkt_cnt--; dev->stats.tx_packets++; + if (netif_msg_tx_done(db)) + dev_dbg(db->dev, "tx done, NSR %02x\n", tx_status); + /* Queue packet check & send */ if (db->tx_pkt_cnt > 0) { - iow(db, DM9000_TXPLL, db->queue_pkt_len & 0xff); - iow(db, DM9000_TXPLH, (db->queue_pkt_len >> 8) & 0xff); + iow(db, DM9000_TXPLL, db->queue_pkt_len); + iow(db, DM9000_TXPLH, db->queue_pkt_len >> 8); iow(db, DM9000_TCR, TCR_TXREQ); dev->trans_start = jiffies; } @@ -803,19 +925,14 @@ static irqreturn_t dm9000_interrupt(int irq, void *dev_id) { struct net_device *dev = dev_id; - board_info_t *db; + board_info_t *db = (board_info_t *) dev->priv; int int_status; u8 reg_save; - PRINTK3("entering %s\n",__FUNCTION__); - - if (!dev) { - PRINTK1("dm9000_interrupt() without DEVICE arg\n"); - return IRQ_HANDLED; - } + dm9000_dbg(db, 3, "entering %s\n", __func__); /* A real interrupt coming */ - db = (board_info_t *) dev->priv; + spin_lock(&db->lock); /* Save previous register address */ @@ -828,6 +945,9 @@ dm9000_interrupt(int irq, void *dev_id) int_status = ior(db, DM9000_ISR); /* Got ISR */ iow(db, DM9000_ISR, int_status); /* Clear ISR status */ + if (netif_msg_intr(db)) + dev_dbg(db->dev, "interrupt status %02x\n", int_status); + /* Received the coming packet */ if (int_status & ISR_PRS) dm9000_rx(dev); @@ -847,27 +967,9 @@ dm9000_interrupt(int irq, void *dev_id) return IRQ_HANDLED; } -/* - * A periodic timer routine - * Dynamic media sense, allocated Rx buffer... - */ -static void -dm9000_timer(unsigned long data) -{ - struct net_device *dev = (struct net_device *) data; - board_info_t *db = (board_info_t *) dev->priv; - - PRINTK3("dm9000_timer()\n"); - - mii_check_media(&db->mii, netif_msg_link(db), 0); - - /* Set timer again */ - db->timer.expires = DM9000_TIMER_WUT; - add_timer(&db->timer); -} - struct dm9000_rxhdr { - u16 RxStatus; + u8 RxPktReady; + u8 RxStatus; u16 RxLen; } __attribute__((__packed__)); @@ -893,7 +995,7 @@ dm9000_rx(struct net_device *dev) /* Status check: this byte must be 0 or 1 */ if (rxbyte > DM9000_PKT_RDY) { - printk("status check failed: %d\n", rxbyte); + dev_warn(db->dev, "status check fail: %d\n", rxbyte); iow(db, DM9000_RCR, 0x00); /* Stop Device */ iow(db, DM9000_ISR, IMR_PAR); /* Stop INT request */ return; @@ -908,30 +1010,38 @@ dm9000_rx(struct net_device *dev) (db->inblk)(db->io_data, &rxhdr, sizeof(rxhdr)); - RxLen = rxhdr.RxLen; + RxLen = le16_to_cpu(rxhdr.RxLen); + + if (netif_msg_rx_status(db)) + dev_dbg(db->dev, "RX: status %02x, length %04x\n", + rxhdr.RxStatus, RxLen); /* Packet Status check */ if (RxLen < 0x40) { GoodPacket = false; - PRINTK1("Bad Packet received (runt)\n"); + if (netif_msg_rx_err(db)) + dev_dbg(db->dev, "RX: Bad Packet (runt)\n"); } if (RxLen > DM9000_PKT_MAX) { - PRINTK1("RST: RX Len:%x\n", RxLen); + dev_dbg(db->dev, "RST: RX Len:%x\n", RxLen); } - if (rxhdr.RxStatus & 0xbf00) { + if (rxhdr.RxStatus & 0xbf) { GoodPacket = false; - if (rxhdr.RxStatus & 0x100) { - PRINTK1("fifo error\n"); + if (rxhdr.RxStatus & 0x01) { + if (netif_msg_rx_err(db)) + dev_dbg(db->dev, "fifo error\n"); dev->stats.rx_fifo_errors++; } - if (rxhdr.RxStatus & 0x200) { - PRINTK1("crc error\n"); + if (rxhdr.RxStatus & 0x02) { + if (netif_msg_rx_err(db)) + dev_dbg(db->dev, "crc error\n"); dev->stats.rx_crc_errors++; } - if (rxhdr.RxStatus & 0x8000) { - PRINTK1("length error\n"); + if (rxhdr.RxStatus & 0x80) { + if (netif_msg_rx_err(db)) + dev_dbg(db->dev, "length error\n"); dev->stats.rx_length_errors++; } } @@ -960,72 +1070,119 @@ dm9000_rx(struct net_device *dev) } while (rxbyte == DM9000_PKT_RDY); } -/* - * Read a word data from SROM - */ -static u16 -read_srom_word(board_info_t * db, int offset) +static unsigned int +dm9000_read_locked(board_info_t *db, int reg) { - iow(db, DM9000_EPAR, offset); - iow(db, DM9000_EPCR, EPCR_ERPRR); - mdelay(8); /* according to the datasheet 200us should be enough, - but it doesn't work */ - iow(db, DM9000_EPCR, 0x0); - return (ior(db, DM9000_EPDRL) + (ior(db, DM9000_EPDRH) << 8)); + unsigned long flags; + unsigned int ret; + + spin_lock_irqsave(&db->lock, flags); + ret = ior(db, reg); + spin_unlock_irqrestore(&db->lock, flags); + + return ret; +} + +static int dm9000_wait_eeprom(board_info_t *db) +{ + unsigned int status; + int timeout = 8; /* wait max 8msec */ + + /* The DM9000 data sheets say we should be able to + * poll the ERRE bit in EPCR to wait for the EEPROM + * operation. From testing several chips, this bit + * does not seem to work. + * + * We attempt to use the bit, but fall back to the + * timeout (which is why we do not return an error + * on expiry) to say that the EEPROM operation has + * completed. + */ + + while (1) { + status = dm9000_read_locked(db, DM9000_EPCR); + + if ((status & EPCR_ERRE) == 0) + break; + + if (timeout-- < 0) { + dev_dbg(db->dev, "timeout waiting EEPROM\n"); + break; + } + } + + return 0; } -#ifdef DM9000_PROGRAM_EEPROM /* - * Write a word data to SROM + * Read a word data from EEPROM */ static void -write_srom_word(board_info_t * db, int offset, u16 val) +dm9000_read_eeprom(board_info_t *db, int offset, u8 *to) { + unsigned long flags; + + if (db->flags & DM9000_PLATF_NO_EEPROM) { + to[0] = 0xff; + to[1] = 0xff; + return; + } + + mutex_lock(&db->addr_lock); + + spin_lock_irqsave(&db->lock, flags); + iow(db, DM9000_EPAR, offset); - iow(db, DM9000_EPDRH, ((val >> 8) & 0xff)); - iow(db, DM9000_EPDRL, (val & 0xff)); - iow(db, DM9000_EPCR, EPCR_WEP | EPCR_ERPRW); - mdelay(8); /* same shit */ - iow(db, DM9000_EPCR, 0); + iow(db, DM9000_EPCR, EPCR_ERPRR); + + spin_unlock_irqrestore(&db->lock, flags); + + dm9000_wait_eeprom(db); + + /* delay for at-least 150uS */ + msleep(1); + + spin_lock_irqsave(&db->lock, flags); + + iow(db, DM9000_EPCR, 0x0); + + to[0] = ior(db, DM9000_EPDRL); + to[1] = ior(db, DM9000_EPDRH); + + spin_unlock_irqrestore(&db->lock, flags); + + mutex_unlock(&db->addr_lock); } /* - * Only for development: - * Here we write static data to the eeprom in case - * we don't have valid content on a new board + * Write a word data to SROM */ static void -program_eeprom(board_info_t * db) +dm9000_write_eeprom(board_info_t *db, int offset, u8 *data) { - u16 eeprom[] = { 0x0c00, 0x007f, 0x1300, /* MAC Address */ - 0x0000, /* Autoload: accept nothing */ - 0x0a46, 0x9000, /* Vendor / Product ID */ - 0x0000, /* pin control */ - 0x0000, - }; /* Wake-up mode control */ - int i; - for (i = 0; i < 8; i++) - write_srom_word(db, i, eeprom[i]); -} -#endif + unsigned long flags; + if (db->flags & DM9000_PLATF_NO_EEPROM) + return; -/* - * Calculate the CRC valude of the Rx packet - * flag = 1 : return the reverse CRC (for the received packet CRC) - * 0 : return the normal CRC (for Hash Table index) - */ + mutex_lock(&db->addr_lock); -static unsigned long -cal_CRC(unsigned char *Data, unsigned int Len, u8 flag) -{ + spin_lock_irqsave(&db->lock, flags); + iow(db, DM9000_EPAR, offset); + iow(db, DM9000_EPDRH, data[1]); + iow(db, DM9000_EPDRL, data[0]); + iow(db, DM9000_EPCR, EPCR_WEP | EPCR_ERPRW); + spin_unlock_irqrestore(&db->lock, flags); + + dm9000_wait_eeprom(db); - u32 crc = ether_crc_le(Len, Data); + mdelay(1); /* wait at least 150uS to clear */ - if (flag) - return ~crc; + spin_lock_irqsave(&db->lock, flags); + iow(db, DM9000_EPCR, 0); + spin_unlock_irqrestore(&db->lock, flags); - return crc; + mutex_unlock(&db->addr_lock); } /* @@ -1037,15 +1194,16 @@ dm9000_hash_table(struct net_device *dev) board_info_t *db = (board_info_t *) dev->priv; struct dev_mc_list *mcptr = dev->mc_list; int mc_cnt = dev->mc_count; + int i, oft; u32 hash_val; - u16 i, oft, hash_table[4]; + u16 hash_table[4]; unsigned long flags; - PRINTK2("dm9000_hash_table()\n"); + dm9000_dbg(db, 1, "entering %s\n", __func__); - spin_lock_irqsave(&db->lock,flags); + spin_lock_irqsave(&db->lock, flags); - for (i = 0, oft = 0x10; i < 6; i++, oft++) + for (i = 0, oft = DM9000_PAR; i < 6; i++, oft++) iow(db, oft, dev->dev_addr[i]); /* Clear Hash Table */ @@ -1057,21 +1215,33 @@ dm9000_hash_table(struct net_device *dev) /* the multicast address in Hash Table : 64 bits */ for (i = 0; i < mc_cnt; i++, mcptr = mcptr->next) { - hash_val = cal_CRC((char *) mcptr->dmi_addr, 6, 0) & 0x3f; + hash_val = ether_crc_le(6, mcptr->dmi_addr) & 0x3f; hash_table[hash_val / 16] |= (u16) 1 << (hash_val % 16); } /* Write the hash table to MAC MD table */ - for (i = 0, oft = 0x16; i < 4; i++) { - iow(db, oft++, hash_table[i] & 0xff); - iow(db, oft++, (hash_table[i] >> 8) & 0xff); + for (i = 0, oft = DM9000_MAR; i < 4; i++) { + iow(db, oft++, hash_table[i]); + iow(db, oft++, hash_table[i] >> 8); } - spin_unlock_irqrestore(&db->lock,flags); + spin_unlock_irqrestore(&db->lock, flags); } /* + * Sleep, either by using msleep() or if we are suspending, then + * use mdelay() to sleep. + */ +static void dm9000_msleep(board_info_t *db, unsigned int ms) +{ + if (db->in_suspend) + mdelay(ms); + else + msleep(ms); +} + +/* * Read a word from phyxcer */ static int @@ -1082,6 +1252,8 @@ dm9000_phy_read(struct net_device *dev, int phy_reg_unused, int reg) unsigned int reg_save; int ret; + mutex_lock(&db->addr_lock); + spin_lock_irqsave(&db->lock,flags); /* Save previous register address */ @@ -1091,7 +1263,15 @@ dm9000_phy_read(struct net_device *dev, int phy_reg_unused, int reg) iow(db, DM9000_EPAR, DM9000_PHY | reg); iow(db, DM9000_EPCR, 0xc); /* Issue phyxcer read command */ - udelay(100); /* Wait read complete */ + + writeb(reg_save, db->io_addr); + spin_unlock_irqrestore(&db->lock,flags); + + dm9000_msleep(db, 1); /* Wait read complete */ + + spin_lock_irqsave(&db->lock,flags); + reg_save = readb(db->io_addr); + iow(db, DM9000_EPCR, 0x0); /* Clear phyxcer read command */ /* The read data keeps on REG_0D & REG_0E */ @@ -1099,9 +1279,9 @@ dm9000_phy_read(struct net_device *dev, int phy_reg_unused, int reg) /* restore the previous address */ writeb(reg_save, db->io_addr); - spin_unlock_irqrestore(&db->lock,flags); + mutex_unlock(&db->addr_lock); return ret; } @@ -1115,6 +1295,8 @@ dm9000_phy_write(struct net_device *dev, int phyaddr_unused, int reg, int value) unsigned long flags; unsigned long reg_save; + mutex_lock(&db->addr_lock); + spin_lock_irqsave(&db->lock,flags); /* Save previous register address */ @@ -1124,25 +1306,38 @@ dm9000_phy_write(struct net_device *dev, int phyaddr_unused, int reg, int value) iow(db, DM9000_EPAR, DM9000_PHY | reg); /* Fill the written data into REG_0D & REG_0E */ - iow(db, DM9000_EPDRL, (value & 0xff)); - iow(db, DM9000_EPDRH, ((value >> 8) & 0xff)); + iow(db, DM9000_EPDRL, value); + iow(db, DM9000_EPDRH, value >> 8); iow(db, DM9000_EPCR, 0xa); /* Issue phyxcer write command */ - udelay(500); /* Wait write complete */ + + writeb(reg_save, db->io_addr); + spin_unlock_irqrestore(&db->lock, flags); + + dm9000_msleep(db, 1); /* Wait write complete */ + + spin_lock_irqsave(&db->lock,flags); + reg_save = readb(db->io_addr); + iow(db, DM9000_EPCR, 0x0); /* Clear phyxcer write command */ /* restore the previous address */ writeb(reg_save, db->io_addr); - spin_unlock_irqrestore(&db->lock,flags); + spin_unlock_irqrestore(&db->lock, flags); + mutex_unlock(&db->addr_lock); } static int dm9000_drv_suspend(struct platform_device *dev, pm_message_t state) { struct net_device *ndev = platform_get_drvdata(dev); + board_info_t *db; if (ndev) { + db = (board_info_t *) ndev->priv; + db->in_suspend = 1; + if (netif_running(ndev)) { netif_device_detach(ndev); dm9000_shutdown(ndev); @@ -1165,6 +1360,8 @@ dm9000_drv_resume(struct platform_device *dev) netif_device_attach(ndev); } + + db->in_suspend = 0; } return 0; } @@ -1180,8 +1377,7 @@ dm9000_drv_remove(struct platform_device *pdev) dm9000_release_board(pdev, (board_info_t *) ndev->priv); free_netdev(ndev); /* free device structure */ - PRINTK1("clean_module() exit\n"); - + dev_dbg(&pdev->dev, "released and freed device\n"); return 0; } @@ -1199,7 +1395,7 @@ static struct platform_driver dm9000_driver = { static int __init dm9000_init(void) { - printk(KERN_INFO "%s Ethernet Driver\n", CARDNAME); + printk(KERN_INFO "%s Ethernet Driver, V%s\n", CARDNAME, DRV_VERSION); return platform_driver_register(&dm9000_driver); /* search board and register */ } diff --git a/drivers/net/e1000/e1000_ethtool.c b/drivers/net/e1000/e1000_ethtool.c index d876787ce33..85e66f4c788 100644 --- a/drivers/net/e1000/e1000_ethtool.c +++ b/drivers/net/e1000/e1000_ethtool.c @@ -50,7 +50,7 @@ struct e1000_stats { int stat_offset; }; -#define E1000_STAT(m) sizeof(((struct e1000_adapter *)0)->m), \ +#define E1000_STAT(m) FIELD_SIZEOF(struct e1000_adapter, m), \ offsetof(struct e1000_adapter, m) static const struct e1000_stats e1000_gstrings_stats[] = { { "rx_packets", E1000_STAT(stats.gprc) }, diff --git a/drivers/net/e1000/e1000_main.c b/drivers/net/e1000/e1000_main.c index 7c5b05a82f0..0991648c53d 100644 --- a/drivers/net/e1000/e1000_main.c +++ b/drivers/net/e1000/e1000_main.c @@ -926,8 +926,6 @@ e1000_probe(struct pci_dev *pdev, { struct net_device *netdev; struct e1000_adapter *adapter; - unsigned long mmio_start, mmio_len; - unsigned long flash_start, flash_len; static int cards_found = 0; static int global_quad_port_a = 0; /* global ksp3 port a indication */ @@ -970,11 +968,9 @@ e1000_probe(struct pci_dev *pdev, adapter->hw.back = adapter; adapter->msg_enable = (1 << debug) - 1; - mmio_start = pci_resource_start(pdev, BAR_0); - mmio_len = pci_resource_len(pdev, BAR_0); - err = -EIO; - adapter->hw.hw_addr = ioremap(mmio_start, mmio_len); + adapter->hw.hw_addr = ioremap(pci_resource_start(pdev, BAR_0), + pci_resource_len(pdev, BAR_0)); if (!adapter->hw.hw_addr) goto err_ioremap; @@ -1009,10 +1005,6 @@ e1000_probe(struct pci_dev *pdev, #endif strncpy(netdev->name, pci_name(pdev), sizeof(netdev->name) - 1); - netdev->mem_start = mmio_start; - netdev->mem_end = mmio_start + mmio_len; - netdev->base_addr = adapter->hw.io_base; - adapter->bd_number = cards_found; /* setup the private structure */ @@ -1025,9 +1017,9 @@ e1000_probe(struct pci_dev *pdev, * because it depends on mac_type */ if ((adapter->hw.mac_type == e1000_ich8lan) && (pci_resource_flags(pdev, 1) & IORESOURCE_MEM)) { - flash_start = pci_resource_start(pdev, 1); - flash_len = pci_resource_len(pdev, 1); - adapter->hw.flash_address = ioremap(flash_start, flash_len); + adapter->hw.flash_address = + ioremap(pci_resource_start(pdev, 1), + pci_resource_len(pdev, 1)); if (!adapter->hw.flash_address) goto err_flashmap; } @@ -1203,6 +1195,14 @@ e1000_probe(struct pci_dev *pdev, printk("%s\n", print_mac(mac, netdev->dev_addr)); + if (adapter->hw.bus_type == e1000_bus_type_pci_express) { + DPRINTK(PROBE, WARNING, "This device (id %04x:%04x) will no " + "longer be supported by this driver in the future.\n", + pdev->vendor, pdev->device); + DPRINTK(PROBE, WARNING, "please use the \"e1000e\" " + "driver instead.\n"); + } + /* reset the hardware with the new settings */ e1000_reset(adapter); diff --git a/drivers/net/e1000e/netdev.c b/drivers/net/e1000e/netdev.c index f58f017ee47..3031d6d1624 100644 --- a/drivers/net/e1000e/netdev.c +++ b/drivers/net/e1000e/netdev.c @@ -1055,23 +1055,6 @@ static void e1000_release_hw_control(struct e1000_adapter *adapter) } } -static void e1000_release_manageability(struct e1000_adapter *adapter) -{ - if (adapter->flags & FLAG_MNG_PT_ENABLED) { - struct e1000_hw *hw = &adapter->hw; - - u32 manc = er32(MANC); - - /* re-enable hardware interception of ARP */ - manc |= E1000_MANC_ARP_EN; - manc &= ~E1000_MANC_EN_MNG2HOST; - - /* don't explicitly have to mess with MANC2H since - * MANC has an enable disable that gates MANC2H */ - ew32(MANC, manc); - } -} - /** * @e1000_alloc_ring - allocate memory for a ring structure **/ @@ -1561,9 +1544,6 @@ static void e1000_init_manageability(struct e1000_adapter *adapter) manc = er32(MANC); - /* disable hardware interception of ARP */ - manc &= ~(E1000_MANC_ARP_EN); - /* enable receiving management packets to the host. this will probably * generate destination unreachable messages from the host OS, but * the packets will be handled on SMBUS */ @@ -1690,6 +1670,9 @@ static void e1000_setup_rctl(struct e1000_adapter *adapter) else rctl |= E1000_RCTL_LPE; + /* Enable hardware CRC frame stripping */ + rctl |= E1000_RCTL_SECRC; + /* Setup buffer sizes */ rctl &= ~E1000_RCTL_SZ_4096; rctl |= E1000_RCTL_BSEX; @@ -1755,9 +1738,6 @@ static void e1000_setup_rctl(struct e1000_adapter *adapter) /* Enable Packet split descriptors */ rctl |= E1000_RCTL_DTYP_PS; - - /* Enable hardware CRC frame stripping */ - rctl |= E1000_RCTL_SECRC; psrctl |= adapter->rx_ps_bsize0 >> E1000_PSRCTL_BSIZE0_SHIFT; @@ -2008,7 +1988,7 @@ static void e1000_power_down_phy(struct e1000_adapter *adapter) u16 mii_reg; /* WoL is enabled */ - if (!adapter->wol) + if (adapter->wol) return; /* non-copper PHY? */ @@ -2140,8 +2120,6 @@ void e1000e_reset(struct e1000_adapter *adapter) phy_data &= ~IGP02E1000_PM_SPD; e1e_wphy(hw, IGP02E1000_PHY_POWER_MGMT, phy_data); } - - e1000_release_manageability(adapter); } int e1000e_up(struct e1000_adapter *adapter) @@ -3487,8 +3465,6 @@ static int e1000_suspend(struct pci_dev *pdev, pm_message_t state) pci_enable_wake(pdev, PCI_D3cold, 0); } - e1000_release_manageability(adapter); - /* make sure adapter isn't asleep if manageability is enabled */ if (adapter->flags & FLAG_MNG_PT_ENABLED) { pci_enable_wake(pdev, PCI_D3hot, 1); @@ -4054,8 +4030,6 @@ static void __devexit e1000_remove(struct pci_dev *pdev) flush_scheduled_work(); - e1000_release_manageability(adapter); - /* Release control of h/w to f/w. If f/w is AMT enabled, this * would have already happened in close and is redundant. */ e1000_release_hw_control(adapter); diff --git a/drivers/net/forcedeth.c b/drivers/net/forcedeth.c index d4843d014bc..801b4d9cd97 100644 --- a/drivers/net/forcedeth.c +++ b/drivers/net/forcedeth.c @@ -166,21 +166,24 @@ * Hardware access: */ -#define DEV_NEED_TIMERIRQ 0x0001 /* set the timer irq flag in the irq mask */ -#define DEV_NEED_LINKTIMER 0x0002 /* poll link settings. Relies on the timer irq */ -#define DEV_HAS_LARGEDESC 0x0004 /* device supports jumbo frames and needs packet format 2 */ -#define DEV_HAS_HIGH_DMA 0x0008 /* device supports 64bit dma */ -#define DEV_HAS_CHECKSUM 0x0010 /* device supports tx and rx checksum offloads */ -#define DEV_HAS_VLAN 0x0020 /* device supports vlan tagging and striping */ -#define DEV_HAS_MSI 0x0040 /* device supports MSI */ -#define DEV_HAS_MSI_X 0x0080 /* device supports MSI-X */ -#define DEV_HAS_POWER_CNTRL 0x0100 /* device supports power savings */ -#define DEV_HAS_PAUSEFRAME_TX 0x0200 /* device supports tx pause frames */ -#define DEV_HAS_STATISTICS_V1 0x0400 /* device supports hw statistics version 1 */ -#define DEV_HAS_STATISTICS_V2 0x0800 /* device supports hw statistics version 2 */ -#define DEV_HAS_TEST_EXTENDED 0x1000 /* device supports extended diagnostic test */ -#define DEV_HAS_MGMT_UNIT 0x2000 /* device supports management unit */ -#define DEV_HAS_CORRECT_MACADDR 0x4000 /* device supports correct mac address order */ +#define DEV_NEED_TIMERIRQ 0x00001 /* set the timer irq flag in the irq mask */ +#define DEV_NEED_LINKTIMER 0x00002 /* poll link settings. Relies on the timer irq */ +#define DEV_HAS_LARGEDESC 0x00004 /* device supports jumbo frames and needs packet format 2 */ +#define DEV_HAS_HIGH_DMA 0x00008 /* device supports 64bit dma */ +#define DEV_HAS_CHECKSUM 0x00010 /* device supports tx and rx checksum offloads */ +#define DEV_HAS_VLAN 0x00020 /* device supports vlan tagging and striping */ +#define DEV_HAS_MSI 0x00040 /* device supports MSI */ +#define DEV_HAS_MSI_X 0x00080 /* device supports MSI-X */ +#define DEV_HAS_POWER_CNTRL 0x00100 /* device supports power savings */ +#define DEV_HAS_STATISTICS_V1 0x00200 /* device supports hw statistics version 1 */ +#define DEV_HAS_STATISTICS_V2 0x00400 /* device supports hw statistics version 2 */ +#define DEV_HAS_TEST_EXTENDED 0x00800 /* device supports extended diagnostic test */ +#define DEV_HAS_MGMT_UNIT 0x01000 /* device supports management unit */ +#define DEV_HAS_CORRECT_MACADDR 0x02000 /* device supports correct mac address order */ +#define DEV_HAS_COLLISION_FIX 0x04000 /* device supports tx collision fix */ +#define DEV_HAS_PAUSEFRAME_TX_V1 0x08000 /* device supports tx pause frames version 1 */ +#define DEV_HAS_PAUSEFRAME_TX_V2 0x10000 /* device supports tx pause frames version 2 */ +#define DEV_HAS_PAUSEFRAME_TX_V3 0x20000 /* device supports tx pause frames version 3 */ enum { NvRegIrqStatus = 0x000, @@ -266,9 +269,12 @@ enum { #define NVREG_RNDSEED_FORCE3 0x7400 NvRegTxDeferral = 0xA0, -#define NVREG_TX_DEFERRAL_DEFAULT 0x15050f -#define NVREG_TX_DEFERRAL_RGMII_10_100 0x16070f -#define NVREG_TX_DEFERRAL_RGMII_1000 0x14050f +#define NVREG_TX_DEFERRAL_DEFAULT 0x15050f +#define NVREG_TX_DEFERRAL_RGMII_10_100 0x16070f +#define NVREG_TX_DEFERRAL_RGMII_1000 0x14050f +#define NVREG_TX_DEFERRAL_RGMII_STRETCH_10 0x16190f +#define NVREG_TX_DEFERRAL_RGMII_STRETCH_100 0x16300f +#define NVREG_TX_DEFERRAL_MII_STRETCH 0x152000 NvRegRxDeferral = 0xA4, #define NVREG_RX_DEFERRAL_DEFAULT 0x16 NvRegMacAddrA = 0xA8, @@ -318,8 +324,10 @@ enum { NvRegTxRingPhysAddrHigh = 0x148, NvRegRxRingPhysAddrHigh = 0x14C, NvRegTxPauseFrame = 0x170, -#define NVREG_TX_PAUSEFRAME_DISABLE 0x01ff0080 -#define NVREG_TX_PAUSEFRAME_ENABLE 0x01800010 +#define NVREG_TX_PAUSEFRAME_DISABLE 0x0fff0080 +#define NVREG_TX_PAUSEFRAME_ENABLE_V1 0x01800010 +#define NVREG_TX_PAUSEFRAME_ENABLE_V2 0x056003f0 +#define NVREG_TX_PAUSEFRAME_ENABLE_V3 0x09f00880 NvRegMIIStatus = 0x180, #define NVREG_MIISTAT_ERROR 0x0001 #define NVREG_MIISTAT_LINKCHANGE 0x0008 @@ -2751,7 +2759,12 @@ static void nv_update_pause(struct net_device *dev, u32 pause_flags) if (np->pause_flags & NV_PAUSEFRAME_TX_CAPABLE) { u32 regmisc = readl(base + NvRegMisc1) & ~NVREG_MISC1_PAUSE_TX; if (pause_flags & NV_PAUSEFRAME_TX_ENABLE) { - writel(NVREG_TX_PAUSEFRAME_ENABLE, base + NvRegTxPauseFrame); + u32 pause_enable = NVREG_TX_PAUSEFRAME_ENABLE_V1; + if (np->driver_data & DEV_HAS_PAUSEFRAME_TX_V2) + pause_enable = NVREG_TX_PAUSEFRAME_ENABLE_V2; + if (np->driver_data & DEV_HAS_PAUSEFRAME_TX_V3) + pause_enable = NVREG_TX_PAUSEFRAME_ENABLE_V3; + writel(pause_enable, base + NvRegTxPauseFrame); writel(regmisc|NVREG_MISC1_PAUSE_TX, base + NvRegMisc1); np->pause_flags |= NV_PAUSEFRAME_TX_ENABLE; } else { @@ -2785,6 +2798,7 @@ static int nv_update_linkspeed(struct net_device *dev) int retval = 0; u32 control_1000, status_1000, phyreg, pause_flags, txreg; u32 txrxFlags = 0; + u32 phy_exp; /* BMSR_LSTATUS is latched, read it twice: * we want the current value. @@ -2912,13 +2926,25 @@ set_speed: phyreg |= PHY_1000; writel(phyreg, base + NvRegPhyInterface); + phy_exp = mii_rw(dev, np->phyaddr, MII_EXPANSION, MII_READ) & EXPANSION_NWAY; /* autoneg capable */ if (phyreg & PHY_RGMII) { - if ((np->linkspeed & NVREG_LINKSPEED_MASK) == NVREG_LINKSPEED_1000) + if ((np->linkspeed & NVREG_LINKSPEED_MASK) == NVREG_LINKSPEED_1000) { txreg = NVREG_TX_DEFERRAL_RGMII_1000; - else - txreg = NVREG_TX_DEFERRAL_RGMII_10_100; + } else { + if (!phy_exp && !np->duplex && (np->driver_data & DEV_HAS_COLLISION_FIX)) { + if ((np->linkspeed & NVREG_LINKSPEED_MASK) == NVREG_LINKSPEED_10) + txreg = NVREG_TX_DEFERRAL_RGMII_STRETCH_10; + else + txreg = NVREG_TX_DEFERRAL_RGMII_STRETCH_100; + } else { + txreg = NVREG_TX_DEFERRAL_RGMII_10_100; + } + } } else { - txreg = NVREG_TX_DEFERRAL_DEFAULT; + if (!phy_exp && !np->duplex && (np->driver_data & DEV_HAS_COLLISION_FIX)) + txreg = NVREG_TX_DEFERRAL_MII_STRETCH; + else + txreg = NVREG_TX_DEFERRAL_DEFAULT; } writel(txreg, base + NvRegTxDeferral); @@ -5155,7 +5181,9 @@ static int __devinit nv_probe(struct pci_dev *pci_dev, const struct pci_device_i } np->pause_flags = NV_PAUSEFRAME_RX_CAPABLE | NV_PAUSEFRAME_RX_REQ | NV_PAUSEFRAME_AUTONEG; - if (id->driver_data & DEV_HAS_PAUSEFRAME_TX) { + if ((id->driver_data & DEV_HAS_PAUSEFRAME_TX_V1) || + (id->driver_data & DEV_HAS_PAUSEFRAME_TX_V2) || + (id->driver_data & DEV_HAS_PAUSEFRAME_TX_V3)) { np->pause_flags |= NV_PAUSEFRAME_TX_CAPABLE | NV_PAUSEFRAME_TX_REQ; } @@ -5559,107 +5587,107 @@ static struct pci_device_id pci_tbl[] = { }, { /* MCP55 Ethernet Controller */ PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_14), - .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_VLAN|DEV_HAS_MSI|DEV_HAS_MSI_X|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT, + .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_VLAN|DEV_HAS_MSI|DEV_HAS_MSI_X|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT, }, { /* MCP55 Ethernet Controller */ PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_15), - .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_VLAN|DEV_HAS_MSI|DEV_HAS_MSI_X|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT, + .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_VLAN|DEV_HAS_MSI|DEV_HAS_MSI_X|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT, }, { /* MCP61 Ethernet Controller */ PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_16), - .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR, + .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR, }, { /* MCP61 Ethernet Controller */ PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_17), - .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR, + .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR, }, { /* MCP61 Ethernet Controller */ PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_18), - .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR, + .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR, }, { /* MCP61 Ethernet Controller */ PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_19), - .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR, + .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR, }, { /* MCP65 Ethernet Controller */ PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_20), - .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR, + .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR, }, { /* MCP65 Ethernet Controller */ PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_21), - .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR, + .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR, }, { /* MCP65 Ethernet Controller */ PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_22), - .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR, + .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR, }, { /* MCP65 Ethernet Controller */ PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_23), - .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR, + .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR, }, { /* MCP67 Ethernet Controller */ PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_24), - .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR, + .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR, }, { /* MCP67 Ethernet Controller */ PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_25), - .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR, + .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR, }, { /* MCP67 Ethernet Controller */ PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_26), - .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR, + .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR, }, { /* MCP67 Ethernet Controller */ PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_27), - .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR, + .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR, }, { /* MCP73 Ethernet Controller */ PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_28), - .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR, + .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_HAS_COLLISION_FIX, }, { /* MCP73 Ethernet Controller */ PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_29), - .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR, + .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_HAS_COLLISION_FIX, }, { /* MCP73 Ethernet Controller */ PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_30), - .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR, + .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_HAS_COLLISION_FIX, }, { /* MCP73 Ethernet Controller */ PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_31), - .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR, + .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_HAS_COLLISION_FIX, }, { /* MCP77 Ethernet Controller */ PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_32), - .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_MSI|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR, + .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_MSI|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX_V2|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_HAS_COLLISION_FIX, }, { /* MCP77 Ethernet Controller */ PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_33), - .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_MSI|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR, + .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_MSI|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX_V2|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_HAS_COLLISION_FIX, }, { /* MCP77 Ethernet Controller */ PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_34), - .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_MSI|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR, + .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_MSI|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX_V2|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_HAS_COLLISION_FIX, }, { /* MCP77 Ethernet Controller */ PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_35), - .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_MSI|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR, + .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_MSI|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX_V2|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_HAS_COLLISION_FIX, }, { /* MCP79 Ethernet Controller */ PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_36), - .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_MSI|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR, + .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_MSI|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX_V3|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_HAS_COLLISION_FIX, }, { /* MCP79 Ethernet Controller */ PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_37), - .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_MSI|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR, + .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_MSI|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX_V3|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_HAS_COLLISION_FIX, }, { /* MCP79 Ethernet Controller */ PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_38), - .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_MSI|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR, + .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_MSI|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX_V3|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_HAS_COLLISION_FIX, }, { /* MCP79 Ethernet Controller */ PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_39), - .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_MSI|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR, + .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_MSI|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX_V3|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_HAS_COLLISION_FIX, }, {0,}, }; diff --git a/drivers/net/gianfar.c b/drivers/net/gianfar.c index 0431e9ed0fa..4244fc282f2 100644 --- a/drivers/net/gianfar.c +++ b/drivers/net/gianfar.c @@ -130,8 +130,8 @@ static void free_skb_resources(struct gfar_private *priv); static void gfar_set_multi(struct net_device *dev); static void gfar_set_hash_for_addr(struct net_device *dev, u8 *addr); static void gfar_configure_serdes(struct net_device *dev); -extern int gfar_local_mdio_write(struct gfar_mii *regs, int mii_id, int regnum, u16 value); -extern int gfar_local_mdio_read(struct gfar_mii *regs, int mii_id, int regnum); +extern int gfar_local_mdio_write(struct gfar_mii __iomem *regs, int mii_id, int regnum, u16 value); +extern int gfar_local_mdio_read(struct gfar_mii __iomem *regs, int mii_id, int regnum); #ifdef CONFIG_GFAR_NAPI static int gfar_poll(struct napi_struct *napi, int budget); #endif diff --git a/drivers/net/gianfar_mii.c b/drivers/net/gianfar_mii.c index 6a647d95e6e..24327629bf0 100644 --- a/drivers/net/gianfar_mii.c +++ b/drivers/net/gianfar_mii.c @@ -51,7 +51,7 @@ * the local mdio pins, which may not be the same as system mdio bus, used for * controlling the external PHYs, for example. */ -int gfar_local_mdio_write(struct gfar_mii *regs, int mii_id, +int gfar_local_mdio_write(struct gfar_mii __iomem *regs, int mii_id, int regnum, u16 value) { /* Set the PHY address and the register address we want to write */ @@ -77,7 +77,7 @@ int gfar_local_mdio_write(struct gfar_mii *regs, int mii_id, * and are always tied to the local mdio pins, which may not be the * same as system mdio bus, used for controlling the external PHYs, for eg. */ -int gfar_local_mdio_read(struct gfar_mii *regs, int mii_id, int regnum) +int gfar_local_mdio_read(struct gfar_mii __iomem *regs, int mii_id, int regnum) { u16 value; diff --git a/drivers/net/hamradio/mkiss.c b/drivers/net/hamradio/mkiss.c index cfcd15af501..30c9b3b0d13 100644 --- a/drivers/net/hamradio/mkiss.c +++ b/drivers/net/hamradio/mkiss.c @@ -289,7 +289,6 @@ static void ax_bump(struct mkiss *ax) *ax->rbuff &= ~0x20; } } - spin_unlock_bh(&ax->buflock); count = ax->rcount; @@ -297,17 +296,17 @@ static void ax_bump(struct mkiss *ax) printk(KERN_ERR "mkiss: %s: memory squeeze, dropping packet.\n", ax->dev->name); ax->stats.rx_dropped++; + spin_unlock_bh(&ax->buflock); return; } - spin_lock_bh(&ax->buflock); memcpy(skb_put(skb,count), ax->rbuff, count); - spin_unlock_bh(&ax->buflock); skb->protocol = ax25_type_trans(skb, ax->dev); netif_rx(skb); ax->dev->last_rx = jiffies; ax->stats.rx_packets++; ax->stats.rx_bytes += count; + spin_unlock_bh(&ax->buflock); } static void kiss_unesc(struct mkiss *ax, unsigned char s) diff --git a/drivers/net/igb/igb_ethtool.c b/drivers/net/igb/igb_ethtool.c index f69721e4eaa..0447f9bcd27 100644 --- a/drivers/net/igb/igb_ethtool.c +++ b/drivers/net/igb/igb_ethtool.c @@ -43,7 +43,7 @@ struct igb_stats { int stat_offset; }; -#define IGB_STAT(m) sizeof(((struct igb_adapter *)0)->m), \ +#define IGB_STAT(m) FIELD_SIZEOF(struct igb_adapter, m), \ offsetof(struct igb_adapter, m) static const struct igb_stats igb_gstrings_stats[] = { { "rx_packets", IGB_STAT(stats.gprc) }, diff --git a/drivers/net/igb/igb_main.c b/drivers/net/igb/igb_main.c index d4eb8e2d872..bff280eff5e 100644 --- a/drivers/net/igb/igb_main.c +++ b/drivers/net/igb/igb_main.c @@ -606,9 +606,6 @@ static void igb_init_manageability(struct igb_adapter *adapter) u32 manc2h = rd32(E1000_MANC2H); u32 manc = rd32(E1000_MANC); - /* disable hardware interception of ARP */ - manc &= ~(E1000_MANC_ARP_EN); - /* enable receiving management packets to the host */ /* this will probably generate destination unreachable messages * from the host OS, but the packets will be handled on SMBUS */ @@ -623,25 +620,6 @@ static void igb_init_manageability(struct igb_adapter *adapter) } } -static void igb_release_manageability(struct igb_adapter *adapter) -{ - struct e1000_hw *hw = &adapter->hw; - - if (adapter->en_mng_pt) { - u32 manc = rd32(E1000_MANC); - - /* re-enable hardware interception of ARP */ - manc |= E1000_MANC_ARP_EN; - manc &= ~E1000_MANC_EN_MNG2HOST; - - /* don't explicitly have to mess with MANC2H since - * MANC has an enable disable that gates MANC2H */ - - /* XXX stop the hardware watchdog ? */ - wr32(E1000_MANC, manc); - } -} - /** * igb_configure - configure the hardware for RX and TX * @adapter: private board structure @@ -844,7 +822,6 @@ void igb_reset(struct igb_adapter *adapter) igb_reset_adaptive(&adapter->hw); adapter->hw.phy.ops.get_phy_info(&adapter->hw); - igb_release_manageability(adapter); } /** @@ -1178,9 +1155,6 @@ static void __devexit igb_remove(struct pci_dev *pdev) flush_scheduled_work(); - - igb_release_manageability(adapter); - /* Release control of h/w to f/w. If f/w is AMT enabled, this * would have already happened in close and is redundant. */ igb_release_hw_control(adapter); @@ -3955,8 +3929,6 @@ static int igb_suspend(struct pci_dev *pdev, pm_message_t state) pci_enable_wake(pdev, PCI_D3cold, 0); } - igb_release_manageability(adapter); - /* make sure adapter isn't asleep if manageability is enabled */ if (adapter->en_mng_pt) { pci_enable_wake(pdev, PCI_D3hot, 1); diff --git a/drivers/net/ixgb/ixgb_ethtool.c b/drivers/net/ixgb/ixgb_ethtool.c index a267dd86252..53a9fd086f9 100644 --- a/drivers/net/ixgb/ixgb_ethtool.c +++ b/drivers/net/ixgb/ixgb_ethtool.c @@ -49,7 +49,7 @@ struct ixgb_stats { int stat_offset; }; -#define IXGB_STAT(m) sizeof(((struct ixgb_adapter *)0)->m), \ +#define IXGB_STAT(m) FIELD_SIZEOF(struct ixgb_adapter, m), \ offsetof(struct ixgb_adapter, m) static struct ixgb_stats ixgb_gstrings_stats[] = { {"rx_packets", IXGB_STAT(net_stats.rx_packets)}, diff --git a/drivers/net/ixgbe/ixgbe_main.c b/drivers/net/ixgbe/ixgbe_main.c index ead49e54f31..23d0a4afe0e 100644 --- a/drivers/net/ixgbe/ixgbe_main.c +++ b/drivers/net/ixgbe/ixgbe_main.c @@ -220,7 +220,6 @@ static bool ixgbe_clean_tx_irq(struct ixgbe_adapter *adapter, tx_ring->stats.bytes += tx_buffer_info->length; if (cleaned) { struct sk_buff *skb = tx_buffer_info->skb; -#ifdef NETIF_F_TSO unsigned int segs, bytecount; segs = skb_shinfo(skb)->gso_segs ?: 1; /* multiply data chunks by size of headers */ @@ -228,10 +227,6 @@ static bool ixgbe_clean_tx_irq(struct ixgbe_adapter *adapter, skb->len; total_tx_packets += segs; total_tx_bytes += bytecount; -#else - total_tx_packets++; - total_tx_bytes += skb->len; -#endif } ixgbe_unmap_and_free_tx_resource(adapter, tx_buffer_info); @@ -1942,6 +1937,10 @@ static int ixgbe_open(struct net_device *netdev) int err; u32 num_rx_queues = adapter->num_rx_queues; + /* disallow open during test */ + if (test_bit(__IXGBE_TESTING, &adapter->state)) + return -EBUSY; + try_intr_reinit: /* allocate transmit descriptors */ err = ixgbe_setup_all_tx_resources(adapter); @@ -2278,11 +2277,29 @@ static bool ixgbe_tx_csum(struct ixgbe_adapter *adapter, IXGBE_ADVTXD_DTYP_CTXT); if (skb->ip_summed == CHECKSUM_PARTIAL) { - if (skb->protocol == htons(ETH_P_IP)) + switch (skb->protocol) { + case __constant_htons(ETH_P_IP): type_tucmd_mlhl |= IXGBE_ADVTXD_TUCMD_IPV4; + if (ip_hdr(skb)->protocol == IPPROTO_TCP) + type_tucmd_mlhl |= + IXGBE_ADVTXD_TUCMD_L4T_TCP; + break; + + case __constant_htons(ETH_P_IPV6): + /* XXX what about other V6 headers?? */ + if (ipv6_hdr(skb)->nexthdr == IPPROTO_TCP) + type_tucmd_mlhl |= + IXGBE_ADVTXD_TUCMD_L4T_TCP; + break; - if (skb->sk->sk_protocol == IPPROTO_TCP) - type_tucmd_mlhl |= IXGBE_ADVTXD_TUCMD_L4T_TCP; + default: + if (unlikely(net_ratelimit())) { + DPRINTK(PROBE, WARNING, + "partial checksum but proto=%x!\n", + skb->protocol); + } + break; + } } context_desc->type_tucmd_mlhl = cpu_to_le32(type_tucmd_mlhl); @@ -2778,6 +2795,14 @@ static int __devinit ixgbe_probe(struct pci_dev *pdev, hw->mac.type, hw->phy.type, (part_num >> 8), (part_num & 0xff)); + if (link_width <= IXGBE_PCI_LINK_WIDTH_4) { + dev_warn(&pdev->dev, "PCI-Express bandwidth available for " + "this card is not sufficient for optimal " + "performance.\n"); + dev_warn(&pdev->dev, "For optimal performance a x8 " + "PCI-Express slot is required.\n"); + } + /* reset the hardware with the new settings */ ixgbe_start_hw(hw); diff --git a/drivers/net/mlx4/mr.c b/drivers/net/mlx4/mr.c index 679dfdb6807..79b317b88c8 100644 --- a/drivers/net/mlx4/mr.c +++ b/drivers/net/mlx4/mr.c @@ -578,13 +578,6 @@ int mlx4_fmr_alloc(struct mlx4_dev *dev, u32 pd, u32 access, int max_pages, goto err_free; } - fmr->mpt = mlx4_table_find(&priv->mr_table.dmpt_table, - key_to_hw_index(fmr->mr.key), NULL); - if (!fmr->mpt) { - err = -ENOMEM; - goto err_free; - } - return 0; err_free: @@ -595,7 +588,19 @@ EXPORT_SYMBOL_GPL(mlx4_fmr_alloc); int mlx4_fmr_enable(struct mlx4_dev *dev, struct mlx4_fmr *fmr) { - return mlx4_mr_enable(dev, &fmr->mr); + struct mlx4_priv *priv = mlx4_priv(dev); + int err; + + err = mlx4_mr_enable(dev, &fmr->mr); + if (err) + return err; + + fmr->mpt = mlx4_table_find(&priv->mr_table.dmpt_table, + key_to_hw_index(fmr->mr.key), NULL); + if (!fmr->mpt) + return -ENOMEM; + + return 0; } EXPORT_SYMBOL_GPL(mlx4_fmr_enable); diff --git a/drivers/net/netconsole.c b/drivers/net/netconsole.c index 31e047dd7bb..501e451be91 100644 --- a/drivers/net/netconsole.c +++ b/drivers/net/netconsole.c @@ -309,8 +309,8 @@ static ssize_t show_local_mac(struct netconsole_target *nt, char *buf) struct net_device *dev = nt->np.dev; DECLARE_MAC_BUF(mac); - return snprintf(buf, PAGE_SIZE, "%s\n", - print_mac(mac, dev->dev_addr)); + return snprintf(buf, PAGE_SIZE, "%s\n", dev ? + print_mac(mac, dev->dev_addr) : "ff:ff:ff:ff:ff:ff"); } static ssize_t show_remote_mac(struct netconsole_target *nt, char *buf) diff --git a/drivers/net/ni52.c b/drivers/net/ni52.c index 6b3384a24f0..26aa8fe1fb2 100644 --- a/drivers/net/ni52.c +++ b/drivers/net/ni52.c @@ -33,20 +33,20 @@ * I have also done a look in the following sources: (mail me if you need them) * crynwr-packet-driver by Russ Nelson * Garret A. Wollman's (fourth) i82586-driver for BSD - * (before getting an i82596 (yes 596 not 586) manual, the existing drivers helped - * me a lot to understand this tricky chip.) + * (before getting an i82596 (yes 596 not 586) manual, the existing drivers + * helped me a lot to understand this tricky chip.) * * Known Problems: * The internal sysbus seems to be slow. So we often lose packets because of * overruns while receiving from a fast remote host. - * This can slow down TCP connections. Maybe the newer ni5210 cards are better. - * my experience is, that if a machine sends with more than about 500-600K/s - * the fifo/sysbus overflows. + * This can slow down TCP connections. Maybe the newer ni5210 cards are + * better. My experience is, that if a machine sends with more than about + * 500-600K/s the fifo/sysbus overflows. * * IMPORTANT NOTE: * On fast networks, it's a (very) good idea to have 16K shared memory. With - * 8K, we can store only 4 receive frames, so it can (easily) happen that a remote - * machine 'overruns' our system. + * 8K, we can store only 4 receive frames, so it can (easily) happen that a + * remote machine 'overruns' our system. * * Known i82586/card problems (I'm sure, there are many more!): * Running the NOP-mode, the i82586 sometimes seems to forget to report @@ -60,7 +60,8 @@ * * results from ftp performance tests with Linux 1.2.5 * send and receive about 350-400 KByte/s (peak up to 460 kbytes/s) - * sending in NOP-mode: peak performance up to 530K/s (but better don't run this mode) + * sending in NOP-mode: peak performance up to 530K/s (but better don't + * run this mode) */ /* @@ -94,7 +95,8 @@ * * 26.March.94: patches for Linux 1.0 and iomem-auto-probe (MH) * - * 30.Sep.93: Added nop-chain .. driver now runs with only one Xmit-Buff, too (MH) + * 30.Sep.93: Added nop-chain .. driver now runs with only one Xmit-Buff, + * too (MH) * * < 30.Sep.93: first versions */ @@ -102,7 +104,7 @@ static int debuglevel; /* debug-printk 0: off 1: a few 2: more */ static int automatic_resume; /* experimental .. better should be zero */ static int rfdadd; /* rfdadd=1 may be better for 8K MEM cards */ -static int fifo=0x8; /* don't change */ +static int fifo = 0x8; /* don't change */ #include <linux/module.h> #include <linux/kernel.h> @@ -127,14 +129,15 @@ static int fifo=0x8; /* don't change */ #define DEBUG /* debug on */ #define SYSBUSVAL 1 /* 8 Bit */ -#define ni_attn586() {outb(0,dev->base_addr+NI52_ATTENTION);} -#define ni_reset586() {outb(0,dev->base_addr+NI52_RESET);} -#define ni_disint() {outb(0,dev->base_addr+NI52_INTDIS);} -#define ni_enaint() {outb(0,dev->base_addr+NI52_INTENA);} +#define ni_attn586() { outb(0, dev->base_addr + NI52_ATTENTION); } +#define ni_reset586() { outb(0, dev->base_addr + NI52_RESET); } +#define ni_disint() { outb(0, dev->base_addr + NI52_INTDIS); } +#define ni_enaint() { outb(0, dev->base_addr + NI52_INTENA); } -#define make32(ptr16) (p->memtop + (short) (ptr16) ) -#define make24(ptr32) ( ((char *) (ptr32)) - p->base) -#define make16(ptr32) ((unsigned short) ((unsigned long)(ptr32) - (unsigned long) p->memtop )) +#define make32(ptr16) (p->memtop + (short) (ptr16)) +#define make24(ptr32) ((unsigned long)(ptr32)) - p->base +#define make16(ptr32) ((unsigned short) ((unsigned long)(ptr32)\ + - (unsigned long) p->memtop)) /******************* how to calculate the buffers ***************************** @@ -159,96 +162,112 @@ sizeof(nop_cmd) = 8; /**************************************************************************/ -/* different DELAYs */ -#define DELAY(x) mdelay(32 * x); -#define DELAY_16(); { udelay(16); } -#define DELAY_18(); { udelay(4); } - -/* wait for command with timeout: */ -#define WAIT_4_SCB_CMD() \ -{ int i; \ - for(i=0;i<16384;i++) { \ - if(!p->scb->cmd_cuc) break; \ - DELAY_18(); \ - if(i == 16383) { \ - printk("%s: scb_cmd timed out: %04x,%04x .. disabling i82586!!\n",dev->name,p->scb->cmd_cuc,p->scb->cus); \ - if(!p->reseted) { p->reseted = 1; ni_reset586(); } } } } - -#define WAIT_4_SCB_CMD_RUC() { int i; \ - for(i=0;i<16384;i++) { \ - if(!p->scb->cmd_ruc) break; \ - DELAY_18(); \ - if(i == 16383) { \ - printk("%s: scb_cmd (ruc) timed out: %04x,%04x .. disabling i82586!!\n",dev->name,p->scb->cmd_ruc,p->scb->rus); \ - if(!p->reseted) { p->reseted = 1; ni_reset586(); } } } } - -#define WAIT_4_STAT_COMPL(addr) { int i; \ - for(i=0;i<32767;i++) { \ - if((addr)->cmd_status & STAT_COMPL) break; \ - DELAY_16(); DELAY_16(); } } #define NI52_TOTAL_SIZE 16 #define NI52_ADDR0 0x02 #define NI52_ADDR1 0x07 #define NI52_ADDR2 0x01 -static int ni52_probe1(struct net_device *dev,int ioaddr); -static irqreturn_t ni52_interrupt(int irq,void *dev_id); +static int ni52_probe1(struct net_device *dev, int ioaddr); +static irqreturn_t ni52_interrupt(int irq, void *dev_id); static int ni52_open(struct net_device *dev); static int ni52_close(struct net_device *dev); -static int ni52_send_packet(struct sk_buff *,struct net_device *); +static int ni52_send_packet(struct sk_buff *, struct net_device *); static struct net_device_stats *ni52_get_stats(struct net_device *dev); static void set_multicast_list(struct net_device *dev); static void ni52_timeout(struct net_device *dev); -#if 0 -static void ni52_dump(struct net_device *,void *); -#endif /* helper-functions */ static int init586(struct net_device *dev); -static int check586(struct net_device *dev,char *where,unsigned size); +static int check586(struct net_device *dev, char *where, unsigned size); static void alloc586(struct net_device *dev); static void startrecv586(struct net_device *dev); -static void *alloc_rfa(struct net_device *dev,void *ptr); +static void *alloc_rfa(struct net_device *dev, void *ptr); static void ni52_rcv_int(struct net_device *dev); static void ni52_xmt_int(struct net_device *dev); static void ni52_rnr_int(struct net_device *dev); -struct priv -{ +struct priv { struct net_device_stats stats; unsigned long base; char *memtop; - long int lock; - int reseted; - volatile struct rfd_struct *rfd_last,*rfd_top,*rfd_first; - volatile struct scp_struct *scp; /* volatile is important */ - volatile struct iscp_struct *iscp; /* volatile is important */ - volatile struct scb_struct *scb; /* volatile is important */ - volatile struct tbd_struct *xmit_buffs[NUM_XMIT_BUFFS]; + spinlock_t spinlock; + int reset; + struct rfd_struct *rfd_last, *rfd_top, *rfd_first; + struct scp_struct *scp; + struct iscp_struct *iscp; + struct scb_struct *scb; + struct tbd_struct *xmit_buffs[NUM_XMIT_BUFFS]; #if (NUM_XMIT_BUFFS == 1) - volatile struct transmit_cmd_struct *xmit_cmds[2]; - volatile struct nop_cmd_struct *nop_cmds[2]; + struct transmit_cmd_struct *xmit_cmds[2]; + struct nop_cmd_struct *nop_cmds[2]; #else - volatile struct transmit_cmd_struct *xmit_cmds[NUM_XMIT_BUFFS]; - volatile struct nop_cmd_struct *nop_cmds[NUM_XMIT_BUFFS]; + struct transmit_cmd_struct *xmit_cmds[NUM_XMIT_BUFFS]; + struct nop_cmd_struct *nop_cmds[NUM_XMIT_BUFFS]; #endif - volatile int nop_point,num_recv_buffs; - volatile char *xmit_cbuffs[NUM_XMIT_BUFFS]; - volatile int xmit_count,xmit_last; + int nop_point, num_recv_buffs; + char *xmit_cbuffs[NUM_XMIT_BUFFS]; + int xmit_count, xmit_last; }; +/* wait for command with timeout: */ +static void wait_for_scb_cmd(struct net_device *dev) +{ + struct priv *p = dev->priv; + int i; + for (i = 0; i < 16384; i++) { + if (readb(&p->scb->cmd_cuc) == 0) + break; + udelay(4); + if (i == 16383) { + printk(KERN_ERR "%s: scb_cmd timed out: %04x,%04x .. disabling i82586!!\n", + dev->name, readb(&p->scb->cmd_cuc), readb(&p->scb->cus)); + if (!p->reset) { + p->reset = 1; + ni_reset586(); + } + } + } +} + +static void wait_for_scb_cmd_ruc(struct net_device *dev) +{ + struct priv *p = dev->priv; + int i; + for (i = 0; i < 16384; i++) { + if (readb(&p->scb->cmd_ruc) == 0) + break; + udelay(4); + if (i == 16383) { + printk(KERN_ERR "%s: scb_cmd (ruc) timed out: %04x,%04x .. disabling i82586!!\n", + dev->name, p->scb->cmd_ruc, p->scb->rus); + if (!p->reset) { + p->reset = 1; + ni_reset586(); + } + } + } +} + +static void wait_for_stat_compl(void *p) +{ + struct nop_cmd_struct *addr = p; + int i; + for (i = 0; i < 32767; i++) { + if (readw(&((addr)->cmd_status)) & STAT_COMPL) + break; + udelay(32); + } +} + /********************************************** * close device */ static int ni52_close(struct net_device *dev) { free_irq(dev->irq, dev); - ni_reset586(); /* the hard way to stop the receiver */ - netif_stop_queue(dev); - return 0; } @@ -265,55 +284,53 @@ static int ni52_open(struct net_device *dev) startrecv586(dev); ni_enaint(); - ret = request_irq(dev->irq, &ni52_interrupt,0,dev->name,dev); - if (ret) - { + ret = request_irq(dev->irq, &ni52_interrupt, 0, dev->name, dev); + if (ret) { ni_reset586(); return ret; } - netif_start_queue(dev); - return 0; /* most done by init */ } /********************************************** * Check to see if there's an 82586 out there. */ -static int check586(struct net_device *dev,char *where,unsigned size) +static int check586(struct net_device *dev, char *where, unsigned size) { struct priv pb; struct priv *p = /* (struct priv *) dev->priv*/ &pb; char *iscp_addrs[2]; int i; - p->base = (unsigned long) isa_bus_to_virt((unsigned long)where) + size - 0x01000000; + p->base = (unsigned long) isa_bus_to_virt((unsigned long)where) + + size - 0x01000000; p->memtop = isa_bus_to_virt((unsigned long)where) + size; p->scp = (struct scp_struct *)(p->base + SCP_DEFAULT_ADDRESS); - memset((char *)p->scp,0, sizeof(struct scp_struct)); - for(i=0;i<sizeof(struct scp_struct);i++) /* memory was writeable? */ - if(((char *)p->scp)[i]) + memset_io((char *)p->scp, 0, sizeof(struct scp_struct)); + for (i = 0; i < sizeof(struct scp_struct); i++) + /* memory was writeable? */ + if (readb((char *)p->scp + i)) return 0; - p->scp->sysbus = SYSBUSVAL; /* 1 = 8Bit-Bus, 0 = 16 Bit */ - if(p->scp->sysbus != SYSBUSVAL) + writeb(SYSBUSVAL, &p->scp->sysbus); /* 1 = 8Bit-Bus, 0 = 16 Bit */ + if (readb(&p->scp->sysbus) != SYSBUSVAL) return 0; iscp_addrs[0] = isa_bus_to_virt((unsigned long)where); - iscp_addrs[1]= (char *) p->scp - sizeof(struct iscp_struct); + iscp_addrs[1] = (char *) p->scp - sizeof(struct iscp_struct); - for(i=0;i<2;i++) - { + for (i = 0; i < 2; i++) { p->iscp = (struct iscp_struct *) iscp_addrs[i]; - memset((char *)p->iscp,0, sizeof(struct iscp_struct)); + memset_io((char *)p->iscp, 0, sizeof(struct iscp_struct)); - p->scp->iscp = make24(p->iscp); - p->iscp->busy = 1; + writel(make24(p->iscp), &p->scp->iscp); + writeb(1, &p->iscp->busy); ni_reset586(); ni_attn586(); - DELAY(1); /* wait a while... */ - - if(p->iscp->busy) /* i82586 clears 'busy' after successful init */ + mdelay(32); /* wait a while... */ + /* i82586 clears 'busy' after successful init */ + if (readb(&p->iscp->busy)) return 0; } return 1; @@ -327,36 +344,39 @@ static void alloc586(struct net_device *dev) struct priv *p = (struct priv *) dev->priv; ni_reset586(); - DELAY(1); + mdelay(32); + + spin_lock_init(&p->spinlock); p->scp = (struct scp_struct *) (p->base + SCP_DEFAULT_ADDRESS); p->scb = (struct scb_struct *) isa_bus_to_virt(dev->mem_start); - p->iscp = (struct iscp_struct *) ((char *)p->scp - sizeof(struct iscp_struct)); + p->iscp = (struct iscp_struct *) + ((char *)p->scp - sizeof(struct iscp_struct)); - memset((char *) p->iscp,0,sizeof(struct iscp_struct)); - memset((char *) p->scp ,0,sizeof(struct scp_struct)); + memset_io(p->iscp, 0, sizeof(struct iscp_struct)); + memset_io(p->scp , 0, sizeof(struct scp_struct)); - p->scp->iscp = make24(p->iscp); - p->scp->sysbus = SYSBUSVAL; - p->iscp->scb_offset = make16(p->scb); + writel(make24(p->iscp), &p->scp->iscp); + writeb(SYSBUSVAL, &p->scp->sysbus); + writew(make16(p->scb), &p->iscp->scb_offset); - p->iscp->busy = 1; + writeb(1, &p->iscp->busy); ni_reset586(); ni_attn586(); - DELAY(1); + mdelay(32); - if(p->iscp->busy) - printk("%s: Init-Problems (alloc).\n",dev->name); + if (readb(&p->iscp->busy)) + printk(KERN_ERR "%s: Init-Problems (alloc).\n", dev->name); - p->reseted = 0; + p->reset = 0; - memset((char *)p->scb,0,sizeof(struct scb_struct)); + memset_io((char *)p->scb, 0, sizeof(struct scb_struct)); } /* set: io,irq,memstart,memend or set it when calling insmod */ -static int irq=9; -static int io=0x300; +static int irq = 9; +static int io = 0x300; static long memstart; /* e.g 0xd0000 */ static long memend; /* e.g 0xd4000 */ @@ -413,7 +433,7 @@ out: return ERR_PTR(err); } -static int __init ni52_probe1(struct net_device *dev,int ioaddr) +static int __init ni52_probe1(struct net_device *dev, int ioaddr) { int i, size, retval; @@ -425,90 +445,96 @@ static int __init ni52_probe1(struct net_device *dev,int ioaddr) if (!request_region(ioaddr, NI52_TOTAL_SIZE, DRV_NAME)) return -EBUSY; - if( !(inb(ioaddr+NI52_MAGIC1) == NI52_MAGICVAL1) || + if (!(inb(ioaddr+NI52_MAGIC1) == NI52_MAGICVAL1) || !(inb(ioaddr+NI52_MAGIC2) == NI52_MAGICVAL2)) { retval = -ENODEV; goto out; } - for(i=0;i<ETH_ALEN;i++) + for (i = 0; i < ETH_ALEN; i++) dev->dev_addr[i] = inb(dev->base_addr+i); - if(dev->dev_addr[0] != NI52_ADDR0 || dev->dev_addr[1] != NI52_ADDR1 + if (dev->dev_addr[0] != NI52_ADDR0 || dev->dev_addr[1] != NI52_ADDR1 || dev->dev_addr[2] != NI52_ADDR2) { retval = -ENODEV; goto out; } - printk(KERN_INFO "%s: NI5210 found at %#3lx, ",dev->name,dev->base_addr); + printk(KERN_INFO "%s: NI5210 found at %#3lx, ", + dev->name, dev->base_addr); /* * check (or search) IO-Memory, 8K and 16K */ #ifdef MODULE size = dev->mem_end - dev->mem_start; - if(size != 0x2000 && size != 0x4000) { - printk("\n%s: Illegal memory size %d. Allowed is 0x2000 or 0x4000 bytes.\n",dev->name,size); + if (size != 0x2000 && size != 0x4000) { + printk("\n"); + printk(KERN_ERR "%s: Invalid memory size %d. Allowed is 0x2000 or 0x4000 bytes.\n", dev->name, size); retval = -ENODEV; goto out; } - if(!check586(dev,(char *) dev->mem_start,size)) { - printk("?memcheck, Can't find memory at 0x%lx with size %d!\n",dev->mem_start,size); + if (!check586(dev, (char *)dev->mem_start, size)) { + printk(KERN_ERR "?memcheck, Can't find memory at 0x%lx with size %d!\n", dev->mem_start, size); retval = -ENODEV; goto out; } #else - if(dev->mem_start != 0) /* no auto-mem-probe */ - { + if (dev->mem_start != 0) { + /* no auto-mem-probe */ size = 0x4000; /* check for 16K mem */ - if(!check586(dev,(char *) dev->mem_start,size)) { + if (!check586(dev, (char *) dev->mem_start, size)) { size = 0x2000; /* check for 8K mem */ - if(!check586(dev,(char *) dev->mem_start,size)) { - printk("?memprobe, Can't find memory at 0x%lx!\n",dev->mem_start); + if (!check586(dev, (char *)dev->mem_start, size)) { + printk(KERN_ERR "?memprobe, Can't find memory at 0x%lx!\n", dev->mem_start); retval = -ENODEV; goto out; } } - } - else - { - static long memaddrs[] = { 0xc8000,0xca000,0xcc000,0xce000,0xd0000,0xd2000, - 0xd4000,0xd6000,0xd8000,0xda000,0xdc000, 0 }; - for(i=0;;i++) - { - if(!memaddrs[i]) { - printk("?memprobe, Can't find io-memory!\n"); + } else { + static const unsigned long memaddrs[] = { + 0xc8000, 0xca000, 0xcc000, 0xce000, 0xd0000, 0xd2000, + 0xd4000, 0xd6000, 0xd8000, 0xda000, 0xdc000, 0 + }; + for (i = 0;; i++) { + if (!memaddrs[i]) { + printk(KERN_ERR "?memprobe, Can't find io-memory!\n"); retval = -ENODEV; goto out; } dev->mem_start = memaddrs[i]; size = 0x2000; /* check for 8K mem */ - if(check586(dev,(char *)dev->mem_start,size)) /* 8K-check */ + if (check586(dev, (char *)dev->mem_start, size)) + /* 8K-check */ break; size = 0x4000; /* check for 16K mem */ - if(check586(dev,(char *)dev->mem_start,size)) /* 16K-check */ + if (check586(dev, (char *)dev->mem_start, size)) + /* 16K-check */ break; } } - dev->mem_end = dev->mem_start + size; /* set mem_end showed by 'ifconfig' */ + /* set mem_end showed by 'ifconfig' */ + dev->mem_end = dev->mem_start + size; #endif - memset((char *) dev->priv,0,sizeof(struct priv)); + memset((char *)dev->priv, 0, sizeof(struct priv)); - ((struct priv *) (dev->priv))->memtop = isa_bus_to_virt(dev->mem_start) + size; - ((struct priv *) (dev->priv))->base = (unsigned long) isa_bus_to_virt(dev->mem_start) + size - 0x01000000; + ((struct priv *)(dev->priv))->memtop = + isa_bus_to_virt(dev->mem_start) + size; + ((struct priv *)(dev->priv))->base = (unsigned long) + isa_bus_to_virt(dev->mem_start) + size - 0x01000000; alloc586(dev); /* set number of receive-buffs according to memsize */ - if(size == 0x2000) + if (size == 0x2000) ((struct priv *) dev->priv)->num_recv_buffs = NUM_RECV_BUFFS_8; else ((struct priv *) dev->priv)->num_recv_buffs = NUM_RECV_BUFFS_16; - printk("Memaddr: 0x%lx, Memsize: %d, ",dev->mem_start,size); + printk(KERN_DEBUG "Memaddr: 0x%lx, Memsize: %d, ", + dev->mem_start, size); - if(dev->irq < 2) - { + if (dev->irq < 2) { unsigned long irq_mask; irq_mask = probe_irq_on(); @@ -517,18 +543,16 @@ static int __init ni52_probe1(struct net_device *dev,int ioaddr) mdelay(20); dev->irq = probe_irq_off(irq_mask); - if(!dev->irq) - { + if (!dev->irq) { printk("?autoirq, Failed to detect IRQ line!\n"); retval = -EAGAIN; goto out; } - printk("IRQ %d (autodetected).\n",dev->irq); - } - else { - if(dev->irq == 2) + printk("IRQ %d (autodetected).\n", dev->irq); + } else { + if (dev->irq == 2) dev->irq = 9; - printk("IRQ %d (assigned and not checked!).\n",dev->irq); + printk("IRQ %d (assigned and not checked!).\n", dev->irq); } dev->open = ni52_open; @@ -555,56 +579,58 @@ out: static int init586(struct net_device *dev) { void *ptr; - int i,result=0; - struct priv *p = (struct priv *) dev->priv; - volatile struct configure_cmd_struct *cfg_cmd; - volatile struct iasetup_cmd_struct *ias_cmd; - volatile struct tdr_cmd_struct *tdr_cmd; - volatile struct mcsetup_cmd_struct *mc_cmd; - struct dev_mc_list *dmi=dev->mc_list; - int num_addrs=dev->mc_count; + int i, result = 0; + struct priv *p = (struct priv *)dev->priv; + struct configure_cmd_struct *cfg_cmd; + struct iasetup_cmd_struct *ias_cmd; + struct tdr_cmd_struct *tdr_cmd; + struct mcsetup_cmd_struct *mc_cmd; + struct dev_mc_list *dmi = dev->mc_list; + int num_addrs = dev->mc_count; ptr = (void *) ((char *)p->scb + sizeof(struct scb_struct)); cfg_cmd = (struct configure_cmd_struct *)ptr; /* configure-command */ - cfg_cmd->cmd_status = 0; - cfg_cmd->cmd_cmd = CMD_CONFIGURE | CMD_LAST; - cfg_cmd->cmd_link = 0xffff; - - cfg_cmd->byte_cnt = 0x0a; /* number of cfg bytes */ - cfg_cmd->fifo = fifo; /* fifo-limit (8=tx:32/rx:64) */ - cfg_cmd->sav_bf = 0x40; /* hold or discard bad recv frames (bit 7) */ - cfg_cmd->adr_len = 0x2e; /* addr_len |!src_insert |pre-len |loopback */ - cfg_cmd->priority = 0x00; - cfg_cmd->ifs = 0x60; - cfg_cmd->time_low = 0x00; - cfg_cmd->time_high = 0xf2; - cfg_cmd->promisc = 0; - if(dev->flags & IFF_ALLMULTI) { + writew(0, &cfg_cmd->cmd_status); + writew(CMD_CONFIGURE | CMD_LAST, &cfg_cmd->cmd_cmd); + writew(0xFFFF, &cfg_cmd->cmd_link); + + /* number of cfg bytes */ + writeb(0x0a, &cfg_cmd->byte_cnt); + /* fifo-limit (8=tx:32/rx:64) */ + writeb(fifo, &cfg_cmd->fifo); + /* hold or discard bad recv frames (bit 7) */ + writeb(0x40, &cfg_cmd->sav_bf); + /* addr_len |!src_insert |pre-len |loopback */ + writeb(0x2e, &cfg_cmd->adr_len); + writeb(0x00, &cfg_cmd->priority); + writeb(0x60, &cfg_cmd->ifs);; + writeb(0x00, &cfg_cmd->time_low); + writeb(0xf2, &cfg_cmd->time_high); + writeb(0x00, &cfg_cmd->promisc);; + if (dev->flags & IFF_ALLMULTI) { int len = ((char *) p->iscp - (char *) ptr - 8) / 6; - if(num_addrs > len) { - printk("%s: switching to promisc. mode\n",dev->name); - dev->flags|=IFF_PROMISC; + if (num_addrs > len) { + printk(KERN_ERR "%s: switching to promisc. mode\n", + dev->name); + dev->flags |= IFF_PROMISC; } } - if(dev->flags&IFF_PROMISC) - { - cfg_cmd->promisc=1; - dev->flags|=IFF_PROMISC; - } - cfg_cmd->carr_coll = 0x00; + if (dev->flags & IFF_PROMISC) + writeb(0x01, &cfg_cmd->promisc); + writeb(0x00, &cfg_cmd->carr_coll); + writew(make16(cfg_cmd), &p->scb->cbl_offset); + writew(0, &p->scb->cmd_ruc); - p->scb->cbl_offset = make16(cfg_cmd); - p->scb->cmd_ruc = 0; - - p->scb->cmd_cuc = CUC_START; /* cmd.-unit start */ + writeb(CUC_START, &p->scb->cmd_cuc); /* cmd.-unit start */ ni_attn586(); - WAIT_4_STAT_COMPL(cfg_cmd); + wait_for_stat_compl(cfg_cmd); - if((cfg_cmd->cmd_status & (STAT_OK|STAT_COMPL)) != (STAT_COMPL|STAT_OK)) - { - printk("%s: configure command failed: %x\n",dev->name,cfg_cmd->cmd_status); + if ((readw(&cfg_cmd->cmd_status) & (STAT_OK|STAT_COMPL)) != + (STAT_COMPL|STAT_OK)) { + printk(KERN_ERR "%s: configure command failed: %x\n", + dev->name, readw(&cfg_cmd->cmd_status)); return 1; } @@ -614,21 +640,22 @@ static int init586(struct net_device *dev) ias_cmd = (struct iasetup_cmd_struct *)ptr; - ias_cmd->cmd_status = 0; - ias_cmd->cmd_cmd = CMD_IASETUP | CMD_LAST; - ias_cmd->cmd_link = 0xffff; + writew(0, &ias_cmd->cmd_status); + writew(CMD_IASETUP | CMD_LAST, &ias_cmd->cmd_cmd); + writew(0xffff, &ias_cmd->cmd_link); - memcpy((char *)&ias_cmd->iaddr,(char *) dev->dev_addr,ETH_ALEN); + memcpy_toio((char *)&ias_cmd->iaddr, (char *)dev->dev_addr, ETH_ALEN); - p->scb->cbl_offset = make16(ias_cmd); + writew(make16(ias_cmd), &p->scb->cbl_offset); - p->scb->cmd_cuc = CUC_START; /* cmd.-unit start */ + writeb(CUC_START, &p->scb->cmd_cuc); /* cmd.-unit start */ ni_attn586(); - WAIT_4_STAT_COMPL(ias_cmd); + wait_for_stat_compl(ias_cmd); - if((ias_cmd->cmd_status & (STAT_OK|STAT_COMPL)) != (STAT_OK|STAT_COMPL)) { - printk("%s (ni52): individual address setup command failed: %04x\n",dev->name,ias_cmd->cmd_status); + if ((readw(&ias_cmd->cmd_status) & (STAT_OK|STAT_COMPL)) != + (STAT_OK|STAT_COMPL)) { + printk(KERN_ERR "%s (ni52): individual address setup command failed: %04x\n", dev->name, readw(&ias_cmd->cmd_status)); return 1; } @@ -638,117 +665,119 @@ static int init586(struct net_device *dev) tdr_cmd = (struct tdr_cmd_struct *)ptr; - tdr_cmd->cmd_status = 0; - tdr_cmd->cmd_cmd = CMD_TDR | CMD_LAST; - tdr_cmd->cmd_link = 0xffff; - tdr_cmd->status = 0; + writew(0, &tdr_cmd->cmd_status); + writew(CMD_TDR | CMD_LAST, &tdr_cmd->cmd_cmd); + writew(0xffff, &tdr_cmd->cmd_link); + writew(0, &tdr_cmd->status); - p->scb->cbl_offset = make16(tdr_cmd); - p->scb->cmd_cuc = CUC_START; /* cmd.-unit start */ + writew(make16(tdr_cmd), &p->scb->cbl_offset); + writeb(CUC_START, &p->scb->cmd_cuc); /* cmd.-unit start */ ni_attn586(); - WAIT_4_STAT_COMPL(tdr_cmd); - - if(!(tdr_cmd->cmd_status & STAT_COMPL)) - { - printk("%s: Problems while running the TDR.\n",dev->name); - } - else - { - DELAY_16(); /* wait for result */ - result = tdr_cmd->status; + wait_for_stat_compl(tdr_cmd); - p->scb->cmd_cuc = p->scb->cus & STAT_MASK; + if (!(readw(&tdr_cmd->cmd_status) & STAT_COMPL)) + printk(KERN_ERR "%s: Problems while running the TDR.\n", + dev->name); + else { + udelay(16); + result = readw(&tdr_cmd->status); + writeb(readb(&p->scb->cus) & STAT_MASK, &p->scb->cmd_cuc); ni_attn586(); /* ack the interrupts */ - if(result & TDR_LNK_OK) + if (result & TDR_LNK_OK) ; - else if(result & TDR_XCVR_PRB) - printk("%s: TDR: Transceiver problem. Check the cable(s)!\n",dev->name); - else if(result & TDR_ET_OPN) - printk("%s: TDR: No correct termination %d clocks away.\n",dev->name,result & TDR_TIMEMASK); - else if(result & TDR_ET_SRT) - { - if (result & TDR_TIMEMASK) /* time == 0 -> strange :-) */ - printk("%s: TDR: Detected a short circuit %d clocks away.\n",dev->name,result & TDR_TIMEMASK); - } - else - printk("%s: TDR: Unknown status %04x\n",dev->name,result); + else if (result & TDR_XCVR_PRB) + printk(KERN_ERR "%s: TDR: Transceiver problem. Check the cable(s)!\n", + dev->name); + else if (result & TDR_ET_OPN) + printk(KERN_ERR "%s: TDR: No correct termination %d clocks away.\n", + dev->name, result & TDR_TIMEMASK); + else if (result & TDR_ET_SRT) { + /* time == 0 -> strange :-) */ + if (result & TDR_TIMEMASK) + printk(KERN_ERR "%s: TDR: Detected a short circuit %d clocks away.\n", + dev->name, result & TDR_TIMEMASK); + } else + printk(KERN_ERR "%s: TDR: Unknown status %04x\n", + dev->name, result); } /* * Multicast setup */ - if(num_addrs && !(dev->flags & IFF_PROMISC) ) - { + if (num_addrs && !(dev->flags & IFF_PROMISC)) { mc_cmd = (struct mcsetup_cmd_struct *) ptr; - mc_cmd->cmd_status = 0; - mc_cmd->cmd_cmd = CMD_MCSETUP | CMD_LAST; - mc_cmd->cmd_link = 0xffff; - mc_cmd->mc_cnt = num_addrs * 6; + writew(0, &mc_cmd->cmd_status); + writew(CMD_MCSETUP | CMD_LAST, &mc_cmd->cmd_cmd); + writew(0xffff, &mc_cmd->cmd_link); + writew(num_addrs * 6, &mc_cmd->mc_cnt); - for(i=0;i<num_addrs;i++,dmi=dmi->next) - memcpy((char *) mc_cmd->mc_list[i], dmi->dmi_addr,6); + for (i = 0; i < num_addrs; i++, dmi = dmi->next) + memcpy_toio((char *) mc_cmd->mc_list[i], + dmi->dmi_addr, 6); - p->scb->cbl_offset = make16(mc_cmd); - p->scb->cmd_cuc = CUC_START; + writew(make16(mc_cmd), &p->scb->cbl_offset); + writeb(CUC_START, &p->scb->cmd_cuc); ni_attn586(); - WAIT_4_STAT_COMPL(mc_cmd); + wait_for_stat_compl(mc_cmd); - if( (mc_cmd->cmd_status & (STAT_COMPL|STAT_OK)) != (STAT_COMPL|STAT_OK) ) - printk("%s: Can't apply multicast-address-list.\n",dev->name); + if ((readw(&mc_cmd->cmd_status) & (STAT_COMPL|STAT_OK)) + != (STAT_COMPL|STAT_OK)) + printk(KERN_ERR "%s: Can't apply multicast-address-list.\n", dev->name); } /* * alloc nop/xmit-cmds */ #if (NUM_XMIT_BUFFS == 1) - for(i=0;i<2;i++) - { - p->nop_cmds[i] = (struct nop_cmd_struct *)ptr; - p->nop_cmds[i]->cmd_cmd = CMD_NOP; - p->nop_cmds[i]->cmd_status = 0; - p->nop_cmds[i]->cmd_link = make16((p->nop_cmds[i])); + for (i = 0; i < 2; i++) { + p->nop_cmds[i] = (struct nop_cmd_struct *)ptr; + writew(CMD_NOP, &p->nop_cmds[i]->cmd_cmd); + writew(0, &p->nop_cmds[i]->cmd_status); + writew(make16(p->nop_cmds[i]), &p->nop_cmds[i]->cmd_link); ptr = (char *) ptr + sizeof(struct nop_cmd_struct); } #else - for(i=0;i<NUM_XMIT_BUFFS;i++) - { - p->nop_cmds[i] = (struct nop_cmd_struct *)ptr; - p->nop_cmds[i]->cmd_cmd = CMD_NOP; - p->nop_cmds[i]->cmd_status = 0; - p->nop_cmds[i]->cmd_link = make16((p->nop_cmds[i])); + for (i = 0; i < NUM_XMIT_BUFFS; i++) { + p->nop_cmds[i] = (struct nop_cmd_struct *)ptr; + writew(CMD_NOP, &p->nop_cmds[i]->cmd_cmd); + writew(0, &p->nop_cmds[i]->cmd_status); + writew(make16(p->nop_cmds[i]), &p->nop_cmds[i]->cmd_link); ptr = (char *) ptr + sizeof(struct nop_cmd_struct); } #endif - ptr = alloc_rfa(dev,(void *)ptr); /* init receive-frame-area */ + ptr = alloc_rfa(dev, (void *)ptr); /* init receive-frame-area */ /* * alloc xmit-buffs / init xmit_cmds */ - for(i=0;i<NUM_XMIT_BUFFS;i++) - { - p->xmit_cmds[i] = (struct transmit_cmd_struct *)ptr; /*transmit cmd/buff 0*/ + for (i = 0; i < NUM_XMIT_BUFFS; i++) { + /* Transmit cmd/buff 0 */ + p->xmit_cmds[i] = (struct transmit_cmd_struct *)ptr; ptr = (char *) ptr + sizeof(struct transmit_cmd_struct); p->xmit_cbuffs[i] = (char *)ptr; /* char-buffs */ ptr = (char *) ptr + XMIT_BUFF_SIZE; p->xmit_buffs[i] = (struct tbd_struct *)ptr; /* TBD */ ptr = (char *) ptr + sizeof(struct tbd_struct); - if((void *)ptr > (void *)p->iscp) - { - printk("%s: not enough shared-mem for your configuration!\n",dev->name); + if ((void *)ptr > (void *)p->iscp) { + printk(KERN_ERR "%s: not enough shared-mem for your configuration!\n", + dev->name); return 1; } - memset((char *)(p->xmit_cmds[i]) ,0, sizeof(struct transmit_cmd_struct)); - memset((char *)(p->xmit_buffs[i]),0, sizeof(struct tbd_struct)); - p->xmit_cmds[i]->cmd_link = make16(p->nop_cmds[(i+1)%NUM_XMIT_BUFFS]); - p->xmit_cmds[i]->cmd_status = STAT_COMPL; - p->xmit_cmds[i]->cmd_cmd = CMD_XMIT | CMD_INT; - p->xmit_cmds[i]->tbd_offset = make16((p->xmit_buffs[i])); - p->xmit_buffs[i]->next = 0xffff; - p->xmit_buffs[i]->buffer = make24((p->xmit_cbuffs[i])); + memset_io((char *)(p->xmit_cmds[i]), 0, + sizeof(struct transmit_cmd_struct)); + memset_io((char *)(p->xmit_buffs[i]), 0, + sizeof(struct tbd_struct)); + writew(make16(p->nop_cmds[(i+1)%NUM_XMIT_BUFFS]), + &p->xmit_cmds[i]->cmd_link); + writew(STAT_COMPL, &p->xmit_cmds[i]->cmd_status); + writew(CMD_XMIT|CMD_INT, &p->xmit_cmds[i]->cmd_cmd); + writew(make16(p->xmit_buffs[i]), &p->xmit_cmds[i]->tbd_offset); + writew(0xffff, &p->xmit_buffs[i]->next); + writel(make24(p->xmit_cbuffs[i]), &p->xmit_buffs[i]->buffer); } p->xmit_count = 0; @@ -761,21 +790,21 @@ static int init586(struct net_device *dev) * 'start transmitter' */ #ifndef NO_NOPCOMMANDS - p->scb->cbl_offset = make16(p->nop_cmds[0]); - p->scb->cmd_cuc = CUC_START; + writew(make16(p->nop_cmds[0]), &p->scb->cbl_offset); + writeb(CUC_START, &p->scb->cmd_cuc); ni_attn586(); - WAIT_4_SCB_CMD(); + wait_for_scb_cmd(dev); #else - p->xmit_cmds[0]->cmd_link = make16(p->xmit_cmds[0]); - p->xmit_cmds[0]->cmd_cmd = CMD_XMIT | CMD_SUSPEND | CMD_INT; + writew(make16(p->xmit_cmds[0]), &p->xmit_cmds[0]->cmd_link); + writew(CMD_XMIT | CMD_SUSPEND | CMD_INT, &p->xmit_cmds[0]->cmd_cmd); #endif /* * ack. interrupts */ - p->scb->cmd_cuc = p->scb->cus & STAT_MASK; + writeb(readb(&p->scb->cus) & STAT_MASK, &p->scb->cmd_cuc); ni_attn586(); - DELAY_16(); + udelay(16); ni_enaint(); @@ -787,43 +816,45 @@ static int init586(struct net_device *dev) * It sets up the Receive Frame Area (RFA). */ -static void *alloc_rfa(struct net_device *dev,void *ptr) +static void *alloc_rfa(struct net_device *dev, void *ptr) { - volatile struct rfd_struct *rfd = (struct rfd_struct *)ptr; - volatile struct rbd_struct *rbd; + struct rfd_struct *rfd = (struct rfd_struct *)ptr; + struct rbd_struct *rbd; int i; struct priv *p = (struct priv *) dev->priv; - memset((char *) rfd,0,sizeof(struct rfd_struct)*(p->num_recv_buffs+rfdadd)); + memset_io((char *) rfd, 0, + sizeof(struct rfd_struct) * (p->num_recv_buffs + rfdadd)); p->rfd_first = rfd; - for(i = 0; i < (p->num_recv_buffs+rfdadd); i++) { - rfd[i].next = make16(rfd + (i+1) % (p->num_recv_buffs+rfdadd) ); - rfd[i].rbd_offset = 0xffff; + for (i = 0; i < (p->num_recv_buffs + rfdadd); i++) { + writew(make16(rfd + (i+1) % (p->num_recv_buffs+rfdadd)), + &rfd[i].next); + writew(0xffff, &rfd[i].rbd_offset); } - rfd[p->num_recv_buffs-1+rfdadd].last = RFD_SUSP; /* RU suspend */ + /* RU suspend */ + writeb(RFD_SUSP, &rfd[p->num_recv_buffs-1+rfdadd].last); - ptr = (void *) (rfd + (p->num_recv_buffs + rfdadd) ); + ptr = (void *) (rfd + (p->num_recv_buffs + rfdadd)); rbd = (struct rbd_struct *) ptr; ptr = (void *) (rbd + p->num_recv_buffs); /* clr descriptors */ - memset((char *) rbd,0,sizeof(struct rbd_struct)*(p->num_recv_buffs)); + memset_io((char *)rbd, 0, + sizeof(struct rbd_struct) * (p->num_recv_buffs)); - for(i=0;i<p->num_recv_buffs;i++) - { - rbd[i].next = make16((rbd + (i+1) % p->num_recv_buffs)); - rbd[i].size = RECV_BUFF_SIZE; - rbd[i].buffer = make24(ptr); + for (i = 0; i < p->num_recv_buffs; i++) { + writew(make16(rbd + (i+1) % p->num_recv_buffs), &rbd[i].next); + writew(RECV_BUFF_SIZE, &rbd[i].size); + writel(make24(ptr), &rbd[i].buffer); ptr = (char *) ptr + RECV_BUFF_SIZE; } - p->rfd_top = p->rfd_first; p->rfd_last = p->rfd_first + (p->num_recv_buffs - 1 + rfdadd); - p->scb->rfa_offset = make16(p->rfd_first); - p->rfd_first->rbd_offset = make16(rbd); + writew(make16(p->rfd_first), &p->scb->rfa_offset); + writew(make16(rbd), &p->rfd_first->rbd_offset); return ptr; } @@ -833,73 +864,71 @@ static void *alloc_rfa(struct net_device *dev,void *ptr) * Interrupt Handler ... */ -static irqreturn_t ni52_interrupt(int irq,void *dev_id) +static irqreturn_t ni52_interrupt(int irq, void *dev_id) { struct net_device *dev = dev_id; - unsigned short stat; - int cnt=0; + unsigned int stat; + int cnt = 0; struct priv *p; - if (!dev) { - printk ("ni5210-interrupt: irq %d for unknown device.\n",irq); - return IRQ_NONE; - } p = (struct priv *) dev->priv; - if(debuglevel > 1) + if (debuglevel > 1) printk("I"); - WAIT_4_SCB_CMD(); /* wait for last command */ + spin_lock(&p->spinlock); - while((stat=p->scb->cus & STAT_MASK)) - { - p->scb->cmd_cuc = stat; + wait_for_scb_cmd(dev); /* wait for last command */ + + while ((stat = readb(&p->scb->cus) & STAT_MASK)) { + writeb(stat, &p->scb->cmd_cuc); ni_attn586(); - if(stat & STAT_FR) /* received a frame */ + if (stat & STAT_FR) /* received a frame */ ni52_rcv_int(dev); - if(stat & STAT_RNR) /* RU went 'not ready' */ - { + if (stat & STAT_RNR) { /* RU went 'not ready' */ printk("(R)"); - if(p->scb->rus & RU_SUSPEND) /* special case: RU_SUSPEND */ - { - WAIT_4_SCB_CMD(); + if (readb(&p->scb->rus) & RU_SUSPEND) { + /* special case: RU_SUSPEND */ + wait_for_scb_cmd(dev); p->scb->cmd_ruc = RUC_RESUME; ni_attn586(); - WAIT_4_SCB_CMD_RUC(); - } - else - { - printk("%s: Receiver-Unit went 'NOT READY': %04x/%02x.\n",dev->name,(int) stat,(int) p->scb->rus); + wait_for_scb_cmd_ruc(dev); + } else { + printk(KERN_ERR "%s: Receiver-Unit went 'NOT READY': %04x/%02x.\n", + dev->name, stat, readb(&p->scb->rus)); ni52_rnr_int(dev); } } - if(stat & STAT_CX) /* command with I-bit set complete */ + /* Command with I-bit set complete */ + if (stat & STAT_CX) ni52_xmt_int(dev); #ifndef NO_NOPCOMMANDS - if(stat & STAT_CNA) /* CU went 'not ready' */ - { - if(netif_running(dev)) - printk("%s: oops! CU has left active state. stat: %04x/%02x.\n",dev->name,(int) stat,(int) p->scb->cus); + if (stat & STAT_CNA) { /* CU went 'not ready' */ + if (netif_running(dev)) + printk(KERN_ERR "%s: oops! CU has left active state. stat: %04x/%02x.\n", + dev->name, stat, readb(&p->scb->cus)); } #endif - if(debuglevel > 1) - printk("%d",cnt++); + if (debuglevel > 1) + printk("%d", cnt++); - WAIT_4_SCB_CMD(); /* wait for ack. (ni52_xmt_int can be faster than ack!!) */ - if(p->scb->cmd_cuc) /* timed out? */ - { - printk("%s: Acknowledge timed out.\n",dev->name); + /* Wait for ack. (ni52_xmt_int can be faster than ack!!) */ + wait_for_scb_cmd(dev); + if (p->scb->cmd_cuc) { /* timed out? */ + printk(KERN_ERR "%s: Acknowledge timed out.\n", + dev->name); ni_disint(); break; } } + spin_unlock(&p->spinlock); - if(debuglevel > 1) + if (debuglevel > 1) printk("i"); return IRQ_HANDLED; } @@ -910,121 +939,91 @@ static irqreturn_t ni52_interrupt(int irq,void *dev_id) static void ni52_rcv_int(struct net_device *dev) { - int status,cnt=0; + int status, cnt = 0; unsigned short totlen; struct sk_buff *skb; struct rbd_struct *rbd; - struct priv *p = (struct priv *) dev->priv; + struct priv *p = (struct priv *)dev->priv; - if(debuglevel > 0) + if (debuglevel > 0) printk("R"); - for(;(status = p->rfd_top->stat_high) & RFD_COMPL;) - { - rbd = (struct rbd_struct *) make32(p->rfd_top->rbd_offset); - - if(status & RFD_OK) /* frame received without error? */ - { - if( (totlen = rbd->status) & RBD_LAST) /* the first and the last buffer? */ - { - totlen &= RBD_MASK; /* length of this frame */ - rbd->status = 0; - skb = (struct sk_buff *) dev_alloc_skb(totlen+2); - if(skb != NULL) - { - skb_reserve(skb,2); - skb_put(skb,totlen); - skb_copy_to_linear_data(skb,(char *) p->base+(unsigned long) rbd->buffer,totlen); - skb->protocol=eth_type_trans(skb,dev); - netif_rx(skb); - dev->last_rx = jiffies; - p->stats.rx_packets++; - p->stats.rx_bytes += totlen; + for (; (status = readb(&p->rfd_top->stat_high)) & RFD_COMPL;) { + rbd = (struct rbd_struct *) make32(p->rfd_top->rbd_offset); + if (status & RFD_OK) { /* frame received without error? */ + totlen = readw(&rbd->status); + if (totlen & RBD_LAST) { + /* the first and the last buffer? */ + totlen &= RBD_MASK; /* length of this frame */ + writew(0x00, &rbd->status); + skb = (struct sk_buff *)dev_alloc_skb(totlen+2); + if (skb != NULL) { + skb_reserve(skb, 2); + skb_put(skb, totlen); + skb_copy_to_linear_data(skb, (char *)p->base + (unsigned long) rbd->buffer, totlen); + skb->protocol = eth_type_trans(skb, dev); + netif_rx(skb); + dev->last_rx = jiffies; + p->stats.rx_packets++; + p->stats.rx_bytes += totlen; + } else + p->stats.rx_dropped++; + } else { + int rstat; + /* free all RBD's until RBD_LAST is set */ + totlen = 0; + while (!((rstat = readw(&rbd->status)) & RBD_LAST)) { + totlen += rstat & RBD_MASK; + if (!rstat) { + printk(KERN_ERR "%s: Whoops .. no end mark in RBD list\n", dev->name); + break; } - else - p->stats.rx_dropped++; + writew(0, &rbd->status); + rbd = (struct rbd_struct *) make32(readl(&rbd->next)); } - else - { - int rstat; - /* free all RBD's until RBD_LAST is set */ - totlen = 0; - while(!((rstat=rbd->status) & RBD_LAST)) - { - totlen += rstat & RBD_MASK; - if(!rstat) - { - printk("%s: Whoops .. no end mark in RBD list\n",dev->name); - break; - } - rbd->status = 0; - rbd = (struct rbd_struct *) make32(rbd->next); - } - totlen += rstat & RBD_MASK; - rbd->status = 0; - printk("%s: received oversized frame! length: %d\n",dev->name,totlen); - p->stats.rx_dropped++; + totlen += rstat & RBD_MASK; + writew(0, &rbd->status); + printk(KERN_ERR "%s: received oversized frame! length: %d\n", + dev->name, totlen); + p->stats.rx_dropped++; } - } - else /* frame !(ok), only with 'save-bad-frames' */ - { - printk("%s: oops! rfd-error-status: %04x\n",dev->name,status); + } else {/* frame !(ok), only with 'save-bad-frames' */ + printk(KERN_ERR "%s: oops! rfd-error-status: %04x\n", + dev->name, status); p->stats.rx_errors++; } - p->rfd_top->stat_high = 0; - p->rfd_top->last = RFD_SUSP; /* maybe exchange by RFD_LAST */ - p->rfd_top->rbd_offset = 0xffff; - p->rfd_last->last = 0; /* delete RFD_SUSP */ + writeb(0, &p->rfd_top->stat_high); + writeb(RFD_SUSP, &p->rfd_top->last); /* maybe exchange by RFD_LAST */ + writew(0xffff, &p->rfd_top->rbd_offset); + writeb(0, &p->rfd_last->last); /* delete RFD_SUSP */ p->rfd_last = p->rfd_top; p->rfd_top = (struct rfd_struct *) make32(p->rfd_top->next); /* step to next RFD */ - p->scb->rfa_offset = make16(p->rfd_top); + writew(make16(p->rfd_top), &p->scb->rfa_offset); - if(debuglevel > 0) - printk("%d",cnt++); + if (debuglevel > 0) + printk("%d", cnt++); } - if(automatic_resume) - { - WAIT_4_SCB_CMD(); - p->scb->cmd_ruc = RUC_RESUME; + if (automatic_resume) { + wait_for_scb_cmd(dev); + writeb(RUC_RESUME, &p->scb->cmd_ruc); ni_attn586(); - WAIT_4_SCB_CMD_RUC(); + wait_for_scb_cmd_ruc(dev); } #ifdef WAIT_4_BUSY { int i; - for(i=0;i<1024;i++) - { - if(p->rfd_top->status) + for (i = 0; i < 1024; i++) { + if (p->rfd_top->status) break; - DELAY_16(); - if(i == 1023) - printk("%s: RU hasn't fetched next RFD (not busy/complete)\n",dev->name); + udelay(16); + if (i == 1023) + printk(KERN_ERR "%s: RU hasn't fetched next RFD (not busy/complete)\n", dev->name); } } #endif - -#if 0 - if(!at_least_one) - { - int i; - volatile struct rfd_struct *rfds=p->rfd_top; - volatile struct rbd_struct *rbds; - printk("%s: received a FC intr. without having a frame: %04x %d\n",dev->name,status,old_at_least); - for(i=0;i< (p->num_recv_buffs+4);i++) - { - rbds = (struct rbd_struct *) make32(rfds->rbd_offset); - printk("%04x:%04x ",rfds->status,rbds->status); - rfds = (struct rfd_struct *) make32(rfds->next); - } - printk("\nerrs: %04x %04x stat: %04x\n",(int)p->scb->rsc_errs,(int)p->scb->ovrn_errs,(int)p->scb->status); - printk("\nerrs: %04x %04x rus: %02x, cus: %02x\n",(int)p->scb->rsc_errs,(int)p->scb->ovrn_errs,(int)p->scb->rus,(int)p->scb->cus); - } - old_at_least = at_least_one; -#endif - - if(debuglevel > 0) + if (debuglevel > 0) printk("r"); } @@ -1038,16 +1037,16 @@ static void ni52_rnr_int(struct net_device *dev) p->stats.rx_errors++; - WAIT_4_SCB_CMD(); /* wait for the last cmd, WAIT_4_FULLSTAT?? */ - p->scb->cmd_ruc = RUC_ABORT; /* usually the RU is in the 'no resource'-state .. abort it now. */ + wait_for_scb_cmd(dev); /* wait for the last cmd, WAIT_4_FULLSTAT?? */ + writeb(RUC_ABORT, &p->scb->cmd_ruc); /* usually the RU is in the 'no resource'-state .. abort it now. */ ni_attn586(); - WAIT_4_SCB_CMD_RUC(); /* wait for accept cmd. */ + wait_for_scb_cmd_ruc(dev); /* wait for accept cmd. */ - alloc_rfa(dev,(char *)p->rfd_first); -/* maybe add a check here, before restarting the RU */ + alloc_rfa(dev, (char *)p->rfd_first); + /* maybe add a check here, before restarting the RU */ startrecv586(dev); /* restart RU */ - printk("%s: Receive-Unit restarted. Status: %04x\n",dev->name,p->scb->rus); + printk(KERN_ERR "%s: Receive-Unit restarted. Status: %04x\n", dev->name, p->scb->rus); } @@ -1060,43 +1059,41 @@ static void ni52_xmt_int(struct net_device *dev) int status; struct priv *p = (struct priv *) dev->priv; - if(debuglevel > 0) + if (debuglevel > 0) printk("X"); - status = p->xmit_cmds[p->xmit_last]->cmd_status; - if(!(status & STAT_COMPL)) - printk("%s: strange .. xmit-int without a 'COMPLETE'\n",dev->name); + status = readw(&p->xmit_cmds[p->xmit_last]->cmd_status); + if (!(status & STAT_COMPL)) + printk(KERN_ERR "%s: strange .. xmit-int without a 'COMPLETE'\n", dev->name); - if(status & STAT_OK) - { + if (status & STAT_OK) { p->stats.tx_packets++; p->stats.collisions += (status & TCMD_MAXCOLLMASK); - } - else - { + } else { p->stats.tx_errors++; - if(status & TCMD_LATECOLL) { - printk("%s: late collision detected.\n",dev->name); + if (status & TCMD_LATECOLL) { + printk(KERN_ERR "%s: late collision detected.\n", + dev->name); p->stats.collisions++; - } - else if(status & TCMD_NOCARRIER) { + } else if (status & TCMD_NOCARRIER) { p->stats.tx_carrier_errors++; - printk("%s: no carrier detected.\n",dev->name); - } - else if(status & TCMD_LOSTCTS) - printk("%s: loss of CTS detected.\n",dev->name); - else if(status & TCMD_UNDERRUN) { + printk(KERN_ERR "%s: no carrier detected.\n", + dev->name); + } else if (status & TCMD_LOSTCTS) + printk(KERN_ERR "%s: loss of CTS detected.\n", + dev->name); + else if (status & TCMD_UNDERRUN) { p->stats.tx_fifo_errors++; - printk("%s: DMA underrun detected.\n",dev->name); - } - else if(status & TCMD_MAXCOLL) { - printk("%s: Max. collisions exceeded.\n",dev->name); + printk(KERN_ERR "%s: DMA underrun detected.\n", + dev->name); + } else if (status & TCMD_MAXCOLL) { + printk(KERN_ERR "%s: Max. collisions exceeded.\n", + dev->name); p->stats.collisions += 16; } } - #if (NUM_XMIT_BUFFS > 1) - if( (++p->xmit_last) == NUM_XMIT_BUFFS) + if ((++p->xmit_last) == NUM_XMIT_BUFFS) p->xmit_last = 0; #endif netif_wake_queue(dev); @@ -1110,41 +1107,51 @@ static void startrecv586(struct net_device *dev) { struct priv *p = (struct priv *) dev->priv; - WAIT_4_SCB_CMD(); - WAIT_4_SCB_CMD_RUC(); - p->scb->rfa_offset = make16(p->rfd_first); - p->scb->cmd_ruc = RUC_START; + wait_for_scb_cmd(dev); + wait_for_scb_cmd_ruc(dev); + writew(make16(p->rfd_first), &p->scb->rfa_offset); + writeb(RUC_START, &p->scb->cmd_ruc); ni_attn586(); /* start cmd. */ - WAIT_4_SCB_CMD_RUC(); /* wait for accept cmd. (no timeout!!) */ + wait_for_scb_cmd_ruc(dev); + /* wait for accept cmd. (no timeout!!) */ } static void ni52_timeout(struct net_device *dev) { struct priv *p = (struct priv *) dev->priv; #ifndef NO_NOPCOMMANDS - if(p->scb->cus & CU_ACTIVE) /* COMMAND-UNIT active? */ - { + if (readb(&p->scb->cus) & CU_ACTIVE) { /* COMMAND-UNIT active? */ netif_wake_queue(dev); #ifdef DEBUG - printk("%s: strange ... timeout with CU active?!?\n",dev->name); - printk("%s: X0: %04x N0: %04x N1: %04x %d\n",dev->name,(int)p->xmit_cmds[0]->cmd_status,(int)p->nop_cmds[0]->cmd_status,(int)p->nop_cmds[1]->cmd_status,(int)p->nop_point); + printk(KERN_ERR "%s: strange ... timeout with CU active?!?\n", + dev->name); + printk(KERN_ERR "%s: X0: %04x N0: %04x N1: %04x %d\n", + dev->name, (int)p->xmit_cmds[0]->cmd_status, + readw(&p->nop_cmds[0]->cmd_status), + readw(&p->nop_cmds[1]->cmd_status), + p->nop_point); #endif - p->scb->cmd_cuc = CUC_ABORT; + writeb(CUC_ABORT, &p->scb->cmd_cuc); ni_attn586(); - WAIT_4_SCB_CMD(); - p->scb->cbl_offset = make16(p->nop_cmds[p->nop_point]); - p->scb->cmd_cuc = CUC_START; + wait_for_scb_cmd(dev); + writew(make16(p->nop_cmds[p->nop_point]), &p->scb->cbl_offset); + writeb(CUC_START, &p->scb->cmd_cuc); ni_attn586(); - WAIT_4_SCB_CMD(); + wait_for_scb_cmd(dev); dev->trans_start = jiffies; return 0; } #endif { #ifdef DEBUG - printk("%s: xmitter timed out, try to restart! stat: %02x\n",dev->name,p->scb->cus); - printk("%s: command-stats: %04x %04x\n",dev->name,p->xmit_cmds[0]->cmd_status,p->xmit_cmds[1]->cmd_status); - printk("%s: check, whether you set the right interrupt number!\n",dev->name); + printk(KERN_ERR "%s: xmitter timed out, try to restart! stat: %02x\n", + dev->name, readb(&p->scb->cus)); + printk(KERN_ERR "%s: command-stats: %04x %04x\n", + dev->name, + readw(&p->xmit_cmds[0]->cmd_status), + readw(&p->xmit_cmds[1]->cmd_status)); + printk(KERN_ERR "%s: check, whether you set the right interrupt number!\n", + dev->name); #endif ni52_close(dev); ni52_open(dev); @@ -1158,110 +1165,99 @@ static void ni52_timeout(struct net_device *dev) static int ni52_send_packet(struct sk_buff *skb, struct net_device *dev) { - int len,i; + int len, i; #ifndef NO_NOPCOMMANDS int next_nop; #endif struct priv *p = (struct priv *) dev->priv; - if(skb->len > XMIT_BUFF_SIZE) - { - printk("%s: Sorry, max. framelength is %d bytes. The length of your frame is %d bytes.\n",dev->name,XMIT_BUFF_SIZE,skb->len); + if (skb->len > XMIT_BUFF_SIZE) { + printk(KERN_ERR "%s: Sorry, max. framelength is %d bytes. The length of your frame is %d bytes.\n", dev->name, XMIT_BUFF_SIZE, skb->len); return 0; } netif_stop_queue(dev); -#if(NUM_XMIT_BUFFS > 1) - if(test_and_set_bit(0,(void *) &p->lock)) { - printk("%s: Queue was locked\n",dev->name); - return 1; + skb_copy_from_linear_data(skb, (char *)p->xmit_cbuffs[p->xmit_count], + skb->len); + len = skb->len; + if (len < ETH_ZLEN) { + len = ETH_ZLEN; + memset((char *)p->xmit_cbuffs[p->xmit_count]+skb->len, 0, + len - skb->len); } - else -#endif - { - skb_copy_from_linear_data(skb, (char *) p->xmit_cbuffs[p->xmit_count], skb->len); - len = skb->len; - if (len < ETH_ZLEN) { - len = ETH_ZLEN; - memset((char *)p->xmit_cbuffs[p->xmit_count]+skb->len, 0, len - skb->len); - } #if (NUM_XMIT_BUFFS == 1) # ifdef NO_NOPCOMMANDS #ifdef DEBUG - if(p->scb->cus & CU_ACTIVE) - { - printk("%s: Hmmm .. CU is still running and we wanna send a new packet.\n",dev->name); - printk("%s: stat: %04x %04x\n",dev->name,p->scb->cus,p->xmit_cmds[0]->cmd_status); - } + if (p->scb->cus & CU_ACTIVE) { + printk(KERN_ERR "%s: Hmmm .. CU is still running and we wanna send a new packet.\n", dev->name); + printk(KERN_ERR "%s: stat: %04x %04x\n", + dev->name, readb(&p->scb->cus), + readw(&p->xmit_cmds[0]->cmd_status)); + } #endif - - p->xmit_buffs[0]->size = TBD_LAST | len; - for(i=0;i<16;i++) - { - p->xmit_cmds[0]->cmd_status = 0; - WAIT_4_SCB_CMD(); - if( (p->scb->cus & CU_STATUS) == CU_SUSPEND) - p->scb->cmd_cuc = CUC_RESUME; - else - { - p->scb->cbl_offset = make16(p->xmit_cmds[0]); - p->scb->cmd_cuc = CUC_START; - } - - ni_attn586(); - dev->trans_start = jiffies; - if(!i) - dev_kfree_skb(skb); - WAIT_4_SCB_CMD(); - if( (p->scb->cus & CU_ACTIVE)) /* test it, because CU sometimes doesn't start immediately */ - break; - if(p->xmit_cmds[0]->cmd_status) - break; - if(i==15) - printk("%s: Can't start transmit-command.\n",dev->name); + writew(TBD_LAST | len, &p->xmit_buffs[0]->size);; + for (i = 0; i < 16; i++) { + writew(0, &p->xmit_cmds[0]->cmd_status); + wait_for_scb_cmd(dev); + if ((readb(&p->scb->cus) & CU_STATUS) == CU_SUSPEND) + writeb(CUC_RESUME, &p->scb->cmd_cuc); + else { + writew(make16(p->xmit_cmds[0]), &p->scb->cbl_offset); + writeb(CUC_START, &p->scb->cmd_cuc); } -# else - next_nop = (p->nop_point + 1) & 0x1; - p->xmit_buffs[0]->size = TBD_LAST | len; - - p->xmit_cmds[0]->cmd_link = p->nop_cmds[next_nop]->cmd_link - = make16((p->nop_cmds[next_nop])); - p->xmit_cmds[0]->cmd_status = p->nop_cmds[next_nop]->cmd_status = 0; - - p->nop_cmds[p->nop_point]->cmd_link = make16((p->xmit_cmds[0])); + ni_attn586(); dev->trans_start = jiffies; - p->nop_point = next_nop; - dev_kfree_skb(skb); + if (!i) + dev_kfree_skb(skb); + wait_for_scb_cmd(dev); + /* test it, because CU sometimes doesn't start immediately */ + if (readb(&p->scb->cus) & CU_ACTIVE) + break; + if (readw(&p->xmit_cmds[0]->cmd_status)) + break; + if (i == 15) + printk(KERN_WARNING "%s: Can't start transmit-command.\n", dev->name); + } +# else + next_nop = (p->nop_point + 1) & 0x1; + writew(TBD_LAST | len, &p->xmit_buffs[0]->size); + writew(make16(p->nop_cmds[next_nop]), &p->xmit_cmds[0]->cmd_link); + writew(make16(p->nop_cmds[next_nop]), + &p->nop_cmds[next_nop]->cmd_link); + writew(0, &p->xmit_cmds[0]->cmd_status); + writew(0, &p->nop_cmds[next_nop]->cmd_status); + + writew(make16(p->xmit_cmds[0]), &p->nop_cmds[p->nop_point]->cmd_link); + dev->trans_start = jiffies; + p->nop_point = next_nop; + dev_kfree_skb(skb); # endif #else - p->xmit_buffs[p->xmit_count]->size = TBD_LAST | len; - if( (next_nop = p->xmit_count + 1) == NUM_XMIT_BUFFS ) - next_nop = 0; - - p->xmit_cmds[p->xmit_count]->cmd_status = 0; - /* linkpointer of xmit-command already points to next nop cmd */ - p->nop_cmds[next_nop]->cmd_link = make16((p->nop_cmds[next_nop])); - p->nop_cmds[next_nop]->cmd_status = 0; - - p->nop_cmds[p->xmit_count]->cmd_link = make16((p->xmit_cmds[p->xmit_count])); - dev->trans_start = jiffies; - p->xmit_count = next_nop; - - { - unsigned long flags; - save_flags(flags); - cli(); - if(p->xmit_count != p->xmit_last) - netif_wake_queue(dev); - p->lock = 0; - restore_flags(flags); - } - dev_kfree_skb(skb); -#endif + writew(TBD_LAST | len, &p->xmit_buffs[p->xmit_count]->size); + next_nop = p->xmit_count + 1 + if (next_nop == NUM_XMIT_BUFFS) + next_nop = 0; + writew(0, &p->xmit_cmds[p->xmit_count]->cmd_status); + /* linkpointer of xmit-command already points to next nop cmd */ + writew(make16(p->nop_cmds[next_nop]), + &p->nop_cmds[next_nop]->cmd_link); + writew(0, &p->nop_cmds[next_nop]->cmd_status); + writew(make16(p->xmit_cmds[p->xmit_count]), + &p->nop_cmds[p->xmit_count]->cmd_link); + dev->trans_start = jiffies; + p->xmit_count = next_nop; + { + unsigned long flags; + spin_lock_irqsave(&p->spinlock); + if (p->xmit_count != p->xmit_last) + netif_wake_queue(dev); + spin_unlock_irqrestore(&p->spinlock); } + dev_kfree_skb(skb); +#endif return 0; } @@ -1272,16 +1268,17 @@ static int ni52_send_packet(struct sk_buff *skb, struct net_device *dev) static struct net_device_stats *ni52_get_stats(struct net_device *dev) { struct priv *p = (struct priv *) dev->priv; - unsigned short crc,aln,rsc,ovrn; - - crc = p->scb->crc_errs; /* get error-statistic from the ni82586 */ - p->scb->crc_errs = 0; - aln = p->scb->aln_errs; - p->scb->aln_errs = 0; - rsc = p->scb->rsc_errs; - p->scb->rsc_errs = 0; - ovrn = p->scb->ovrn_errs; - p->scb->ovrn_errs = 0; + unsigned short crc, aln, rsc, ovrn; + + /* Get error-statistics from the ni82586 */ + crc = readw(&p->scb->crc_errs); + writew(0, &p->scb->crc_errs); + aln = readw(&p->scb->aln_errs); + writew(0, &p->scb->aln_errs); + rsc = readw(&p->scb->rsc_errs); + writew(0, &p->scb->rsc_errs); + ovrn = readw(&p->scb->ovrn_errs); + writew(0, &p->scb->ovrn_errs); p->stats.rx_crc_errors += crc; p->stats.rx_fifo_errors += ovrn; @@ -1320,8 +1317,9 @@ MODULE_PARM_DESC(memend, "NI5210 memory end address,required"); int __init init_module(void) { - if(io <= 0x0 || !memend || !memstart || irq < 2) { - printk("ni52: Autoprobing not allowed for modules.\nni52: Set symbols 'io' 'irq' 'memstart' and 'memend'\n"); + if (io <= 0x0 || !memend || !memstart || irq < 2) { + printk(KERN_ERR "ni52: Autoprobing not allowed for modules.\n"); + printk(KERN_ERR "ni52: Set symbols 'io' 'irq' 'memstart' and 'memend'\n"); return -ENODEV; } dev_ni52 = ni52_probe(-1); @@ -1338,42 +1336,6 @@ void __exit cleanup_module(void) } #endif /* MODULE */ -#if 0 -/* - * DUMP .. we expect a not running CMD unit and enough space - */ -void ni52_dump(struct net_device *dev,void *ptr) -{ - struct priv *p = (struct priv *) dev->priv; - struct dump_cmd_struct *dump_cmd = (struct dump_cmd_struct *) ptr; - int i; - - p->scb->cmd_cuc = CUC_ABORT; - ni_attn586(); - WAIT_4_SCB_CMD(); - WAIT_4_SCB_CMD_RUC(); - - dump_cmd->cmd_status = 0; - dump_cmd->cmd_cmd = CMD_DUMP | CMD_LAST; - dump_cmd->dump_offset = make16((dump_cmd + 1)); - dump_cmd->cmd_link = 0xffff; - - p->scb->cbl_offset = make16(dump_cmd); - p->scb->cmd_cuc = CUC_START; - ni_attn586(); - WAIT_4_STAT_COMPL(dump_cmd); - - if( (dump_cmd->cmd_status & (STAT_COMPL|STAT_OK)) != (STAT_COMPL|STAT_OK) ) - printk("%s: Can't get dump information.\n",dev->name); - - for(i=0;i<170;i++) { - printk("%02x ",(int) ((unsigned char *) (dump_cmd + 1))[i]); - if(i % 24 == 23) - printk("\n"); - } - printk("\n"); -} -#endif MODULE_LICENSE("GPL"); /* diff --git a/drivers/net/ni52.h b/drivers/net/ni52.h index a33ea0884aa..1f28a4d1a31 100644 --- a/drivers/net/ni52.h +++ b/drivers/net/ni52.h @@ -36,12 +36,12 @@ struct scp_struct { - unsigned short zero_dum0; /* has to be zero */ - unsigned char sysbus; /* 0=16Bit,1=8Bit */ - unsigned char zero_dum1; /* has to be zero for 586 */ - unsigned short zero_dum2; - unsigned short zero_dum3; - char *iscp; /* pointer to the iscp-block */ + u16 zero_dum0; /* has to be zero */ + u8 sysbus; /* 0=16Bit,1=8Bit */ + u8 zero_dum1; /* has to be zero for 586 */ + u8 zero_dum2; + u8 zero_dum3; + u32 iscp; /* pointer to the iscp-block */ }; @@ -50,10 +50,10 @@ struct scp_struct */ struct iscp_struct { - unsigned char busy; /* 586 clears after successful init */ - unsigned char zero_dummy; /* has to be zero */ - unsigned short scb_offset; /* pointeroffset to the scb_base */ - char *scb_base; /* base-address of all 16-bit offsets */ + u8 busy; /* 586 clears after successful init */ + u8 zero_dummy; /* has to be zero */ + u16 scb_offset; /* pointeroffset to the scb_base */ + u32 scb_base; /* base-address of all 16-bit offsets */ }; /* @@ -61,16 +61,16 @@ struct iscp_struct */ struct scb_struct { - unsigned char rus; - unsigned char cus; - unsigned char cmd_ruc; /* command word: RU part */ - unsigned char cmd_cuc; /* command word: CU part & ACK */ - unsigned short cbl_offset; /* pointeroffset, command block list */ - unsigned short rfa_offset; /* pointeroffset, receive frame area */ - unsigned short crc_errs; /* CRC-Error counter */ - unsigned short aln_errs; /* alignmenterror counter */ - unsigned short rsc_errs; /* Resourceerror counter */ - unsigned short ovrn_errs; /* OVerrunerror counter */ + u8 rus; + u8 cus; + u8 cmd_ruc; /* command word: RU part */ + u8 cmd_cuc; /* command word: CU part & ACK */ + u16 cbl_offset; /* pointeroffset, command block list */ + u16 rfa_offset; /* pointeroffset, receive frame area */ + u16 crc_errs; /* CRC-Error counter */ + u16 aln_errs; /* alignmenterror counter */ + u16 rsc_errs; /* Resourceerror counter */ + u16 ovrn_errs; /* OVerrunerror counter */ }; /* @@ -119,16 +119,16 @@ struct scb_struct */ struct rfd_struct { - unsigned char stat_low; /* status word */ - unsigned char stat_high; /* status word */ - unsigned char rfd_sf; /* 82596 mode only */ - unsigned char last; /* Bit15,Last Frame on List / Bit14,suspend */ - unsigned short next; /* linkoffset to next RFD */ - unsigned short rbd_offset; /* pointeroffset to RBD-buffer */ - unsigned char dest[6]; /* ethernet-address, destination */ - unsigned char source[6]; /* ethernet-address, source */ - unsigned short length; /* 802.3 frame-length */ - unsigned short zero_dummy; /* dummy */ + u8 stat_low; /* status word */ + u8 stat_high; /* status word */ + u8 rfd_sf; /* 82596 mode only */ + u8 last; /* Bit15,Last Frame on List / Bit14,suspend */ + u16 next; /* linkoffset to next RFD */ + u16 rbd_offset; /* pointeroffset to RBD-buffer */ + u8 dest[6]; /* ethernet-address, destination */ + u8 source[6]; /* ethernet-address, source */ + u16 length; /* 802.3 frame-length */ + u16 zero_dummy; /* dummy */ }; #define RFD_LAST 0x80 /* last: last rfd in the list */ @@ -153,11 +153,11 @@ struct rfd_struct */ struct rbd_struct { - unsigned short status; /* status word,number of used bytes in buff */ - unsigned short next; /* pointeroffset to next RBD */ - char *buffer; /* receive buffer address pointer */ - unsigned short size; /* size of this buffer */ - unsigned short zero_dummy; /* dummy */ + u16 status; /* status word,number of used bytes in buff */ + u16 next; /* pointeroffset to next RBD */ + u32 buffer; /* receive buffer address pointer */ + u16 size; /* size of this buffer */ + u16 zero_dummy; /* dummy */ }; #define RBD_LAST 0x8000 /* last buffer */ @@ -195,9 +195,9 @@ struct rbd_struct */ struct nop_cmd_struct { - unsigned short cmd_status; /* status of this command */ - unsigned short cmd_cmd; /* the command itself (+bits) */ - unsigned short cmd_link; /* offsetpointer to next command */ + u16 cmd_status; /* status of this command */ + u16 cmd_cmd; /* the command itself (+bits) */ + u16 cmd_link; /* offsetpointer to next command */ }; /* @@ -205,10 +205,10 @@ struct nop_cmd_struct */ struct iasetup_cmd_struct { - unsigned short cmd_status; - unsigned short cmd_cmd; - unsigned short cmd_link; - unsigned char iaddr[6]; + u16 cmd_status; + u16 cmd_cmd; + u16 cmd_link; + u8 iaddr[6]; }; /* @@ -216,21 +216,21 @@ struct iasetup_cmd_struct */ struct configure_cmd_struct { - unsigned short cmd_status; - unsigned short cmd_cmd; - unsigned short cmd_link; - unsigned char byte_cnt; /* size of the config-cmd */ - unsigned char fifo; /* fifo/recv monitor */ - unsigned char sav_bf; /* save bad frames (bit7=1)*/ - unsigned char adr_len; /* adr_len(0-2),al_loc(3),pream(4-5),loopbak(6-7)*/ - unsigned char priority; /* lin_prio(0-2),exp_prio(4-6),bof_metd(7) */ - unsigned char ifs; /* inter frame spacing */ - unsigned char time_low; /* slot time low */ - unsigned char time_high; /* slot time high(0-2) and max. retries(4-7) */ - unsigned char promisc; /* promisc-mode(0) , et al (1-7) */ - unsigned char carr_coll; /* carrier(0-3)/collision(4-7) stuff */ - unsigned char fram_len; /* minimal frame len */ - unsigned char dummy; /* dummy */ + u16 cmd_status; + u16 cmd_cmd; + u16 cmd_link; + u8 byte_cnt; /* size of the config-cmd */ + u8 fifo; /* fifo/recv monitor */ + u8 sav_bf; /* save bad frames (bit7=1)*/ + u8 adr_len; /* adr_len(0-2),al_loc(3),pream(4-5),loopbak(6-7)*/ + u8 priority; /* lin_prio(0-2),exp_prio(4-6),bof_metd(7) */ + u8 ifs; /* inter frame spacing */ + u8 time_low; /* slot time low */ + u8 time_high; /* slot time high(0-2) and max. retries(4-7) */ + u8 promisc; /* promisc-mode(0) , et al (1-7) */ + u8 carr_coll; /* carrier(0-3)/collision(4-7) stuff */ + u8 fram_len; /* minimal frame len */ + u8 dummy; /* dummy */ }; /* @@ -238,11 +238,11 @@ struct configure_cmd_struct */ struct mcsetup_cmd_struct { - unsigned short cmd_status; - unsigned short cmd_cmd; - unsigned short cmd_link; - unsigned short mc_cnt; /* number of bytes in the MC-List */ - unsigned char mc_list[0][6]; /* pointer to 6 bytes entries */ + u16 cmd_status; + u16 cmd_cmd; + u16 cmd_link; + u16 mc_cnt; /* number of bytes in the MC-List */ + u8 mc_list[0][6]; /* pointer to 6 bytes entries */ }; /* @@ -250,10 +250,10 @@ struct mcsetup_cmd_struct */ struct dump_cmd_struct { - unsigned short cmd_status; - unsigned short cmd_cmd; - unsigned short cmd_link; - unsigned short dump_offset; /* pointeroffset to DUMP space */ + u16 cmd_status; + u16 cmd_cmd; + u16 cmd_link; + u16 dump_offset; /* pointeroffset to DUMP space */ }; /* @@ -261,12 +261,12 @@ struct dump_cmd_struct */ struct transmit_cmd_struct { - unsigned short cmd_status; - unsigned short cmd_cmd; - unsigned short cmd_link; - unsigned short tbd_offset; /* pointeroffset to TBD */ - unsigned char dest[6]; /* destination address of the frame */ - unsigned short length; /* user defined: 802.3 length / Ether type */ + u16 cmd_status; + u16 cmd_cmd; + u16 cmd_link; + u16 tbd_offset; /* pointeroffset to TBD */ + u8 dest[6]; /* destination address of the frame */ + u16 length; /* user defined: 802.3 length / Ether type */ }; #define TCMD_ERRMASK 0x0fa0 @@ -281,10 +281,10 @@ struct transmit_cmd_struct struct tdr_cmd_struct { - unsigned short cmd_status; - unsigned short cmd_cmd; - unsigned short cmd_link; - unsigned short status; + u16 cmd_status; + u16 cmd_cmd; + u16 cmd_link; + u16 status; }; #define TDR_LNK_OK 0x8000 /* No link problem identified */ @@ -298,9 +298,9 @@ struct tdr_cmd_struct */ struct tbd_struct { - unsigned short size; /* size + EOF-Flag(15) */ - unsigned short next; /* pointeroffset to next TBD */ - char *buffer; /* pointer to buffer */ + u16 size; /* size + EOF-Flag(15) */ + u16 next; /* pointeroffset to next TBD */ + u32 buffer; /* pointer to buffer */ }; #define TBD_LAST 0x8000 /* EOF-Flag, indicates last buffer in list */ diff --git a/drivers/net/niu.c b/drivers/net/niu.c index 2fe14b0c5c6..e98ce1e4965 100644 --- a/drivers/net/niu.c +++ b/drivers/net/niu.c @@ -33,8 +33,8 @@ #define DRV_MODULE_NAME "niu" #define PFX DRV_MODULE_NAME ": " -#define DRV_MODULE_VERSION "0.6" -#define DRV_MODULE_RELDATE "January 5, 2008" +#define DRV_MODULE_VERSION "0.7" +#define DRV_MODULE_RELDATE "February 18, 2008" static char version[] __devinitdata = DRV_MODULE_NAME ".c:v" DRV_MODULE_VERSION " (" DRV_MODULE_RELDATE ")\n"; @@ -5147,7 +5147,12 @@ static void niu_set_rx_mode(struct net_device *dev) index++; } } else { - for (i = 0; i < niu_num_alt_addr(np); i++) { + int alt_start; + if (np->flags & NIU_FLAGS_XMAC) + alt_start = 0; + else + alt_start = 1; + for (i = alt_start; i < niu_num_alt_addr(np); i++) { err = niu_enable_alt_mac(np, i, 0); if (err) printk(KERN_WARNING PFX "%s: Error %d " diff --git a/drivers/net/pcmcia/smc91c92_cs.c b/drivers/net/pcmcia/smc91c92_cs.c index f18eca9831e..250eb1954c3 100644 --- a/drivers/net/pcmcia/smc91c92_cs.c +++ b/drivers/net/pcmcia/smc91c92_cs.c @@ -559,8 +559,16 @@ static int mhz_setup(struct pcmcia_device *link) /* Read the station address from the CIS. It is stored as the last (fourth) string in the Version 1 Version/ID tuple. */ - if (link->prod_id[3]) { - station_addr = link->prod_id[3]; + tuple->DesiredTuple = CISTPL_VERS_1; + if (first_tuple(link, tuple, parse) != CS_SUCCESS) { + rc = -1; + goto free_cfg_mem; + } + /* Ugh -- the EM1144 card has two VERS_1 tuples!?! */ + if (next_tuple(link, tuple, parse) != CS_SUCCESS) + first_tuple(link, tuple, parse); + if (parse->version_1.ns > 3) { + station_addr = parse->version_1.str + parse->version_1.ofs[3]; if (cvt_ascii_address(dev, station_addr) == 0) { rc = 0; goto free_cfg_mem; diff --git a/drivers/net/pcnet32.c b/drivers/net/pcnet32.c index c4b74e9fed2..4eb322e5273 100644 --- a/drivers/net/pcnet32.c +++ b/drivers/net/pcnet32.c @@ -174,7 +174,11 @@ static int homepna[MAX_UNITS]; #define RX_RING_SIZE (1 << (PCNET32_LOG_RX_BUFFERS)) #define RX_MAX_RING_SIZE (1 << (PCNET32_LOG_MAX_RX_BUFFERS)) -#define PKT_BUF_SZ 1544 +#define PKT_BUF_SKB 1544 +/* actual buffer length after being aligned */ +#define PKT_BUF_SIZE (PKT_BUF_SKB - NET_IP_ALIGN) +/* chip wants twos complement of the (aligned) buffer length */ +#define NEG_BUF_SIZE (NET_IP_ALIGN - PKT_BUF_SKB) /* Offsets from base I/O address. */ #define PCNET32_WIO_RDP 0x10 @@ -604,7 +608,7 @@ static void pcnet32_realloc_rx_ring(struct net_device *dev, /* now allocate any new buffers needed */ for (; new < size; new++ ) { struct sk_buff *rx_skbuff; - new_skb_list[new] = dev_alloc_skb(PKT_BUF_SZ); + new_skb_list[new] = dev_alloc_skb(PKT_BUF_SKB); if (!(rx_skbuff = new_skb_list[new])) { /* keep the original lists and buffers */ if (netif_msg_drv(lp)) @@ -613,20 +617,20 @@ static void pcnet32_realloc_rx_ring(struct net_device *dev, dev->name); goto free_all_new; } - skb_reserve(rx_skbuff, 2); + skb_reserve(rx_skbuff, NET_IP_ALIGN); new_dma_addr_list[new] = pci_map_single(lp->pci_dev, rx_skbuff->data, - PKT_BUF_SZ - 2, PCI_DMA_FROMDEVICE); + PKT_BUF_SIZE, PCI_DMA_FROMDEVICE); new_rx_ring[new].base = cpu_to_le32(new_dma_addr_list[new]); - new_rx_ring[new].buf_length = cpu_to_le16(2 - PKT_BUF_SZ); + new_rx_ring[new].buf_length = cpu_to_le16(NEG_BUF_SIZE); new_rx_ring[new].status = cpu_to_le16(0x8000); } /* and free any unneeded buffers */ for (; new < lp->rx_ring_size; new++) { if (lp->rx_skbuff[new]) { pci_unmap_single(lp->pci_dev, lp->rx_dma_addr[new], - PKT_BUF_SZ - 2, PCI_DMA_FROMDEVICE); + PKT_BUF_SIZE, PCI_DMA_FROMDEVICE); dev_kfree_skb(lp->rx_skbuff[new]); } } @@ -651,7 +655,7 @@ static void pcnet32_realloc_rx_ring(struct net_device *dev, for (; --new >= lp->rx_ring_size; ) { if (new_skb_list[new]) { pci_unmap_single(lp->pci_dev, new_dma_addr_list[new], - PKT_BUF_SZ - 2, PCI_DMA_FROMDEVICE); + PKT_BUF_SIZE, PCI_DMA_FROMDEVICE); dev_kfree_skb(new_skb_list[new]); } } @@ -678,7 +682,7 @@ static void pcnet32_purge_rx_ring(struct net_device *dev) wmb(); /* Make sure adapter sees owner change */ if (lp->rx_skbuff[i]) { pci_unmap_single(lp->pci_dev, lp->rx_dma_addr[i], - PKT_BUF_SZ - 2, PCI_DMA_FROMDEVICE); + PKT_BUF_SIZE, PCI_DMA_FROMDEVICE); dev_kfree_skb_any(lp->rx_skbuff[i]); } lp->rx_skbuff[i] = NULL; @@ -1201,7 +1205,7 @@ static void pcnet32_rx_entry(struct net_device *dev, pkt_len = (le32_to_cpu(rxp->msg_length) & 0xfff) - 4; /* Discard oversize frames. */ - if (unlikely(pkt_len > PKT_BUF_SZ - 2)) { + if (unlikely(pkt_len > PKT_BUF_SIZE)) { if (netif_msg_drv(lp)) printk(KERN_ERR "%s: Impossible packet size %d!\n", dev->name, pkt_len); @@ -1218,26 +1222,26 @@ static void pcnet32_rx_entry(struct net_device *dev, if (pkt_len > rx_copybreak) { struct sk_buff *newskb; - if ((newskb = dev_alloc_skb(PKT_BUF_SZ))) { - skb_reserve(newskb, 2); + if ((newskb = dev_alloc_skb(PKT_BUF_SKB))) { + skb_reserve(newskb, NET_IP_ALIGN); skb = lp->rx_skbuff[entry]; pci_unmap_single(lp->pci_dev, lp->rx_dma_addr[entry], - PKT_BUF_SZ - 2, + PKT_BUF_SIZE, PCI_DMA_FROMDEVICE); skb_put(skb, pkt_len); lp->rx_skbuff[entry] = newskb; lp->rx_dma_addr[entry] = pci_map_single(lp->pci_dev, newskb->data, - PKT_BUF_SZ - 2, + PKT_BUF_SIZE, PCI_DMA_FROMDEVICE); rxp->base = cpu_to_le32(lp->rx_dma_addr[entry]); rx_in_place = 1; } else skb = NULL; } else { - skb = dev_alloc_skb(pkt_len + 2); + skb = dev_alloc_skb(pkt_len + NET_IP_ALIGN); } if (skb == NULL) { @@ -1250,7 +1254,7 @@ static void pcnet32_rx_entry(struct net_device *dev, } skb->dev = dev; if (!rx_in_place) { - skb_reserve(skb, 2); /* 16 byte align */ + skb_reserve(skb, NET_IP_ALIGN); skb_put(skb, pkt_len); /* Make room */ pci_dma_sync_single_for_cpu(lp->pci_dev, lp->rx_dma_addr[entry], @@ -1291,7 +1295,7 @@ static int pcnet32_rx(struct net_device *dev, int budget) * The docs say that the buffer length isn't touched, but Andrew * Boyd of QNX reports that some revs of the 79C965 clear it. */ - rxp->buf_length = cpu_to_le16(2 - PKT_BUF_SZ); + rxp->buf_length = cpu_to_le16(NEG_BUF_SIZE); wmb(); /* Make sure owner changes after others are visible */ rxp->status = cpu_to_le16(0x8000); entry = (++lp->cur_rx) & lp->rx_mod_mask; @@ -1774,8 +1778,8 @@ pcnet32_probe1(unsigned long ioaddr, int shared, struct pci_dev *pdev) memset(dev->dev_addr, 0, sizeof(dev->dev_addr)); if (pcnet32_debug & NETIF_MSG_PROBE) { - for (i = 0; i < 6; i++) - printk(" %2.2x", dev->dev_addr[i]); + DECLARE_MAC_BUF(mac); + printk(" %s", print_mac(mac, dev->dev_addr)); /* Version 0x2623 and 0x2624 */ if (((chip_version + 1) & 0xfffe) == 0x2624) { @@ -2396,7 +2400,7 @@ static int pcnet32_init_ring(struct net_device *dev) if (rx_skbuff == NULL) { if (! (rx_skbuff = lp->rx_skbuff[i] = - dev_alloc_skb(PKT_BUF_SZ))) { + dev_alloc_skb(PKT_BUF_SKB))) { /* there is not much, we can do at this point */ if (netif_msg_drv(lp)) printk(KERN_ERR @@ -2404,16 +2408,16 @@ static int pcnet32_init_ring(struct net_device *dev) dev->name); return -1; } - skb_reserve(rx_skbuff, 2); + skb_reserve(rx_skbuff, NET_IP_ALIGN); } rmb(); if (lp->rx_dma_addr[i] == 0) lp->rx_dma_addr[i] = pci_map_single(lp->pci_dev, rx_skbuff->data, - PKT_BUF_SZ - 2, PCI_DMA_FROMDEVICE); + PKT_BUF_SIZE, PCI_DMA_FROMDEVICE); lp->rx_ring[i].base = cpu_to_le32(lp->rx_dma_addr[i]); - lp->rx_ring[i].buf_length = cpu_to_le16(2 - PKT_BUF_SZ); + lp->rx_ring[i].buf_length = cpu_to_le16(NEG_BUF_SIZE); wmb(); /* Make sure owner changes after all others are visible */ lp->rx_ring[i].status = cpu_to_le16(0x8000); } diff --git a/drivers/net/phy/fixed.c b/drivers/net/phy/fixed.c index 73b6d39ef6b..ca9b040f9ad 100644 --- a/drivers/net/phy/fixed.c +++ b/drivers/net/phy/fixed.c @@ -236,12 +236,12 @@ module_init(fixed_mdio_bus_init); static void __exit fixed_mdio_bus_exit(void) { struct fixed_mdio_bus *fmb = &platform_fmb; - struct fixed_phy *fp; + struct fixed_phy *fp, *tmp; mdiobus_unregister(&fmb->mii_bus); platform_device_unregister(pdev); - list_for_each_entry(fp, &fmb->phys, node) { + list_for_each_entry_safe(fp, tmp, &fmb->phys, node) { list_del(&fp->node); kfree(fp); } diff --git a/drivers/net/ps3_gelic_net.c b/drivers/net/ps3_gelic_net.c index 055af081e02..7eb6e7e848f 100644 --- a/drivers/net/ps3_gelic_net.c +++ b/drivers/net/ps3_gelic_net.c @@ -46,29 +46,25 @@ #include <asm/lv1call.h> #include "ps3_gelic_net.h" +#include "ps3_gelic_wireless.h" #define DRV_NAME "Gelic Network Driver" -#define DRV_VERSION "1.0" +#define DRV_VERSION "2.0" MODULE_AUTHOR("SCE Inc."); MODULE_DESCRIPTION("Gelic Network driver"); MODULE_LICENSE("GPL"); -static inline struct device *ctodev(struct gelic_net_card *card) -{ - return &card->dev->core; -} -static inline u64 bus_id(struct gelic_net_card *card) -{ - return card->dev->bus_id; -} -static inline u64 dev_id(struct gelic_net_card *card) -{ - return card->dev->dev_id; -} + +static inline void gelic_card_enable_rxdmac(struct gelic_card *card); +static inline void gelic_card_disable_rxdmac(struct gelic_card *card); +static inline void gelic_card_disable_txdmac(struct gelic_card *card); +static inline void gelic_card_reset_chain(struct gelic_card *card, + struct gelic_descr_chain *chain, + struct gelic_descr *start_descr); /* set irq_mask */ -static int gelic_net_set_irq_mask(struct gelic_net_card *card, u64 mask) +int gelic_card_set_irq_mask(struct gelic_card *card, u64 mask) { int status; @@ -76,54 +72,110 @@ static int gelic_net_set_irq_mask(struct gelic_net_card *card, u64 mask) mask, 0); if (status) dev_info(ctodev(card), - "lv1_net_set_interrupt_mask failed %d\n", status); + "%s failed %d\n", __func__, status); return status; } -static inline void gelic_net_rx_irq_on(struct gelic_net_card *card) + +static inline void gelic_card_rx_irq_on(struct gelic_card *card) { - gelic_net_set_irq_mask(card, card->ghiintmask | GELIC_NET_RXINT); + card->irq_mask |= GELIC_CARD_RXINT; + gelic_card_set_irq_mask(card, card->irq_mask); } -static inline void gelic_net_rx_irq_off(struct gelic_net_card *card) +static inline void gelic_card_rx_irq_off(struct gelic_card *card) { - gelic_net_set_irq_mask(card, card->ghiintmask & ~GELIC_NET_RXINT); + card->irq_mask &= ~GELIC_CARD_RXINT; + gelic_card_set_irq_mask(card, card->irq_mask); +} + +static void gelic_card_get_ether_port_status(struct gelic_card *card, + int inform) +{ + u64 v2; + struct net_device *ether_netdev; + + lv1_net_control(bus_id(card), dev_id(card), + GELIC_LV1_GET_ETH_PORT_STATUS, + GELIC_LV1_VLAN_TX_ETHERNET, 0, 0, + &card->ether_port_status, &v2); + + if (inform) { + ether_netdev = card->netdev[GELIC_PORT_ETHERNET]; + if (card->ether_port_status & GELIC_LV1_ETHER_LINK_UP) + netif_carrier_on(ether_netdev); + else + netif_carrier_off(ether_netdev); + } +} + +void gelic_card_up(struct gelic_card *card) +{ + pr_debug("%s: called\n", __func__); + down(&card->updown_lock); + if (atomic_inc_return(&card->users) == 1) { + pr_debug("%s: real do\n", __func__); + /* enable irq */ + gelic_card_set_irq_mask(card, card->irq_mask); + /* start rx */ + gelic_card_enable_rxdmac(card); + + napi_enable(&card->napi); + } + up(&card->updown_lock); + pr_debug("%s: done\n", __func__); } + +void gelic_card_down(struct gelic_card *card) +{ + u64 mask; + pr_debug("%s: called\n", __func__); + down(&card->updown_lock); + if (atomic_dec_if_positive(&card->users) == 0) { + pr_debug("%s: real do\n", __func__); + napi_disable(&card->napi); + /* + * Disable irq. Wireless interrupts will + * be disabled later if any + */ + mask = card->irq_mask & (GELIC_CARD_WLAN_EVENT_RECEIVED | + GELIC_CARD_WLAN_COMMAND_COMPLETED); + gelic_card_set_irq_mask(card, mask); + /* stop rx */ + gelic_card_disable_rxdmac(card); + gelic_card_reset_chain(card, &card->rx_chain, + card->descr + GELIC_NET_TX_DESCRIPTORS); + /* stop tx */ + gelic_card_disable_txdmac(card); + } + up(&card->updown_lock); + pr_debug("%s: done\n", __func__); +} + /** - * gelic_net_get_descr_status -- returns the status of a descriptor + * gelic_descr_get_status -- returns the status of a descriptor * @descr: descriptor to look at * * returns the status as in the dmac_cmd_status field of the descriptor */ -static enum gelic_net_descr_status -gelic_net_get_descr_status(struct gelic_net_descr *descr) +static enum gelic_descr_dma_status +gelic_descr_get_status(struct gelic_descr *descr) { - u32 cmd_status; - - cmd_status = descr->dmac_cmd_status; - cmd_status >>= GELIC_NET_DESCR_IND_PROC_SHIFT; - return cmd_status; + return be32_to_cpu(descr->dmac_cmd_status) & GELIC_DESCR_DMA_STAT_MASK; } /** - * gelic_net_set_descr_status -- sets the status of a descriptor + * gelic_descr_set_status -- sets the status of a descriptor * @descr: descriptor to change * @status: status to set in the descriptor * * changes the status to the specified value. Doesn't change other bits * in the status */ -static void gelic_net_set_descr_status(struct gelic_net_descr *descr, - enum gelic_net_descr_status status) +static void gelic_descr_set_status(struct gelic_descr *descr, + enum gelic_descr_dma_status status) { - u32 cmd_status; - - /* read the status */ - cmd_status = descr->dmac_cmd_status; - /* clean the upper 4 bits */ - cmd_status &= GELIC_NET_DESCR_IND_PROC_MASKO; - /* add the status to it */ - cmd_status |= ((u32)status) << GELIC_NET_DESCR_IND_PROC_SHIFT; - /* and write it back */ - descr->dmac_cmd_status = cmd_status; + descr->dmac_cmd_status = cpu_to_be32(status | + (be32_to_cpu(descr->dmac_cmd_status) & + ~GELIC_DESCR_DMA_STAT_MASK)); /* * dma_cmd_status field is used to indicate whether the descriptor * is valid or not. @@ -134,24 +186,24 @@ static void gelic_net_set_descr_status(struct gelic_net_descr *descr, } /** - * gelic_net_free_chain - free descriptor chain + * gelic_card_free_chain - free descriptor chain * @card: card structure * @descr_in: address of desc */ -static void gelic_net_free_chain(struct gelic_net_card *card, - struct gelic_net_descr *descr_in) +static void gelic_card_free_chain(struct gelic_card *card, + struct gelic_descr *descr_in) { - struct gelic_net_descr *descr; + struct gelic_descr *descr; for (descr = descr_in; descr && descr->bus_addr; descr = descr->next) { dma_unmap_single(ctodev(card), descr->bus_addr, - GELIC_NET_DESCR_SIZE, DMA_BIDIRECTIONAL); + GELIC_DESCR_SIZE, DMA_BIDIRECTIONAL); descr->bus_addr = 0; } } /** - * gelic_net_init_chain - links descriptor chain + * gelic_card_init_chain - links descriptor chain * @card: card structure * @chain: address of chain * @start_descr: address of descriptor array @@ -162,22 +214,22 @@ static void gelic_net_free_chain(struct gelic_net_card *card, * * returns 0 on success, <0 on failure */ -static int gelic_net_init_chain(struct gelic_net_card *card, - struct gelic_net_descr_chain *chain, - struct gelic_net_descr *start_descr, int no) +static int gelic_card_init_chain(struct gelic_card *card, + struct gelic_descr_chain *chain, + struct gelic_descr *start_descr, int no) { int i; - struct gelic_net_descr *descr; + struct gelic_descr *descr; descr = start_descr; memset(descr, 0, sizeof(*descr) * no); /* set up the hardware pointers in each descriptor */ for (i = 0; i < no; i++, descr++) { - gelic_net_set_descr_status(descr, GELIC_NET_DESCR_NOT_IN_USE); + gelic_descr_set_status(descr, GELIC_DESCR_DMA_NOT_IN_USE); descr->bus_addr = dma_map_single(ctodev(card), descr, - GELIC_NET_DESCR_SIZE, + GELIC_DESCR_SIZE, DMA_BIDIRECTIONAL); if (!descr->bus_addr) @@ -193,7 +245,7 @@ static int gelic_net_init_chain(struct gelic_net_card *card, /* chain bus addr of hw descriptor */ descr = start_descr; for (i = 0; i < no; i++, descr++) { - descr->next_descr_addr = descr->next->bus_addr; + descr->next_descr_addr = cpu_to_be32(descr->next->bus_addr); } chain->head = start_descr; @@ -208,13 +260,38 @@ iommu_error: for (i--, descr--; 0 <= i; i--, descr--) if (descr->bus_addr) dma_unmap_single(ctodev(card), descr->bus_addr, - GELIC_NET_DESCR_SIZE, + GELIC_DESCR_SIZE, DMA_BIDIRECTIONAL); return -ENOMEM; } /** - * gelic_net_prepare_rx_descr - reinitializes a rx descriptor + * gelic_card_reset_chain - reset status of a descriptor chain + * @card: card structure + * @chain: address of chain + * @start_descr: address of descriptor array + * + * Reset the status of dma descriptors to ready state + * and re-initialize the hardware chain for later use + */ +static void gelic_card_reset_chain(struct gelic_card *card, + struct gelic_descr_chain *chain, + struct gelic_descr *start_descr) +{ + struct gelic_descr *descr; + + for (descr = start_descr; start_descr != descr->next; descr++) { + gelic_descr_set_status(descr, GELIC_DESCR_DMA_CARDOWNED); + descr->next_descr_addr = cpu_to_be32(descr->next->bus_addr); + } + + chain->head = start_descr; + chain->tail = (descr - 1); + + (descr - 1)->next_descr_addr = 0; +} +/** + * gelic_descr_prepare_rx - reinitializes a rx descriptor * @card: card structure * @descr: descriptor to re-init * @@ -223,29 +300,27 @@ iommu_error: * allocates a new rx skb, iommu-maps it and attaches it to the descriptor. * Activate the descriptor state-wise */ -static int gelic_net_prepare_rx_descr(struct gelic_net_card *card, - struct gelic_net_descr *descr) +static int gelic_descr_prepare_rx(struct gelic_card *card, + struct gelic_descr *descr) { int offset; unsigned int bufsize; - if (gelic_net_get_descr_status(descr) != GELIC_NET_DESCR_NOT_IN_USE) { + if (gelic_descr_get_status(descr) != GELIC_DESCR_DMA_NOT_IN_USE) dev_info(ctodev(card), "%s: ERROR status \n", __func__); - } /* we need to round up the buffer size to a multiple of 128 */ bufsize = ALIGN(GELIC_NET_MAX_MTU, GELIC_NET_RXBUF_ALIGN); /* and we need to have it 128 byte aligned, therefore we allocate a * bit more */ - descr->skb = netdev_alloc_skb(card->netdev, - bufsize + GELIC_NET_RXBUF_ALIGN - 1); + descr->skb = dev_alloc_skb(bufsize + GELIC_NET_RXBUF_ALIGN - 1); if (!descr->skb) { descr->buf_addr = 0; /* tell DMAC don't touch memory */ dev_info(ctodev(card), "%s:allocate skb failed !!\n", __func__); return -ENOMEM; } - descr->buf_size = bufsize; + descr->buf_size = cpu_to_be32(bufsize); descr->dmac_cmd_status = 0; descr->result_size = 0; descr->valid_size = 0; @@ -256,63 +331,64 @@ static int gelic_net_prepare_rx_descr(struct gelic_net_card *card, if (offset) skb_reserve(descr->skb, GELIC_NET_RXBUF_ALIGN - offset); /* io-mmu-map the skb */ - descr->buf_addr = dma_map_single(ctodev(card), descr->skb->data, - GELIC_NET_MAX_MTU, - DMA_FROM_DEVICE); + descr->buf_addr = cpu_to_be32(dma_map_single(ctodev(card), + descr->skb->data, + GELIC_NET_MAX_MTU, + DMA_FROM_DEVICE)); if (!descr->buf_addr) { dev_kfree_skb_any(descr->skb); descr->skb = NULL; dev_info(ctodev(card), "%s:Could not iommu-map rx buffer\n", __func__); - gelic_net_set_descr_status(descr, GELIC_NET_DESCR_NOT_IN_USE); + gelic_descr_set_status(descr, GELIC_DESCR_DMA_NOT_IN_USE); return -ENOMEM; } else { - gelic_net_set_descr_status(descr, GELIC_NET_DESCR_CARDOWNED); + gelic_descr_set_status(descr, GELIC_DESCR_DMA_CARDOWNED); return 0; } } /** - * gelic_net_release_rx_chain - free all skb of rx descr + * gelic_card_release_rx_chain - free all skb of rx descr * @card: card structure * */ -static void gelic_net_release_rx_chain(struct gelic_net_card *card) +static void gelic_card_release_rx_chain(struct gelic_card *card) { - struct gelic_net_descr *descr = card->rx_chain.head; + struct gelic_descr *descr = card->rx_chain.head; do { if (descr->skb) { dma_unmap_single(ctodev(card), - descr->buf_addr, + be32_to_cpu(descr->buf_addr), descr->skb->len, DMA_FROM_DEVICE); descr->buf_addr = 0; dev_kfree_skb_any(descr->skb); descr->skb = NULL; - gelic_net_set_descr_status(descr, - GELIC_NET_DESCR_NOT_IN_USE); + gelic_descr_set_status(descr, + GELIC_DESCR_DMA_NOT_IN_USE); } descr = descr->next; } while (descr != card->rx_chain.head); } /** - * gelic_net_fill_rx_chain - fills descriptors/skbs in the rx chains + * gelic_card_fill_rx_chain - fills descriptors/skbs in the rx chains * @card: card structure * * fills all descriptors in the rx chain: allocates skbs * and iommu-maps them. - * returns 0 on success, <0 on failure + * returns 0 on success, < 0 on failure */ -static int gelic_net_fill_rx_chain(struct gelic_net_card *card) +static int gelic_card_fill_rx_chain(struct gelic_card *card) { - struct gelic_net_descr *descr = card->rx_chain.head; + struct gelic_descr *descr = card->rx_chain.head; int ret; do { if (!descr->skb) { - ret = gelic_net_prepare_rx_descr(card, descr); + ret = gelic_descr_prepare_rx(card, descr); if (ret) goto rewind; } @@ -321,41 +397,41 @@ static int gelic_net_fill_rx_chain(struct gelic_net_card *card) return 0; rewind: - gelic_net_release_rx_chain(card); + gelic_card_release_rx_chain(card); return ret; } /** - * gelic_net_alloc_rx_skbs - allocates rx skbs in rx descriptor chains + * gelic_card_alloc_rx_skbs - allocates rx skbs in rx descriptor chains * @card: card structure * - * returns 0 on success, <0 on failure + * returns 0 on success, < 0 on failure */ -static int gelic_net_alloc_rx_skbs(struct gelic_net_card *card) +static int gelic_card_alloc_rx_skbs(struct gelic_card *card) { - struct gelic_net_descr_chain *chain; + struct gelic_descr_chain *chain; int ret; chain = &card->rx_chain; - ret = gelic_net_fill_rx_chain(card); - chain->head = card->rx_top->prev; /* point to the last */ + ret = gelic_card_fill_rx_chain(card); + chain->tail = card->rx_top->prev; /* point to the last */ return ret; } /** - * gelic_net_release_tx_descr - processes a used tx descriptor + * gelic_descr_release_tx - processes a used tx descriptor * @card: card structure * @descr: descriptor to release * * releases a used tx descriptor (unmapping, freeing of skb) */ -static void gelic_net_release_tx_descr(struct gelic_net_card *card, - struct gelic_net_descr *descr) +static void gelic_descr_release_tx(struct gelic_card *card, + struct gelic_descr *descr) { struct sk_buff *skb = descr->skb; - BUG_ON(!(descr->data_status & (1 << GELIC_NET_TXDESC_TAIL))); + BUG_ON(!(be32_to_cpu(descr->data_status) & GELIC_DESCR_TX_TAIL)); - dma_unmap_single(ctodev(card), descr->buf_addr, skb->len, + dma_unmap_single(ctodev(card), be32_to_cpu(descr->buf_addr), skb->len, DMA_TO_DEVICE); dev_kfree_skb_any(skb); @@ -369,59 +445,75 @@ static void gelic_net_release_tx_descr(struct gelic_net_card *card, descr->skb = NULL; /* set descr status */ - gelic_net_set_descr_status(descr, GELIC_NET_DESCR_NOT_IN_USE); + gelic_descr_set_status(descr, GELIC_DESCR_DMA_NOT_IN_USE); +} + +static void gelic_card_stop_queues(struct gelic_card *card) +{ + netif_stop_queue(card->netdev[GELIC_PORT_ETHERNET]); + + if (card->netdev[GELIC_PORT_WIRELESS]) + netif_stop_queue(card->netdev[GELIC_PORT_WIRELESS]); } +static void gelic_card_wake_queues(struct gelic_card *card) +{ + netif_wake_queue(card->netdev[GELIC_PORT_ETHERNET]); + if (card->netdev[GELIC_PORT_WIRELESS]) + netif_wake_queue(card->netdev[GELIC_PORT_WIRELESS]); +} /** - * gelic_net_release_tx_chain - processes sent tx descriptors + * gelic_card_release_tx_chain - processes sent tx descriptors * @card: adapter structure * @stop: net_stop sequence * * releases the tx descriptors that gelic has finished with */ -static void gelic_net_release_tx_chain(struct gelic_net_card *card, int stop) +static void gelic_card_release_tx_chain(struct gelic_card *card, int stop) { - struct gelic_net_descr_chain *tx_chain; - enum gelic_net_descr_status status; + struct gelic_descr_chain *tx_chain; + enum gelic_descr_dma_status status; + struct net_device *netdev; int release = 0; for (tx_chain = &card->tx_chain; tx_chain->head != tx_chain->tail && tx_chain->tail; tx_chain->tail = tx_chain->tail->next) { - status = gelic_net_get_descr_status(tx_chain->tail); + status = gelic_descr_get_status(tx_chain->tail); + netdev = tx_chain->tail->skb->dev; switch (status) { - case GELIC_NET_DESCR_RESPONSE_ERROR: - case GELIC_NET_DESCR_PROTECTION_ERROR: - case GELIC_NET_DESCR_FORCE_END: + case GELIC_DESCR_DMA_RESPONSE_ERROR: + case GELIC_DESCR_DMA_PROTECTION_ERROR: + case GELIC_DESCR_DMA_FORCE_END: if (printk_ratelimit()) dev_info(ctodev(card), "%s: forcing end of tx descriptor " \ "with status %x\n", __func__, status); - card->netdev->stats.tx_dropped++; + netdev->stats.tx_dropped++; break; - case GELIC_NET_DESCR_COMPLETE: + case GELIC_DESCR_DMA_COMPLETE: if (tx_chain->tail->skb) { - card->netdev->stats.tx_packets++; - card->netdev->stats.tx_bytes += + netdev->stats.tx_packets++; + netdev->stats.tx_bytes += tx_chain->tail->skb->len; } break; - case GELIC_NET_DESCR_CARDOWNED: + case GELIC_DESCR_DMA_CARDOWNED: /* pending tx request */ default: - /* any other value (== GELIC_NET_DESCR_NOT_IN_USE) */ + /* any other value (== GELIC_DESCR_DMA_NOT_IN_USE) */ if (!stop) goto out; } - gelic_net_release_tx_descr(card, tx_chain->tail); + gelic_descr_release_tx(card, tx_chain->tail); release ++; } out: if (!stop && release) - netif_wake_queue(card->netdev); + gelic_card_wake_queues(card); } /** @@ -432,9 +524,9 @@ out: * netdev interface. It also sets up multicast, allmulti and promisc * flags appropriately */ -static void gelic_net_set_multi(struct net_device *netdev) +void gelic_net_set_multi(struct net_device *netdev) { - struct gelic_net_card *card = netdev_priv(netdev); + struct gelic_card *card = netdev_card(netdev); struct dev_mc_list *mc; unsigned int i; uint8_t *p; @@ -456,8 +548,8 @@ static void gelic_net_set_multi(struct net_device *netdev) "lv1_net_add_multicast_address failed, %d\n", status); - if (netdev->flags & IFF_ALLMULTI - || netdev->mc_count > GELIC_NET_MC_COUNT_MAX) { /* list max */ + if ((netdev->flags & IFF_ALLMULTI) || + (netdev->mc_count > GELIC_NET_MC_COUNT_MAX)) { status = lv1_net_add_multicast_address(bus_id(card), dev_id(card), 0, 1); @@ -468,7 +560,7 @@ static void gelic_net_set_multi(struct net_device *netdev) return; } - /* set multicast address */ + /* set multicast addresses */ for (mc = netdev->mc_list; mc; mc = mc->next) { addr = 0; p = mc->dmi_addr; @@ -487,31 +579,42 @@ static void gelic_net_set_multi(struct net_device *netdev) } /** - * gelic_net_enable_rxdmac - enables the receive DMA controller + * gelic_card_enable_rxdmac - enables the receive DMA controller * @card: card structure * - * gelic_net_enable_rxdmac enables the DMA controller by setting RX_DMA_EN + * gelic_card_enable_rxdmac enables the DMA controller by setting RX_DMA_EN * in the GDADMACCNTR register */ -static inline void gelic_net_enable_rxdmac(struct gelic_net_card *card) +static inline void gelic_card_enable_rxdmac(struct gelic_card *card) { int status; +#ifdef DEBUG + if (gelic_descr_get_status(card->rx_chain.head) != + GELIC_DESCR_DMA_CARDOWNED) { + printk(KERN_ERR "%s: status=%x\n", __func__, + be32_to_cpu(card->rx_chain.head->dmac_cmd_status)); + printk(KERN_ERR "%s: nextphy=%x\n", __func__, + be32_to_cpu(card->rx_chain.head->next_descr_addr)); + printk(KERN_ERR "%s: head=%p\n", __func__, + card->rx_chain.head); + } +#endif status = lv1_net_start_rx_dma(bus_id(card), dev_id(card), - card->rx_chain.tail->bus_addr, 0); + card->rx_chain.head->bus_addr, 0); if (status) dev_info(ctodev(card), "lv1_net_start_rx_dma failed, status=%d\n", status); } /** - * gelic_net_disable_rxdmac - disables the receive DMA controller + * gelic_card_disable_rxdmac - disables the receive DMA controller * @card: card structure * - * gelic_net_disable_rxdmac terminates processing on the DMA controller by + * gelic_card_disable_rxdmac terminates processing on the DMA controller by * turing off DMA and issueing a force end */ -static inline void gelic_net_disable_rxdmac(struct gelic_net_card *card) +static inline void gelic_card_disable_rxdmac(struct gelic_card *card) { int status; @@ -523,13 +626,13 @@ static inline void gelic_net_disable_rxdmac(struct gelic_net_card *card) } /** - * gelic_net_disable_txdmac - disables the transmit DMA controller + * gelic_card_disable_txdmac - disables the transmit DMA controller * @card: card structure * - * gelic_net_disable_txdmac terminates processing on the DMA controller by + * gelic_card_disable_txdmac terminates processing on the DMA controller by * turing off DMA and issueing a force end */ -static inline void gelic_net_disable_txdmac(struct gelic_net_card *card) +static inline void gelic_card_disable_txdmac(struct gelic_card *card) { int status; @@ -546,51 +649,37 @@ static inline void gelic_net_disable_txdmac(struct gelic_net_card *card) * * always returns 0 */ -static int gelic_net_stop(struct net_device *netdev) +int gelic_net_stop(struct net_device *netdev) { - struct gelic_net_card *card = netdev_priv(netdev); - - napi_disable(&card->napi); - netif_stop_queue(netdev); + struct gelic_card *card; - /* turn off DMA, force end */ - gelic_net_disable_rxdmac(card); - gelic_net_disable_txdmac(card); - - gelic_net_set_irq_mask(card, 0); - - /* disconnect event port */ - free_irq(card->netdev->irq, card->netdev); - ps3_sb_event_receive_port_destroy(card->dev, card->netdev->irq); - card->netdev->irq = NO_IRQ; + pr_debug("%s: start\n", __func__); + netif_stop_queue(netdev); netif_carrier_off(netdev); - /* release chains */ - gelic_net_release_tx_chain(card, 1); - gelic_net_release_rx_chain(card); - - gelic_net_free_chain(card, card->tx_top); - gelic_net_free_chain(card, card->rx_top); + card = netdev_card(netdev); + gelic_card_down(card); + pr_debug("%s: done\n", __func__); return 0; } /** - * gelic_net_get_next_tx_descr - returns the next available tx descriptor + * gelic_card_get_next_tx_descr - returns the next available tx descriptor * @card: device structure to get descriptor from * * returns the address of the next descriptor, or NULL if not available. */ -static struct gelic_net_descr * -gelic_net_get_next_tx_descr(struct gelic_net_card *card) +static struct gelic_descr * +gelic_card_get_next_tx_descr(struct gelic_card *card) { if (!card->tx_chain.head) return NULL; /* see if the next descriptor is free */ if (card->tx_chain.tail != card->tx_chain.head->next && - gelic_net_get_descr_status(card->tx_chain.head) == - GELIC_NET_DESCR_NOT_IN_USE) + gelic_descr_get_status(card->tx_chain.head) == + GELIC_DESCR_DMA_NOT_IN_USE) return card->tx_chain.head; else return NULL; @@ -606,32 +695,33 @@ gelic_net_get_next_tx_descr(struct gelic_net_card *card) * depending on hardware checksum settings. This function assumes a wmb() * has executed before. */ -static void gelic_net_set_txdescr_cmdstat(struct gelic_net_descr *descr, - struct sk_buff *skb) +static void gelic_descr_set_tx_cmdstat(struct gelic_descr *descr, + struct sk_buff *skb) { if (skb->ip_summed != CHECKSUM_PARTIAL) - descr->dmac_cmd_status = GELIC_NET_DMAC_CMDSTAT_NOCS | - GELIC_NET_DMAC_CMDSTAT_END_FRAME; + descr->dmac_cmd_status = + cpu_to_be32(GELIC_DESCR_DMA_CMD_NO_CHKSUM | + GELIC_DESCR_TX_DMA_FRAME_TAIL); else { /* is packet ip? * if yes: tcp? udp? */ if (skb->protocol == htons(ETH_P_IP)) { if (ip_hdr(skb)->protocol == IPPROTO_TCP) descr->dmac_cmd_status = - GELIC_NET_DMAC_CMDSTAT_TCPCS | - GELIC_NET_DMAC_CMDSTAT_END_FRAME; + cpu_to_be32(GELIC_DESCR_DMA_CMD_TCP_CHKSUM | + GELIC_DESCR_TX_DMA_FRAME_TAIL); else if (ip_hdr(skb)->protocol == IPPROTO_UDP) descr->dmac_cmd_status = - GELIC_NET_DMAC_CMDSTAT_UDPCS | - GELIC_NET_DMAC_CMDSTAT_END_FRAME; + cpu_to_be32(GELIC_DESCR_DMA_CMD_UDP_CHKSUM | + GELIC_DESCR_TX_DMA_FRAME_TAIL); else /* * the stack should checksum non-tcp and non-udp * packets on his own: NETIF_F_IP_CSUM */ descr->dmac_cmd_status = - GELIC_NET_DMAC_CMDSTAT_NOCS | - GELIC_NET_DMAC_CMDSTAT_END_FRAME; + cpu_to_be32(GELIC_DESCR_DMA_CMD_NO_CHKSUM | + GELIC_DESCR_TX_DMA_FRAME_TAIL); } } } @@ -662,7 +752,7 @@ static inline struct sk_buff *gelic_put_vlan_tag(struct sk_buff *skb, } /** - * gelic_net_prepare_tx_descr_v - get dma address of skb_data + * gelic_descr_prepare_tx - setup a descriptor for sending packets * @card: card structure * @descr: descriptor structure * @skb: packet to use @@ -670,16 +760,19 @@ static inline struct sk_buff *gelic_put_vlan_tag(struct sk_buff *skb, * returns 0 on success, <0 on failure. * */ -static int gelic_net_prepare_tx_descr_v(struct gelic_net_card *card, - struct gelic_net_descr *descr, - struct sk_buff *skb) +static int gelic_descr_prepare_tx(struct gelic_card *card, + struct gelic_descr *descr, + struct sk_buff *skb) { dma_addr_t buf; - if (card->vlan_index != -1) { + if (card->vlan_required) { struct sk_buff *skb_tmp; + enum gelic_port_type type; + + type = netdev_port(skb->dev)->type; skb_tmp = gelic_put_vlan_tag(skb, - card->vlan_id[card->vlan_index]); + card->vlan[type].tx); if (!skb_tmp) return -ENOMEM; skb = skb_tmp; @@ -694,12 +787,12 @@ static int gelic_net_prepare_tx_descr_v(struct gelic_net_card *card, return -ENOMEM; } - descr->buf_addr = buf; - descr->buf_size = skb->len; + descr->buf_addr = cpu_to_be32(buf); + descr->buf_size = cpu_to_be32(skb->len); descr->skb = skb; descr->data_status = 0; descr->next_descr_addr = 0; /* terminate hw descr */ - gelic_net_set_txdescr_cmdstat(descr, skb); + gelic_descr_set_tx_cmdstat(descr, skb); /* bump free descriptor pointer */ card->tx_chain.head = descr->next; @@ -707,20 +800,20 @@ static int gelic_net_prepare_tx_descr_v(struct gelic_net_card *card, } /** - * gelic_net_kick_txdma - enables TX DMA processing + * gelic_card_kick_txdma - enables TX DMA processing * @card: card structure * @descr: descriptor address to enable TX processing at * */ -static int gelic_net_kick_txdma(struct gelic_net_card *card, - struct gelic_net_descr *descr) +static int gelic_card_kick_txdma(struct gelic_card *card, + struct gelic_descr *descr) { int status = 0; if (card->tx_dma_progress) return 0; - if (gelic_net_get_descr_status(descr) == GELIC_NET_DESCR_CARDOWNED) { + if (gelic_descr_get_status(descr) == GELIC_DESCR_DMA_CARDOWNED) { card->tx_dma_progress = 1; status = lv1_net_start_tx_dma(bus_id(card), dev_id(card), descr->bus_addr, 0); @@ -738,56 +831,56 @@ static int gelic_net_kick_txdma(struct gelic_net_card *card, * * returns 0 on success, <0 on failure */ -static int gelic_net_xmit(struct sk_buff *skb, struct net_device *netdev) +int gelic_net_xmit(struct sk_buff *skb, struct net_device *netdev) { - struct gelic_net_card *card = netdev_priv(netdev); - struct gelic_net_descr *descr; + struct gelic_card *card = netdev_card(netdev); + struct gelic_descr *descr; int result; unsigned long flags; - spin_lock_irqsave(&card->tx_dma_lock, flags); + spin_lock_irqsave(&card->tx_lock, flags); - gelic_net_release_tx_chain(card, 0); + gelic_card_release_tx_chain(card, 0); - descr = gelic_net_get_next_tx_descr(card); + descr = gelic_card_get_next_tx_descr(card); if (!descr) { /* * no more descriptors free */ - netif_stop_queue(netdev); - spin_unlock_irqrestore(&card->tx_dma_lock, flags); + gelic_card_stop_queues(card); + spin_unlock_irqrestore(&card->tx_lock, flags); return NETDEV_TX_BUSY; } - result = gelic_net_prepare_tx_descr_v(card, descr, skb); + result = gelic_descr_prepare_tx(card, descr, skb); if (result) { /* * DMA map failed. As chanses are that failure * would continue, just release skb and return */ - card->netdev->stats.tx_dropped++; + netdev->stats.tx_dropped++; dev_kfree_skb_any(skb); - spin_unlock_irqrestore(&card->tx_dma_lock, flags); + spin_unlock_irqrestore(&card->tx_lock, flags); return NETDEV_TX_OK; } /* * link this prepared descriptor to previous one * to achieve high performance */ - descr->prev->next_descr_addr = descr->bus_addr; + descr->prev->next_descr_addr = cpu_to_be32(descr->bus_addr); /* * as hardware descriptor is modified in the above lines, * ensure that the hardware sees it */ wmb(); - if (gelic_net_kick_txdma(card, descr)) { + if (gelic_card_kick_txdma(card, descr)) { /* * kick failed. * release descriptors which were just prepared */ - card->netdev->stats.tx_dropped++; - gelic_net_release_tx_descr(card, descr); - gelic_net_release_tx_descr(card, descr->next); + netdev->stats.tx_dropped++; + gelic_descr_release_tx(card, descr); + gelic_descr_release_tx(card, descr->next); card->tx_chain.tail = descr->next->next; dev_info(ctodev(card), "%s: kick failure\n", __func__); } else { @@ -795,7 +888,7 @@ static int gelic_net_xmit(struct sk_buff *skb, struct net_device *netdev) netdev->trans_start = jiffies; } - spin_unlock_irqrestore(&card->tx_dma_lock, flags); + spin_unlock_irqrestore(&card->tx_lock, flags); return NETDEV_TX_OK; } @@ -803,30 +896,34 @@ static int gelic_net_xmit(struct sk_buff *skb, struct net_device *netdev) * gelic_net_pass_skb_up - takes an skb from a descriptor and passes it on * @descr: descriptor to process * @card: card structure + * @netdev: net_device structure to be passed packet * * iommu-unmaps the skb, fills out skb structure and passes the data to the * stack. The descriptor state is not changed. */ -static void gelic_net_pass_skb_up(struct gelic_net_descr *descr, - struct gelic_net_card *card) +static void gelic_net_pass_skb_up(struct gelic_descr *descr, + struct gelic_card *card, + struct net_device *netdev) + { - struct sk_buff *skb; - struct net_device *netdev; + struct sk_buff *skb = descr->skb; u32 data_status, data_error; - data_status = descr->data_status; - data_error = descr->data_error; - netdev = card->netdev; + data_status = be32_to_cpu(descr->data_status); + data_error = be32_to_cpu(descr->data_error); /* unmap skb buffer */ - skb = descr->skb; - dma_unmap_single(ctodev(card), descr->buf_addr, GELIC_NET_MAX_MTU, + dma_unmap_single(ctodev(card), be32_to_cpu(descr->buf_addr), + GELIC_NET_MAX_MTU, DMA_FROM_DEVICE); - skb_put(skb, descr->valid_size? descr->valid_size : descr->result_size); + skb_put(skb, be32_to_cpu(descr->valid_size)? + be32_to_cpu(descr->valid_size) : + be32_to_cpu(descr->result_size)); if (!descr->valid_size) dev_info(ctodev(card), "buffer full %x %x %x\n", - descr->result_size, descr->buf_size, - descr->dmac_cmd_status); + be32_to_cpu(descr->result_size), + be32_to_cpu(descr->buf_size), + be32_to_cpu(descr->dmac_cmd_status)); descr->skb = NULL; /* @@ -838,8 +935,8 @@ static void gelic_net_pass_skb_up(struct gelic_net_descr *descr, /* checksum offload */ if (card->rx_csum) { - if ((data_status & GELIC_NET_DATA_STATUS_CHK_MASK) && - (!(data_error & GELIC_NET_DATA_ERROR_CHK_MASK))) + if ((data_status & GELIC_DESCR_DATA_STATUS_CHK_MASK) && + (!(data_error & GELIC_DESCR_DATA_ERROR_CHK_MASK))) skb->ip_summed = CHECKSUM_UNNECESSARY; else skb->ip_summed = CHECKSUM_NONE; @@ -847,15 +944,15 @@ static void gelic_net_pass_skb_up(struct gelic_net_descr *descr, skb->ip_summed = CHECKSUM_NONE; /* update netdevice statistics */ - card->netdev->stats.rx_packets++; - card->netdev->stats.rx_bytes += skb->len; + netdev->stats.rx_packets++; + netdev->stats.rx_bytes += skb->len; /* pass skb up to stack */ netif_receive_skb(skb); } /** - * gelic_net_decode_one_descr - processes an rx descriptor + * gelic_card_decode_one_descr - processes an rx descriptor * @card: card structure * * returns 1 if a packet has been sent to the stack, otherwise 0 @@ -863,36 +960,56 @@ static void gelic_net_pass_skb_up(struct gelic_net_descr *descr, * processes an rx descriptor by iommu-unmapping the data buffer and passing * the packet up to the stack */ -static int gelic_net_decode_one_descr(struct gelic_net_card *card) +static int gelic_card_decode_one_descr(struct gelic_card *card) { - enum gelic_net_descr_status status; - struct gelic_net_descr_chain *chain = &card->rx_chain; - struct gelic_net_descr *descr = chain->tail; + enum gelic_descr_dma_status status; + struct gelic_descr_chain *chain = &card->rx_chain; + struct gelic_descr *descr = chain->head; + struct net_device *netdev = NULL; int dmac_chain_ended; - status = gelic_net_get_descr_status(descr); + status = gelic_descr_get_status(descr); /* is this descriptor terminated with next_descr == NULL? */ dmac_chain_ended = - descr->dmac_cmd_status & GELIC_NET_DMAC_CMDSTAT_RXDCEIS; + be32_to_cpu(descr->dmac_cmd_status) & + GELIC_DESCR_RX_DMA_CHAIN_END; - if (status == GELIC_NET_DESCR_CARDOWNED) + if (status == GELIC_DESCR_DMA_CARDOWNED) return 0; - if (status == GELIC_NET_DESCR_NOT_IN_USE) { + if (status == GELIC_DESCR_DMA_NOT_IN_USE) { dev_dbg(ctodev(card), "dormant descr? %p\n", descr); return 0; } - if ((status == GELIC_NET_DESCR_RESPONSE_ERROR) || - (status == GELIC_NET_DESCR_PROTECTION_ERROR) || - (status == GELIC_NET_DESCR_FORCE_END)) { + /* netdevice select */ + if (card->vlan_required) { + unsigned int i; + u16 vid; + vid = *(u16 *)(descr->skb->data) & VLAN_VID_MASK; + for (i = 0; i < GELIC_PORT_MAX; i++) { + if (card->vlan[i].rx == vid) { + netdev = card->netdev[i]; + break; + } + }; + if (GELIC_PORT_MAX <= i) { + pr_info("%s: unknown packet vid=%x\n", __func__, vid); + goto refill; + } + } else + netdev = card->netdev[GELIC_PORT_ETHERNET]; + + if ((status == GELIC_DESCR_DMA_RESPONSE_ERROR) || + (status == GELIC_DESCR_DMA_PROTECTION_ERROR) || + (status == GELIC_DESCR_DMA_FORCE_END)) { dev_info(ctodev(card), "dropping RX descriptor with state %x\n", status); - card->netdev->stats.rx_dropped++; + netdev->stats.rx_dropped++; goto refill; } - if (status == GELIC_NET_DESCR_BUFFER_FULL) { + if (status == GELIC_DESCR_DMA_BUFFER_FULL) { /* * Buffer full would occur if and only if * the frame length was longer than the size of this @@ -909,14 +1026,14 @@ static int gelic_net_decode_one_descr(struct gelic_net_card *card) * descriptoers any other than FRAME_END here should * be treated as error. */ - if (status != GELIC_NET_DESCR_FRAME_END) { + if (status != GELIC_DESCR_DMA_FRAME_END) { dev_dbg(ctodev(card), "RX descriptor with state %x\n", status); goto refill; } /* ok, we've got a packet in descr */ - gelic_net_pass_skb_up(descr, card); + gelic_net_pass_skb_up(descr, card, netdev); refill: /* * So that always DMAC can see the end @@ -926,21 +1043,21 @@ refill: descr->next_descr_addr = 0; /* change the descriptor state: */ - gelic_net_set_descr_status(descr, GELIC_NET_DESCR_NOT_IN_USE); + gelic_descr_set_status(descr, GELIC_DESCR_DMA_NOT_IN_USE); /* * this call can fail, but for now, just leave this * decriptor without skb */ - gelic_net_prepare_rx_descr(card, descr); + gelic_descr_prepare_rx(card, descr); - chain->head = descr; - chain->tail = descr->next; + chain->tail = descr; + chain->head = descr->next; /* * Set this descriptor the end of the chain. */ - descr->prev->next_descr_addr = descr->bus_addr; + descr->prev->next_descr_addr = cpu_to_be32(descr->bus_addr); /* * If dmac chain was met, DMAC stopped. @@ -956,29 +1073,27 @@ refill: /** * gelic_net_poll - NAPI poll function called by the stack to return packets - * @netdev: interface device structure + * @napi: napi structure * @budget: number of packets we can pass to the stack at most * - * returns 0 if no more packets available to the driver/stack. Returns 1, - * if the quota is exceeded, but the driver has still packets. + * returns the number of the processed packets * */ static int gelic_net_poll(struct napi_struct *napi, int budget) { - struct gelic_net_card *card = container_of(napi, struct gelic_net_card, napi); - struct net_device *netdev = card->netdev; + struct gelic_card *card = container_of(napi, struct gelic_card, napi); int packets_done = 0; while (packets_done < budget) { - if (!gelic_net_decode_one_descr(card)) + if (!gelic_card_decode_one_descr(card)) break; packets_done++; } if (packets_done < budget) { - netif_rx_complete(netdev, napi); - gelic_net_rx_irq_on(card); + napi_complete(napi); + gelic_card_rx_irq_on(card); } return packets_done; } @@ -989,7 +1104,7 @@ static int gelic_net_poll(struct napi_struct *napi, int budget) * * returns 0 on success, <0 on failure */ -static int gelic_net_change_mtu(struct net_device *netdev, int new_mtu) +int gelic_net_change_mtu(struct net_device *netdev, int new_mtu) { /* no need to re-alloc skbs or so -- the max mtu is about 2.3k * and mtu is outbound only anyway */ @@ -1002,13 +1117,12 @@ static int gelic_net_change_mtu(struct net_device *netdev, int new_mtu) } /** - * gelic_net_interrupt - event handler for gelic_net + * gelic_card_interrupt - event handler for gelic_net */ -static irqreturn_t gelic_net_interrupt(int irq, void *ptr) +static irqreturn_t gelic_card_interrupt(int irq, void *ptr) { unsigned long flags; - struct net_device *netdev = ptr; - struct gelic_net_card *card = netdev_priv(netdev); + struct gelic_card *card = ptr; u64 status; status = card->irq_status; @@ -1016,24 +1130,37 @@ static irqreturn_t gelic_net_interrupt(int irq, void *ptr) if (!status) return IRQ_NONE; + status &= card->irq_mask; + if (card->rx_dma_restart_required) { card->rx_dma_restart_required = 0; - gelic_net_enable_rxdmac(card); + gelic_card_enable_rxdmac(card); } - if (status & GELIC_NET_RXINT) { - gelic_net_rx_irq_off(card); - netif_rx_schedule(netdev, &card->napi); + if (status & GELIC_CARD_RXINT) { + gelic_card_rx_irq_off(card); + napi_schedule(&card->napi); } - if (status & GELIC_NET_TXINT) { - spin_lock_irqsave(&card->tx_dma_lock, flags); + if (status & GELIC_CARD_TXINT) { + spin_lock_irqsave(&card->tx_lock, flags); card->tx_dma_progress = 0; - gelic_net_release_tx_chain(card, 0); + gelic_card_release_tx_chain(card, 0); /* kick outstanding tx descriptor if any */ - gelic_net_kick_txdma(card, card->tx_chain.tail); - spin_unlock_irqrestore(&card->tx_dma_lock, flags); + gelic_card_kick_txdma(card, card->tx_chain.tail); + spin_unlock_irqrestore(&card->tx_lock, flags); } + + /* ether port status changed */ + if (status & GELIC_CARD_PORT_STATUS_CHANGED) + gelic_card_get_ether_port_status(card, 1); + +#ifdef CONFIG_GELIC_WIRELESS + if (status & (GELIC_CARD_WLAN_EVENT_RECEIVED | + GELIC_CARD_WLAN_COMMAND_COMPLETED)) + gelic_wl_interrupt(card->netdev[GELIC_PORT_WIRELESS], status); +#endif + return IRQ_HANDLED; } @@ -1044,55 +1171,17 @@ static irqreturn_t gelic_net_interrupt(int irq, void *ptr) * * see Documentation/networking/netconsole.txt */ -static void gelic_net_poll_controller(struct net_device *netdev) +void gelic_net_poll_controller(struct net_device *netdev) { - struct gelic_net_card *card = netdev_priv(netdev); + struct gelic_card *card = netdev_card(netdev); - gelic_net_set_irq_mask(card, 0); - gelic_net_interrupt(netdev->irq, netdev); - gelic_net_set_irq_mask(card, card->ghiintmask); + gelic_card_set_irq_mask(card, 0); + gelic_card_interrupt(netdev->irq, netdev); + gelic_card_set_irq_mask(card, card->irq_mask); } #endif /* CONFIG_NET_POLL_CONTROLLER */ /** - * gelic_net_open_device - open device and map dma region - * @card: card structure - */ -static int gelic_net_open_device(struct gelic_net_card *card) -{ - int result; - - result = ps3_sb_event_receive_port_setup(card->dev, PS3_BINDING_CPU_ANY, - &card->netdev->irq); - - if (result) { - dev_info(ctodev(card), - "%s:%d: gelic_net_open_device failed (%d)\n", - __func__, __LINE__, result); - result = -EPERM; - goto fail_alloc_irq; - } - - result = request_irq(card->netdev->irq, gelic_net_interrupt, - IRQF_DISABLED, card->netdev->name, card->netdev); - - if (result) { - dev_info(ctodev(card), "%s:%d: request_irq failed (%d)\n", - __func__, __LINE__, result); - goto fail_request_irq; - } - - return 0; - -fail_request_irq: - ps3_sb_event_receive_port_destroy(card->dev, card->netdev->irq); - card->netdev->irq = NO_IRQ; -fail_alloc_irq: - return result; -} - - -/** * gelic_net_open - called upon ifonfig up * @netdev: interface device structure * @@ -1101,169 +1190,88 @@ fail_alloc_irq: * gelic_net_open allocates all the descriptors and memory needed for * operation, sets up multicast list and enables interrupts */ -static int gelic_net_open(struct net_device *netdev) +int gelic_net_open(struct net_device *netdev) { - struct gelic_net_card *card = netdev_priv(netdev); - - dev_dbg(ctodev(card), " -> %s:%d\n", __func__, __LINE__); - - gelic_net_open_device(card); - - if (gelic_net_init_chain(card, &card->tx_chain, - card->descr, GELIC_NET_TX_DESCRIPTORS)) - goto alloc_tx_failed; - if (gelic_net_init_chain(card, &card->rx_chain, - card->descr + GELIC_NET_TX_DESCRIPTORS, - GELIC_NET_RX_DESCRIPTORS)) - goto alloc_rx_failed; - - /* head of chain */ - card->tx_top = card->tx_chain.head; - card->rx_top = card->rx_chain.head; - dev_dbg(ctodev(card), "descr rx %p, tx %p, size %#lx, num %#x\n", - card->rx_top, card->tx_top, sizeof(struct gelic_net_descr), - GELIC_NET_RX_DESCRIPTORS); - /* allocate rx skbs */ - if (gelic_net_alloc_rx_skbs(card)) - goto alloc_skbs_failed; + struct gelic_card *card = netdev_card(netdev); - napi_enable(&card->napi); - - card->tx_dma_progress = 0; - card->ghiintmask = GELIC_NET_RXINT | GELIC_NET_TXINT; + dev_dbg(ctodev(card), " -> %s %p\n", __func__, netdev); - gelic_net_set_irq_mask(card, card->ghiintmask); - gelic_net_enable_rxdmac(card); + gelic_card_up(card); netif_start_queue(netdev); - netif_carrier_on(netdev); + gelic_card_get_ether_port_status(card, 1); + dev_dbg(ctodev(card), " <- %s\n", __func__); return 0; - -alloc_skbs_failed: - gelic_net_free_chain(card, card->rx_top); -alloc_rx_failed: - gelic_net_free_chain(card, card->tx_top); -alloc_tx_failed: - return -ENOMEM; } -static void gelic_net_get_drvinfo (struct net_device *netdev, - struct ethtool_drvinfo *info) +void gelic_net_get_drvinfo(struct net_device *netdev, + struct ethtool_drvinfo *info) { strncpy(info->driver, DRV_NAME, sizeof(info->driver) - 1); strncpy(info->version, DRV_VERSION, sizeof(info->version) - 1); } -static int gelic_net_get_settings(struct net_device *netdev, - struct ethtool_cmd *cmd) +static int gelic_ether_get_settings(struct net_device *netdev, + struct ethtool_cmd *cmd) { - struct gelic_net_card *card = netdev_priv(netdev); - int status; - u64 v1, v2; - int speed, duplex; + struct gelic_card *card = netdev_card(netdev); - speed = duplex = -1; - status = lv1_net_control(bus_id(card), dev_id(card), - GELIC_NET_GET_ETH_PORT_STATUS, GELIC_NET_PORT, 0, 0, - &v1, &v2); - if (status) { - /* link down */ - } else { - if (v1 & GELIC_NET_FULL_DUPLEX) { - duplex = DUPLEX_FULL; - } else { - duplex = DUPLEX_HALF; - } + gelic_card_get_ether_port_status(card, 0); - if (v1 & GELIC_NET_SPEED_10 ) { - speed = SPEED_10; - } else if (v1 & GELIC_NET_SPEED_100) { - speed = SPEED_100; - } else if (v1 & GELIC_NET_SPEED_1000) { - speed = SPEED_1000; - } + if (card->ether_port_status & GELIC_LV1_ETHER_FULL_DUPLEX) + cmd->duplex = DUPLEX_FULL; + else + cmd->duplex = DUPLEX_HALF; + + switch (card->ether_port_status & GELIC_LV1_ETHER_SPEED_MASK) { + case GELIC_LV1_ETHER_SPEED_10: + cmd->speed = SPEED_10; + break; + case GELIC_LV1_ETHER_SPEED_100: + cmd->speed = SPEED_100; + break; + case GELIC_LV1_ETHER_SPEED_1000: + cmd->speed = SPEED_1000; + break; + default: + pr_info("%s: speed unknown\n", __func__); + cmd->speed = SPEED_10; + break; } + cmd->supported = SUPPORTED_TP | SUPPORTED_Autoneg | SUPPORTED_10baseT_Half | SUPPORTED_10baseT_Full | SUPPORTED_100baseT_Half | SUPPORTED_100baseT_Full | SUPPORTED_1000baseT_Half | SUPPORTED_1000baseT_Full; cmd->advertising = cmd->supported; - cmd->speed = speed; - cmd->duplex = duplex; cmd->autoneg = AUTONEG_ENABLE; /* always enabled */ cmd->port = PORT_TP; return 0; } -static u32 gelic_net_get_link(struct net_device *netdev) +u32 gelic_net_get_rx_csum(struct net_device *netdev) { - struct gelic_net_card *card = netdev_priv(netdev); - int status; - u64 v1, v2; - int link; - - status = lv1_net_control(bus_id(card), dev_id(card), - GELIC_NET_GET_ETH_PORT_STATUS, GELIC_NET_PORT, 0, 0, - &v1, &v2); - if (status) - return 0; /* link down */ - - if (v1 & GELIC_NET_LINK_UP) - link = 1; - else - link = 0; - - return link; -} - -static int gelic_net_nway_reset(struct net_device *netdev) -{ - if (netif_running(netdev)) { - gelic_net_stop(netdev); - gelic_net_open(netdev); - } - return 0; -} - -static u32 gelic_net_get_tx_csum(struct net_device *netdev) -{ - return (netdev->features & NETIF_F_IP_CSUM) != 0; -} - -static int gelic_net_set_tx_csum(struct net_device *netdev, u32 data) -{ - if (data) - netdev->features |= NETIF_F_IP_CSUM; - else - netdev->features &= ~NETIF_F_IP_CSUM; - - return 0; -} - -static u32 gelic_net_get_rx_csum(struct net_device *netdev) -{ - struct gelic_net_card *card = netdev_priv(netdev); + struct gelic_card *card = netdev_card(netdev); return card->rx_csum; } -static int gelic_net_set_rx_csum(struct net_device *netdev, u32 data) +int gelic_net_set_rx_csum(struct net_device *netdev, u32 data) { - struct gelic_net_card *card = netdev_priv(netdev); + struct gelic_card *card = netdev_card(netdev); card->rx_csum = data; return 0; } -static struct ethtool_ops gelic_net_ethtool_ops = { +static struct ethtool_ops gelic_ether_ethtool_ops = { .get_drvinfo = gelic_net_get_drvinfo, - .get_settings = gelic_net_get_settings, - .get_link = gelic_net_get_link, - .nway_reset = gelic_net_nway_reset, - .get_tx_csum = gelic_net_get_tx_csum, - .set_tx_csum = gelic_net_set_tx_csum, + .get_settings = gelic_ether_get_settings, + .get_link = ethtool_op_get_link, + .get_tx_csum = ethtool_op_get_tx_csum, + .set_tx_csum = ethtool_op_set_tx_csum, .get_rx_csum = gelic_net_get_rx_csum, .set_rx_csum = gelic_net_set_rx_csum, }; @@ -1277,9 +1285,9 @@ static struct ethtool_ops gelic_net_ethtool_ops = { */ static void gelic_net_tx_timeout_task(struct work_struct *work) { - struct gelic_net_card *card = - container_of(work, struct gelic_net_card, tx_timeout_task); - struct net_device *netdev = card->netdev; + struct gelic_card *card = + container_of(work, struct gelic_card, tx_timeout_task); + struct net_device *netdev = card->netdev[GELIC_PORT_ETHERNET]; dev_info(ctodev(card), "%s:Timed out. Restarting... \n", __func__); @@ -1302,11 +1310,11 @@ out: * * called, if tx hangs. Schedules a task that resets the interface */ -static void gelic_net_tx_timeout(struct net_device *netdev) +void gelic_net_tx_timeout(struct net_device *netdev) { - struct gelic_net_card *card; + struct gelic_card *card; - card = netdev_priv(netdev); + card = netdev_card(netdev); atomic_inc(&card->tx_timeout_task_counter); if (netdev->flags & IFF_UP) schedule_work(&card->tx_timeout_task); @@ -1315,12 +1323,13 @@ static void gelic_net_tx_timeout(struct net_device *netdev) } /** - * gelic_net_setup_netdev_ops - initialization of net_device operations + * gelic_ether_setup_netdev_ops - initialization of net_device operations * @netdev: net_device structure * * fills out function pointers in the net_device structure */ -static void gelic_net_setup_netdev_ops(struct net_device *netdev) +static void gelic_ether_setup_netdev_ops(struct net_device *netdev, + struct napi_struct *napi) { netdev->open = &gelic_net_open; netdev->stop = &gelic_net_stop; @@ -1330,163 +1339,239 @@ static void gelic_net_setup_netdev_ops(struct net_device *netdev) /* tx watchdog */ netdev->tx_timeout = &gelic_net_tx_timeout; netdev->watchdog_timeo = GELIC_NET_WATCHDOG_TIMEOUT; - netdev->ethtool_ops = &gelic_net_ethtool_ops; + /* NAPI */ + netif_napi_add(netdev, napi, + gelic_net_poll, GELIC_NET_NAPI_WEIGHT); + netdev->ethtool_ops = &gelic_ether_ethtool_ops; +#ifdef CONFIG_NET_POLL_CONTROLLER + netdev->poll_controller = gelic_net_poll_controller; +#endif } /** - * gelic_net_setup_netdev - initialization of net_device + * gelic_ether_setup_netdev - initialization of net_device + * @netdev: net_device structure * @card: card structure * * Returns 0 on success or <0 on failure * - * gelic_net_setup_netdev initializes the net_device structure + * gelic_ether_setup_netdev initializes the net_device structure + * and register it. **/ -static int gelic_net_setup_netdev(struct gelic_net_card *card) +int gelic_net_setup_netdev(struct net_device *netdev, struct gelic_card *card) { - struct net_device *netdev = card->netdev; - struct sockaddr addr; - unsigned int i; int status; u64 v1, v2; DECLARE_MAC_BUF(mac); - SET_NETDEV_DEV(netdev, &card->dev->core); - spin_lock_init(&card->tx_dma_lock); - - card->rx_csum = GELIC_NET_RX_CSUM_DEFAULT; - - gelic_net_setup_netdev_ops(netdev); - - netif_napi_add(netdev, &card->napi, - gelic_net_poll, GELIC_NET_NAPI_WEIGHT); - netdev->features = NETIF_F_IP_CSUM; status = lv1_net_control(bus_id(card), dev_id(card), - GELIC_NET_GET_MAC_ADDRESS, + GELIC_LV1_GET_MAC_ADDRESS, 0, 0, 0, &v1, &v2); + v1 <<= 16; if (status || !is_valid_ether_addr((u8 *)&v1)) { dev_info(ctodev(card), "%s:lv1_net_control GET_MAC_ADDR failed %d\n", __func__, status); return -EINVAL; } - v1 <<= 16; - memcpy(addr.sa_data, &v1, ETH_ALEN); - memcpy(netdev->dev_addr, addr.sa_data, ETH_ALEN); - dev_info(ctodev(card), "MAC addr %s\n", - print_mac(mac, netdev->dev_addr)); + memcpy(netdev->dev_addr, &v1, ETH_ALEN); - card->vlan_index = -1; /* no vlan */ - for (i = 0; i < GELIC_NET_VLAN_MAX; i++) { - status = lv1_net_control(bus_id(card), dev_id(card), - GELIC_NET_GET_VLAN_ID, - i + 1, /* index; one based */ - 0, 0, &v1, &v2); - if (status == GELIC_NET_VLAN_NO_ENTRY) { - dev_dbg(ctodev(card), - "GELIC_VLAN_ID no entry:%d, VLAN disabled\n", - status); - card->vlan_id[i] = 0; - } else if (status) { - dev_dbg(ctodev(card), - "%s:GELIC_NET_VLAN_ID faild, status=%d\n", - __func__, status); - card->vlan_id[i] = 0; - } else { - card->vlan_id[i] = (u32)v1; - dev_dbg(ctodev(card), "vlan_id:%d, %lx\n", i, v1); - } - } - - if (card->vlan_id[GELIC_NET_VLAN_WIRED - 1]) { - card->vlan_index = GELIC_NET_VLAN_WIRED - 1; + if (card->vlan_required) { netdev->hard_header_len += VLAN_HLEN; + /* + * As vlan is internally used, + * we can not receive vlan packets + */ + netdev->features |= NETIF_F_VLAN_CHALLENGED; } status = register_netdev(netdev); if (status) { - dev_err(ctodev(card), "%s:Couldn't register net_device: %d\n", - __func__, status); + dev_err(ctodev(card), "%s:Couldn't register %s %d\n", + __func__, netdev->name, status); return status; } + dev_info(ctodev(card), "%s: MAC addr %s\n", + netdev->name, + print_mac(mac, netdev->dev_addr)); return 0; } /** - * gelic_net_alloc_card - allocates net_device and card structure + * gelic_alloc_card_net - allocates net_device and card structure * * returns the card structure or NULL in case of errors * * the card and net_device structures are linked to each other */ -static struct gelic_net_card *gelic_net_alloc_card(void) +#define GELIC_ALIGN (32) +static struct gelic_card *gelic_alloc_card_net(struct net_device **netdev) { - struct net_device *netdev; - struct gelic_net_card *card; + struct gelic_card *card; + struct gelic_port *port; + void *p; size_t alloc_size; - - alloc_size = sizeof (*card) + - sizeof (struct gelic_net_descr) * GELIC_NET_RX_DESCRIPTORS + - sizeof (struct gelic_net_descr) * GELIC_NET_TX_DESCRIPTORS; /* - * we assume private data is allocated 32 bytes (or more) aligned - * so that gelic_net_descr should be 32 bytes aligned. - * Current alloc_etherdev() does do it because NETDEV_ALIGN - * is 32. - * check this assumption here. + * gelic requires dma descriptor is 32 bytes aligned and + * the hypervisor requires irq_status is 8 bytes aligned. */ - BUILD_BUG_ON(NETDEV_ALIGN < 32); - BUILD_BUG_ON(offsetof(struct gelic_net_card, irq_status) % 8); - BUILD_BUG_ON(offsetof(struct gelic_net_card, descr) % 32); + BUILD_BUG_ON(offsetof(struct gelic_card, irq_status) % 8); + BUILD_BUG_ON(offsetof(struct gelic_card, descr) % 32); + alloc_size = + sizeof(struct gelic_card) + + sizeof(struct gelic_descr) * GELIC_NET_RX_DESCRIPTORS + + sizeof(struct gelic_descr) * GELIC_NET_TX_DESCRIPTORS + + GELIC_ALIGN - 1; + + p = kzalloc(alloc_size, GFP_KERNEL); + if (!p) + return NULL; + card = PTR_ALIGN(p, GELIC_ALIGN); + card->unalign = p; - netdev = alloc_etherdev(alloc_size); - if (!netdev) + /* + * alloc netdev + */ + *netdev = alloc_etherdev(sizeof(struct gelic_port)); + if (!netdev) { + kfree(card->unalign); return NULL; + } + port = netdev_priv(*netdev); + + /* gelic_port */ + port->netdev = *netdev; + port->card = card; + port->type = GELIC_PORT_ETHERNET; + + /* gelic_card */ + card->netdev[GELIC_PORT_ETHERNET] = *netdev; - card = netdev_priv(netdev); - card->netdev = netdev; INIT_WORK(&card->tx_timeout_task, gelic_net_tx_timeout_task); init_waitqueue_head(&card->waitq); atomic_set(&card->tx_timeout_task_counter, 0); + init_MUTEX(&card->updown_lock); + atomic_set(&card->users, 0); return card; } +static void gelic_card_get_vlan_info(struct gelic_card *card) +{ + u64 v1, v2; + int status; + unsigned int i; + struct { + int tx; + int rx; + } vlan_id_ix[2] = { + [GELIC_PORT_ETHERNET] = { + .tx = GELIC_LV1_VLAN_TX_ETHERNET, + .rx = GELIC_LV1_VLAN_RX_ETHERNET + }, + [GELIC_PORT_WIRELESS] = { + .tx = GELIC_LV1_VLAN_TX_WIRELESS, + .rx = GELIC_LV1_VLAN_RX_WIRELESS + } + }; + + for (i = 0; i < ARRAY_SIZE(vlan_id_ix); i++) { + /* tx tag */ + status = lv1_net_control(bus_id(card), dev_id(card), + GELIC_LV1_GET_VLAN_ID, + vlan_id_ix[i].tx, + 0, 0, &v1, &v2); + if (status || !v1) { + if (status != LV1_NO_ENTRY) + dev_dbg(ctodev(card), + "get vlan id for tx(%d) failed(%d)\n", + vlan_id_ix[i].tx, status); + card->vlan[i].tx = 0; + card->vlan[i].rx = 0; + continue; + } + card->vlan[i].tx = (u16)v1; + + /* rx tag */ + status = lv1_net_control(bus_id(card), dev_id(card), + GELIC_LV1_GET_VLAN_ID, + vlan_id_ix[i].rx, + 0, 0, &v1, &v2); + if (status || !v1) { + if (status != LV1_NO_ENTRY) + dev_info(ctodev(card), + "get vlan id for rx(%d) failed(%d)\n", + vlan_id_ix[i].rx, status); + card->vlan[i].tx = 0; + card->vlan[i].rx = 0; + continue; + } + card->vlan[i].rx = (u16)v1; + + dev_dbg(ctodev(card), "vlan_id[%d] tx=%02x rx=%02x\n", + i, card->vlan[i].tx, card->vlan[i].rx); + } + + if (card->vlan[GELIC_PORT_ETHERNET].tx) { + BUG_ON(!card->vlan[GELIC_PORT_WIRELESS].tx); + card->vlan_required = 1; + } else + card->vlan_required = 0; + + /* check wirelss capable firmware */ + if (ps3_compare_firmware_version(1, 6, 0) < 0) { + card->vlan[GELIC_PORT_WIRELESS].tx = 0; + card->vlan[GELIC_PORT_WIRELESS].rx = 0; + } + + dev_info(ctodev(card), "internal vlan %s\n", + card->vlan_required? "enabled" : "disabled"); +} /** * ps3_gelic_driver_probe - add a device to the control of this driver */ -static int ps3_gelic_driver_probe (struct ps3_system_bus_device *dev) +static int ps3_gelic_driver_probe(struct ps3_system_bus_device *dev) { - struct gelic_net_card *card = gelic_net_alloc_card(); + struct gelic_card *card; + struct net_device *netdev; int result; - if (!card) { - dev_info(&dev->core, "gelic_net_alloc_card failed\n"); - result = -ENOMEM; - goto fail_alloc_card; - } - - ps3_system_bus_set_driver_data(dev, card); - card->dev = dev; - + pr_debug("%s: called\n", __func__); result = ps3_open_hv_device(dev); if (result) { - dev_dbg(&dev->core, "ps3_open_hv_device failed\n"); + dev_dbg(&dev->core, "%s:ps3_open_hv_device failed\n", + __func__); goto fail_open; } result = ps3_dma_region_create(dev->d_region); if (result) { - dev_dbg(&dev->core, "ps3_dma_region_create failed(%d)\n", - result); + dev_dbg(&dev->core, "%s:ps3_dma_region_create failed(%d)\n", + __func__, result); BUG_ON("check region type"); goto fail_dma_region; } + /* alloc card/netdevice */ + card = gelic_alloc_card_net(&netdev); + if (!card) { + dev_info(&dev->core, "%s:gelic_net_alloc_card failed\n", + __func__); + result = -ENOMEM; + goto fail_alloc_card; + } + ps3_system_bus_set_driver_data(dev, card); + card->dev = dev; + + /* get internal vlan info */ + gelic_card_get_vlan_info(card); + + /* setup interrupt */ result = lv1_net_set_interrupt_status_indicator(bus_id(card), dev_id(card), ps3_mm_phys_to_lpar(__pa(&card->irq_status)), @@ -1494,34 +1579,101 @@ static int ps3_gelic_driver_probe (struct ps3_system_bus_device *dev) if (result) { dev_dbg(&dev->core, - "lv1_net_set_interrupt_status_indicator failed: %s\n", - ps3_result(result)); + "%s:set_interrupt_status_indicator failed: %s\n", + __func__, ps3_result(result)); result = -EIO; goto fail_status_indicator; } - result = gelic_net_setup_netdev(card); + result = ps3_sb_event_receive_port_setup(dev, PS3_BINDING_CPU_ANY, + &card->irq); + + if (result) { + dev_info(ctodev(card), + "%s:gelic_net_open_device failed (%d)\n", + __func__, result); + result = -EPERM; + goto fail_alloc_irq; + } + result = request_irq(card->irq, gelic_card_interrupt, + IRQF_DISABLED, netdev->name, card); + + if (result) { + dev_info(ctodev(card), "%s:request_irq failed (%d)\n", + __func__, result); + goto fail_request_irq; + } + + /* setup card structure */ + card->irq_mask = GELIC_CARD_RXINT | GELIC_CARD_TXINT | + GELIC_CARD_PORT_STATUS_CHANGED; + card->rx_csum = GELIC_CARD_RX_CSUM_DEFAULT; + + if (gelic_card_init_chain(card, &card->tx_chain, + card->descr, GELIC_NET_TX_DESCRIPTORS)) + goto fail_alloc_tx; + if (gelic_card_init_chain(card, &card->rx_chain, + card->descr + GELIC_NET_TX_DESCRIPTORS, + GELIC_NET_RX_DESCRIPTORS)) + goto fail_alloc_rx; + + /* head of chain */ + card->tx_top = card->tx_chain.head; + card->rx_top = card->rx_chain.head; + dev_dbg(ctodev(card), "descr rx %p, tx %p, size %#lx, num %#x\n", + card->rx_top, card->tx_top, sizeof(struct gelic_descr), + GELIC_NET_RX_DESCRIPTORS); + /* allocate rx skbs */ + if (gelic_card_alloc_rx_skbs(card)) + goto fail_alloc_skbs; + + spin_lock_init(&card->tx_lock); + card->tx_dma_progress = 0; + + /* setup net_device structure */ + netdev->irq = card->irq; + SET_NETDEV_DEV(netdev, &card->dev->core); + gelic_ether_setup_netdev_ops(netdev, &card->napi); + result = gelic_net_setup_netdev(netdev, card); if (result) { - dev_dbg(&dev->core, "%s:%d: ps3_dma_region_create failed: " - "(%d)\n", __func__, __LINE__, result); + dev_dbg(&dev->core, "%s: setup_netdev failed %d", + __func__, result); goto fail_setup_netdev; } +#ifdef CONFIG_GELIC_WIRELESS + if (gelic_wl_driver_probe(card)) { + dev_dbg(&dev->core, "%s: WL init failed\n", __func__); + goto fail_setup_netdev; + } +#endif + pr_debug("%s: done\n", __func__); return 0; fail_setup_netdev: +fail_alloc_skbs: + gelic_card_free_chain(card, card->rx_chain.head); +fail_alloc_rx: + gelic_card_free_chain(card, card->tx_chain.head); +fail_alloc_tx: + free_irq(card->irq, card); + netdev->irq = NO_IRQ; +fail_request_irq: + ps3_sb_event_receive_port_destroy(dev, card->irq); +fail_alloc_irq: lv1_net_set_interrupt_status_indicator(bus_id(card), bus_id(card), - 0 , 0); + 0, 0); fail_status_indicator: + ps3_system_bus_set_driver_data(dev, NULL); + kfree(netdev_card(netdev)->unalign); + free_netdev(netdev); +fail_alloc_card: ps3_dma_region_free(dev->d_region); fail_dma_region: ps3_close_hv_device(dev); fail_open: - ps3_system_bus_set_driver_data(dev, NULL); - free_netdev(card->netdev); -fail_alloc_card: return result; } @@ -1529,9 +1681,34 @@ fail_alloc_card: * ps3_gelic_driver_remove - remove a device from the control of this driver */ -static int ps3_gelic_driver_remove (struct ps3_system_bus_device *dev) +static int ps3_gelic_driver_remove(struct ps3_system_bus_device *dev) { - struct gelic_net_card *card = ps3_system_bus_get_driver_data(dev); + struct gelic_card *card = ps3_system_bus_get_driver_data(dev); + struct net_device *netdev0; + pr_debug("%s: called\n", __func__); + +#ifdef CONFIG_GELIC_WIRELESS + gelic_wl_driver_remove(card); +#endif + /* stop interrupt */ + gelic_card_set_irq_mask(card, 0); + + /* turn off DMA, force end */ + gelic_card_disable_rxdmac(card); + gelic_card_disable_txdmac(card); + + /* release chains */ + gelic_card_release_tx_chain(card, 1); + gelic_card_release_rx_chain(card); + + gelic_card_free_chain(card, card->tx_top); + gelic_card_free_chain(card, card->rx_top); + + netdev0 = card->netdev[GELIC_PORT_ETHERNET]; + /* disconnect event port */ + free_irq(card->irq, card); + netdev0->irq = NO_IRQ; + ps3_sb_event_receive_port_destroy(card->dev, card->irq); wait_event(card->waitq, atomic_read(&card->tx_timeout_task_counter) == 0); @@ -1539,8 +1716,9 @@ static int ps3_gelic_driver_remove (struct ps3_system_bus_device *dev) lv1_net_set_interrupt_status_indicator(bus_id(card), dev_id(card), 0 , 0); - unregister_netdev(card->netdev); - free_netdev(card->netdev); + unregister_netdev(netdev0); + kfree(netdev_card(netdev0)->unalign); + free_netdev(netdev0); ps3_system_bus_set_driver_data(dev, NULL); @@ -1548,6 +1726,7 @@ static int ps3_gelic_driver_remove (struct ps3_system_bus_device *dev) ps3_close_hv_device(dev); + pr_debug("%s: done\n", __func__); return 0; } @@ -1572,8 +1751,8 @@ static void __exit ps3_gelic_driver_exit (void) ps3_system_bus_driver_unregister(&ps3_gelic_driver); } -module_init (ps3_gelic_driver_init); -module_exit (ps3_gelic_driver_exit); +module_init(ps3_gelic_driver_init); +module_exit(ps3_gelic_driver_exit); MODULE_ALIAS(PS3_MODULE_ALIAS_GELIC); diff --git a/drivers/net/ps3_gelic_net.h b/drivers/net/ps3_gelic_net.h index 968560269a3..1d39d06797e 100644 --- a/drivers/net/ps3_gelic_net.h +++ b/drivers/net/ps3_gelic_net.h @@ -35,198 +35,323 @@ #define GELIC_NET_MAX_MTU VLAN_ETH_FRAME_LEN #define GELIC_NET_MIN_MTU VLAN_ETH_ZLEN #define GELIC_NET_RXBUF_ALIGN 128 -#define GELIC_NET_RX_CSUM_DEFAULT 1 /* hw chksum */ +#define GELIC_CARD_RX_CSUM_DEFAULT 1 /* hw chksum */ #define GELIC_NET_WATCHDOG_TIMEOUT 5*HZ #define GELIC_NET_NAPI_WEIGHT (GELIC_NET_RX_DESCRIPTORS) #define GELIC_NET_BROADCAST_ADDR 0xffffffffffffL -#define GELIC_NET_VLAN_POS (VLAN_ETH_ALEN * 2) -#define GELIC_NET_VLAN_MAX 4 + #define GELIC_NET_MC_COUNT_MAX 32 /* multicast address list */ -enum gelic_net_int0_status { - GELIC_NET_GDTDCEINT = 24, - GELIC_NET_GRFANMINT = 28, -}; +/* virtual interrupt status register bits */ + /* INT1 */ +#define GELIC_CARD_TX_RAM_FULL_ERR 0x0000000000000001L +#define GELIC_CARD_RX_RAM_FULL_ERR 0x0000000000000002L +#define GELIC_CARD_TX_SHORT_FRAME_ERR 0x0000000000000004L +#define GELIC_CARD_TX_INVALID_DESCR_ERR 0x0000000000000008L +#define GELIC_CARD_RX_FIFO_FULL_ERR 0x0000000000002000L +#define GELIC_CARD_RX_DESCR_CHAIN_END 0x0000000000004000L +#define GELIC_CARD_RX_INVALID_DESCR_ERR 0x0000000000008000L +#define GELIC_CARD_TX_RESPONCE_ERR 0x0000000000010000L +#define GELIC_CARD_RX_RESPONCE_ERR 0x0000000000100000L +#define GELIC_CARD_TX_PROTECTION_ERR 0x0000000000400000L +#define GELIC_CARD_RX_PROTECTION_ERR 0x0000000004000000L +#define GELIC_CARD_TX_TCP_UDP_CHECKSUM_ERR 0x0000000008000000L +#define GELIC_CARD_PORT_STATUS_CHANGED 0x0000000020000000L +#define GELIC_CARD_WLAN_EVENT_RECEIVED 0x0000000040000000L +#define GELIC_CARD_WLAN_COMMAND_COMPLETED 0x0000000080000000L + /* INT 0 */ +#define GELIC_CARD_TX_FLAGGED_DESCR 0x0004000000000000L +#define GELIC_CARD_RX_FLAGGED_DESCR 0x0040000000000000L +#define GELIC_CARD_TX_TRANSFER_END 0x0080000000000000L +#define GELIC_CARD_TX_DESCR_CHAIN_END 0x0100000000000000L +#define GELIC_CARD_NUMBER_OF_RX_FRAME 0x1000000000000000L +#define GELIC_CARD_ONE_TIME_COUNT_TIMER 0x4000000000000000L +#define GELIC_CARD_FREE_RUN_COUNT_TIMER 0x8000000000000000L + +/* initial interrupt mask */ +#define GELIC_CARD_TXINT GELIC_CARD_TX_DESCR_CHAIN_END -/* GHIINT1STS bits */ -enum gelic_net_int1_status { - GELIC_NET_GDADCEINT = 14, +#define GELIC_CARD_RXINT (GELIC_CARD_RX_DESCR_CHAIN_END | \ + GELIC_CARD_NUMBER_OF_RX_FRAME) + + /* RX descriptor data_status bits */ +enum gelic_descr_rx_status { + GELIC_DESCR_RXDMADU = 0x80000000, /* destination MAC addr unknown */ + GELIC_DESCR_RXLSTFBF = 0x40000000, /* last frame buffer */ + GELIC_DESCR_RXIPCHK = 0x20000000, /* IP checksum performed */ + GELIC_DESCR_RXTCPCHK = 0x10000000, /* TCP/UDP checksup performed */ + GELIC_DESCR_RXWTPKT = 0x00C00000, /* + * wakeup trigger packet + * 01: Magic Packet (TM) + * 10: ARP packet + * 11: Multicast MAC addr + */ + GELIC_DESCR_RXVLNPKT = 0x00200000, /* VLAN packet */ + /* bit 20..16 reserved */ + GELIC_DESCR_RXRRECNUM = 0x0000ff00, /* reception receipt number */ + /* bit 7..0 reserved */ }; -/* interrupt mask */ -#define GELIC_NET_TXINT (1L << (GELIC_NET_GDTDCEINT + 32)) +#define GELIC_DESCR_DATA_STATUS_CHK_MASK \ + (GELIC_DESCR_RXIPCHK | GELIC_DESCR_RXTCPCHK) -#define GELIC_NET_RXINT0 (1L << (GELIC_NET_GRFANMINT + 32)) -#define GELIC_NET_RXINT1 (1L << GELIC_NET_GDADCEINT) -#define GELIC_NET_RXINT (GELIC_NET_RXINT0 | GELIC_NET_RXINT1) + /* TX descriptor data_status bits */ +enum gelic_descr_tx_status { + GELIC_DESCR_TX_TAIL = 0x00000001, /* gelic treated this + * descriptor was end of + * a tx frame + */ +}; - /* RX descriptor data_status bits */ -#define GELIC_NET_RXDMADU 0x80000000 /* destination MAC addr unknown */ -#define GELIC_NET_RXLSTFBF 0x40000000 /* last frame buffer */ -#define GELIC_NET_RXIPCHK 0x20000000 /* IP checksum performed */ -#define GELIC_NET_RXTCPCHK 0x10000000 /* TCP/UDP checksup performed */ -#define GELIC_NET_RXIPSPKT 0x08000000 /* IPsec packet */ -#define GELIC_NET_RXIPSAHPRT 0x04000000 /* IPsec AH protocol performed */ -#define GELIC_NET_RXIPSESPPRT 0x02000000 /* IPsec ESP protocol performed */ -#define GELIC_NET_RXSESPAH 0x01000000 /* - * IPsec ESP protocol auth - * performed - */ - -#define GELIC_NET_RXWTPKT 0x00C00000 /* - * wakeup trigger packet - * 01: Magic Packet (TM) - * 10: ARP packet - * 11: Multicast MAC addr - */ -#define GELIC_NET_RXVLNPKT 0x00200000 /* VLAN packet */ -/* bit 20..16 reserved */ -#define GELIC_NET_RXRRECNUM 0x0000ff00 /* reception receipt number */ -#define GELIC_NET_RXRRECNUM_SHIFT 8 -/* bit 7..0 reserved */ - -#define GELIC_NET_TXDESC_TAIL 0 -#define GELIC_NET_DATA_STATUS_CHK_MASK (GELIC_NET_RXIPCHK | GELIC_NET_RXTCPCHK) - -/* RX descriptor data_error bits */ -/* bit 31 reserved */ -#define GELIC_NET_RXALNERR 0x40000000 /* alignement error 10/100M */ -#define GELIC_NET_RXOVERERR 0x20000000 /* oversize error */ -#define GELIC_NET_RXRNTERR 0x10000000 /* Runt error */ -#define GELIC_NET_RXIPCHKERR 0x08000000 /* IP checksum error */ -#define GELIC_NET_RXTCPCHKERR 0x04000000 /* TCP/UDP checksum error */ -#define GELIC_NET_RXUMCHSP 0x02000000 /* unmatched sp on sp */ -#define GELIC_NET_RXUMCHSPI 0x01000000 /* unmatched SPI on SAD */ -#define GELIC_NET_RXUMCHSAD 0x00800000 /* unmatched SAD */ -#define GELIC_NET_RXIPSAHERR 0x00400000 /* auth error on AH protocol - * processing */ -#define GELIC_NET_RXIPSESPAHERR 0x00200000 /* auth error on ESP protocol - * processing */ -#define GELIC_NET_RXDRPPKT 0x00100000 /* drop packet */ -#define GELIC_NET_RXIPFMTERR 0x00080000 /* IP packet format error */ -/* bit 18 reserved */ -#define GELIC_NET_RXDATAERR 0x00020000 /* IP packet format error */ -#define GELIC_NET_RXCALERR 0x00010000 /* cariier extension length - * error */ -#define GELIC_NET_RXCREXERR 0x00008000 /* carrier extention error */ -#define GELIC_NET_RXMLTCST 0x00004000 /* multicast address frame */ -/* bit 13..0 reserved */ -#define GELIC_NET_DATA_ERROR_CHK_MASK \ - (GELIC_NET_RXIPCHKERR | GELIC_NET_RXTCPCHKERR) +/* RX descriptor data error bits */ +enum gelic_descr_rx_error { + /* bit 31 reserved */ + GELIC_DESCR_RXALNERR = 0x40000000, /* alignement error 10/100M */ + GELIC_DESCR_RXOVERERR = 0x20000000, /* oversize error */ + GELIC_DESCR_RXRNTERR = 0x10000000, /* Runt error */ + GELIC_DESCR_RXIPCHKERR = 0x08000000, /* IP checksum error */ + GELIC_DESCR_RXTCPCHKERR = 0x04000000, /* TCP/UDP checksum error */ + GELIC_DESCR_RXDRPPKT = 0x00100000, /* drop packet */ + GELIC_DESCR_RXIPFMTERR = 0x00080000, /* IP packet format error */ + /* bit 18 reserved */ + GELIC_DESCR_RXDATAERR = 0x00020000, /* IP packet format error */ + GELIC_DESCR_RXCALERR = 0x00010000, /* cariier extension length + * error */ + GELIC_DESCR_RXCREXERR = 0x00008000, /* carrier extention error */ + GELIC_DESCR_RXMLTCST = 0x00004000, /* multicast address frame */ + /* bit 13..0 reserved */ +}; +#define GELIC_DESCR_DATA_ERROR_CHK_MASK \ + (GELIC_DESCR_RXIPCHKERR | GELIC_DESCR_RXTCPCHKERR) +/* DMA command and status (RX and TX)*/ +enum gelic_descr_dma_status { + GELIC_DESCR_DMA_COMPLETE = 0x00000000, /* used in tx */ + GELIC_DESCR_DMA_BUFFER_FULL = 0x00000000, /* used in rx */ + GELIC_DESCR_DMA_RESPONSE_ERROR = 0x10000000, /* used in rx, tx */ + GELIC_DESCR_DMA_PROTECTION_ERROR = 0x20000000, /* used in rx, tx */ + GELIC_DESCR_DMA_FRAME_END = 0x40000000, /* used in rx */ + GELIC_DESCR_DMA_FORCE_END = 0x50000000, /* used in rx, tx */ + GELIC_DESCR_DMA_CARDOWNED = 0xa0000000, /* used in rx, tx */ + GELIC_DESCR_DMA_NOT_IN_USE = 0xb0000000, /* any other value */ +}; + +#define GELIC_DESCR_DMA_STAT_MASK (0xf0000000) /* tx descriptor command and status */ -#define GELIC_NET_DMAC_CMDSTAT_NOCS 0xa0080000 /* middle of frame */ -#define GELIC_NET_DMAC_CMDSTAT_TCPCS 0xa00a0000 -#define GELIC_NET_DMAC_CMDSTAT_UDPCS 0xa00b0000 -#define GELIC_NET_DMAC_CMDSTAT_END_FRAME 0x00040000 /* end of frame */ - -#define GELIC_NET_DMAC_CMDSTAT_RXDCEIS 0x00000002 /* descriptor chain end - * interrupt status */ - -#define GELIC_NET_DMAC_CMDSTAT_CHAIN_END 0x00000002 /* RXDCEIS:DMA stopped */ -#define GELIC_NET_DESCR_IND_PROC_SHIFT 28 -#define GELIC_NET_DESCR_IND_PROC_MASKO 0x0fffffff - - -enum gelic_net_descr_status { - GELIC_NET_DESCR_COMPLETE = 0x00, /* used in tx */ - GELIC_NET_DESCR_BUFFER_FULL = 0x00, /* used in rx */ - GELIC_NET_DESCR_RESPONSE_ERROR = 0x01, /* used in rx and tx */ - GELIC_NET_DESCR_PROTECTION_ERROR = 0x02, /* used in rx and tx */ - GELIC_NET_DESCR_FRAME_END = 0x04, /* used in rx */ - GELIC_NET_DESCR_FORCE_END = 0x05, /* used in rx and tx */ - GELIC_NET_DESCR_CARDOWNED = 0x0a, /* used in rx and tx */ - GELIC_NET_DESCR_NOT_IN_USE = 0x0b /* any other value */ +enum gelic_descr_tx_dma_status { + /* [19] */ + GELIC_DESCR_TX_DMA_IKE = 0x00080000, /* IPSEC off */ + /* [18] */ + GELIC_DESCR_TX_DMA_FRAME_TAIL = 0x00040000, /* last descriptor of + * the packet + */ + /* [17..16] */ + GELIC_DESCR_TX_DMA_TCP_CHKSUM = 0x00020000, /* TCP packet */ + GELIC_DESCR_TX_DMA_UDP_CHKSUM = 0x00030000, /* UDP packet */ + GELIC_DESCR_TX_DMA_NO_CHKSUM = 0x00000000, /* no checksum */ + + /* [1] */ + GELIC_DESCR_TX_DMA_CHAIN_END = 0x00000002, /* DMA terminated + * due to chain end + */ }; + +#define GELIC_DESCR_DMA_CMD_NO_CHKSUM \ + (GELIC_DESCR_DMA_CARDOWNED | GELIC_DESCR_TX_DMA_IKE | \ + GELIC_DESCR_TX_DMA_NO_CHKSUM) + +#define GELIC_DESCR_DMA_CMD_TCP_CHKSUM \ + (GELIC_DESCR_DMA_CARDOWNED | GELIC_DESCR_TX_DMA_IKE | \ + GELIC_DESCR_TX_DMA_TCP_CHKSUM) + +#define GELIC_DESCR_DMA_CMD_UDP_CHKSUM \ + (GELIC_DESCR_DMA_CARDOWNED | GELIC_DESCR_TX_DMA_IKE | \ + GELIC_DESCR_TX_DMA_UDP_CHKSUM) + +enum gelic_descr_rx_dma_status { + /* [ 1 ] */ + GELIC_DESCR_RX_DMA_CHAIN_END = 0x00000002, /* DMA terminated + * due to chain end + */ +}; + /* for lv1_net_control */ -#define GELIC_NET_GET_MAC_ADDRESS 0x0000000000000001 -#define GELIC_NET_GET_ETH_PORT_STATUS 0x0000000000000002 -#define GELIC_NET_SET_NEGOTIATION_MODE 0x0000000000000003 -#define GELIC_NET_GET_VLAN_ID 0x0000000000000004 - -#define GELIC_NET_LINK_UP 0x0000000000000001 -#define GELIC_NET_FULL_DUPLEX 0x0000000000000002 -#define GELIC_NET_AUTO_NEG 0x0000000000000004 -#define GELIC_NET_SPEED_10 0x0000000000000010 -#define GELIC_NET_SPEED_100 0x0000000000000020 -#define GELIC_NET_SPEED_1000 0x0000000000000040 - -#define GELIC_NET_VLAN_ALL 0x0000000000000001 -#define GELIC_NET_VLAN_WIRED 0x0000000000000002 -#define GELIC_NET_VLAN_WIRELESS 0x0000000000000003 -#define GELIC_NET_VLAN_PSP 0x0000000000000004 -#define GELIC_NET_VLAN_PORT0 0x0000000000000010 -#define GELIC_NET_VLAN_PORT1 0x0000000000000011 -#define GELIC_NET_VLAN_PORT2 0x0000000000000012 -#define GELIC_NET_VLAN_DAEMON_CLIENT_BSS 0x0000000000000013 -#define GELIC_NET_VLAN_LIBERO_CLIENT_BSS 0x0000000000000014 -#define GELIC_NET_VLAN_NO_ENTRY -6 - -#define GELIC_NET_PORT 2 /* for port status */ +enum gelic_lv1_net_control_code { + GELIC_LV1_GET_MAC_ADDRESS = 1, + GELIC_LV1_GET_ETH_PORT_STATUS = 2, + GELIC_LV1_SET_NEGOTIATION_MODE = 3, + GELIC_LV1_GET_VLAN_ID = 4, + GELIC_LV1_GET_CHANNEL = 6, + GELIC_LV1_POST_WLAN_CMD = 9, + GELIC_LV1_GET_WLAN_CMD_RESULT = 10, + GELIC_LV1_GET_WLAN_EVENT = 11 +}; + +/* status returened from GET_ETH_PORT_STATUS */ +enum gelic_lv1_ether_port_status { + GELIC_LV1_ETHER_LINK_UP = 0x0000000000000001L, + GELIC_LV1_ETHER_FULL_DUPLEX = 0x0000000000000002L, + GELIC_LV1_ETHER_AUTO_NEG = 0x0000000000000004L, + + GELIC_LV1_ETHER_SPEED_10 = 0x0000000000000010L, + GELIC_LV1_ETHER_SPEED_100 = 0x0000000000000020L, + GELIC_LV1_ETHER_SPEED_1000 = 0x0000000000000040L, + GELIC_LV1_ETHER_SPEED_MASK = 0x0000000000000070L +}; + +enum gelic_lv1_vlan_index { + /* for outgoing packets */ + GELIC_LV1_VLAN_TX_ETHERNET = 0x0000000000000002L, + GELIC_LV1_VLAN_TX_WIRELESS = 0x0000000000000003L, + /* for incoming packets */ + GELIC_LV1_VLAN_RX_ETHERNET = 0x0000000000000012L, + GELIC_LV1_VLAN_RX_WIRELESS = 0x0000000000000013L +}; /* size of hardware part of gelic descriptor */ -#define GELIC_NET_DESCR_SIZE (32) -struct gelic_net_descr { +#define GELIC_DESCR_SIZE (32) + +enum gelic_port_type { + GELIC_PORT_ETHERNET = 0, + GELIC_PORT_WIRELESS = 1, + GELIC_PORT_MAX +}; + +struct gelic_descr { /* as defined by the hardware */ - u32 buf_addr; - u32 buf_size; - u32 next_descr_addr; - u32 dmac_cmd_status; - u32 result_size; - u32 valid_size; /* all zeroes for tx */ - u32 data_status; - u32 data_error; /* all zeroes for tx */ + __be32 buf_addr; + __be32 buf_size; + __be32 next_descr_addr; + __be32 dmac_cmd_status; + __be32 result_size; + __be32 valid_size; /* all zeroes for tx */ + __be32 data_status; + __be32 data_error; /* all zeroes for tx */ /* used in the driver */ struct sk_buff *skb; dma_addr_t bus_addr; - struct gelic_net_descr *next; - struct gelic_net_descr *prev; - struct vlan_ethhdr vlan; + struct gelic_descr *next; + struct gelic_descr *prev; } __attribute__((aligned(32))); -struct gelic_net_descr_chain { +struct gelic_descr_chain { /* we walk from tail to head */ - struct gelic_net_descr *head; - struct gelic_net_descr *tail; + struct gelic_descr *head; + struct gelic_descr *tail; }; -struct gelic_net_card { - struct net_device *netdev; +struct gelic_vlan_id { + u16 tx; + u16 rx; +}; + +struct gelic_card { struct napi_struct napi; + struct net_device *netdev[GELIC_PORT_MAX]; /* * hypervisor requires irq_status should be * 8 bytes aligned, but u64 member is * always disposed in that manner */ u64 irq_status; - u64 ghiintmask; + u64 irq_mask; struct ps3_system_bus_device *dev; - u32 vlan_id[GELIC_NET_VLAN_MAX]; - int vlan_index; + struct gelic_vlan_id vlan[GELIC_PORT_MAX]; + int vlan_required; - struct gelic_net_descr_chain tx_chain; - struct gelic_net_descr_chain rx_chain; + struct gelic_descr_chain tx_chain; + struct gelic_descr_chain rx_chain; int rx_dma_restart_required; - /* gurad dmac descriptor chain*/ - spinlock_t chain_lock; - int rx_csum; - /* guard tx_dma_progress */ - spinlock_t tx_dma_lock; + /* + * tx_lock guards tx descriptor list and + * tx_dma_progress. + */ + spinlock_t tx_lock; int tx_dma_progress; struct work_struct tx_timeout_task; atomic_t tx_timeout_task_counter; wait_queue_head_t waitq; - struct gelic_net_descr *tx_top, *rx_top; - struct gelic_net_descr descr[0]; + /* only first user should up the card */ + struct semaphore updown_lock; + atomic_t users; + + u64 ether_port_status; + /* original address returned by kzalloc */ + void *unalign; + + /* + * each netdevice has copy of irq + */ + unsigned int irq; + struct gelic_descr *tx_top, *rx_top; + struct gelic_descr descr[0]; /* must be the last */ +}; + +struct gelic_port { + struct gelic_card *card; + struct net_device *netdev; + enum gelic_port_type type; + long priv[0]; /* long for alignment */ }; +static inline struct gelic_card *port_to_card(struct gelic_port *p) +{ + return p->card; +} +static inline struct net_device *port_to_netdev(struct gelic_port *p) +{ + return p->netdev; +} +static inline struct gelic_card *netdev_card(struct net_device *d) +{ + return ((struct gelic_port *)netdev_priv(d))->card; +} +static inline struct gelic_port *netdev_port(struct net_device *d) +{ + return (struct gelic_port *)netdev_priv(d); +} +static inline struct device *ctodev(struct gelic_card *card) +{ + return &card->dev->core; +} +static inline u64 bus_id(struct gelic_card *card) +{ + return card->dev->bus_id; +} +static inline u64 dev_id(struct gelic_card *card) +{ + return card->dev->dev_id; +} + +static inline void *port_priv(struct gelic_port *port) +{ + return port->priv; +} + +extern int gelic_card_set_irq_mask(struct gelic_card *card, u64 mask); +/* shared netdev ops */ +extern void gelic_card_up(struct gelic_card *card); +extern void gelic_card_down(struct gelic_card *card); +extern int gelic_net_open(struct net_device *netdev); +extern int gelic_net_stop(struct net_device *netdev); +extern int gelic_net_xmit(struct sk_buff *skb, struct net_device *netdev); +extern void gelic_net_set_multi(struct net_device *netdev); +extern void gelic_net_tx_timeout(struct net_device *netdev); +extern int gelic_net_change_mtu(struct net_device *netdev, int new_mtu); +extern int gelic_net_setup_netdev(struct net_device *netdev, + struct gelic_card *card); -extern unsigned long p_to_lp(long pa); +/* shared ethtool ops */ +extern void gelic_net_get_drvinfo(struct net_device *netdev, + struct ethtool_drvinfo *info); +extern u32 gelic_net_get_rx_csum(struct net_device *netdev); +extern int gelic_net_set_rx_csum(struct net_device *netdev, u32 data); +extern void gelic_net_poll_controller(struct net_device *netdev); #endif /* _GELIC_NET_H */ diff --git a/drivers/net/ps3_gelic_wireless.c b/drivers/net/ps3_gelic_wireless.c new file mode 100644 index 00000000000..750d2a99cb4 --- /dev/null +++ b/drivers/net/ps3_gelic_wireless.c @@ -0,0 +1,2753 @@ +/* + * PS3 gelic network driver. + * + * Copyright (C) 2007 Sony Computer Entertainment Inc. + * Copyright 2007 Sony Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation. + * + * 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. + */ +#undef DEBUG + +#include <linux/kernel.h> +#include <linux/module.h> + +#include <linux/etherdevice.h> +#include <linux/ethtool.h> +#include <linux/if_vlan.h> + +#include <linux/in.h> +#include <linux/ip.h> +#include <linux/tcp.h> +#include <linux/wireless.h> +#include <linux/ctype.h> +#include <linux/string.h> +#include <net/iw_handler.h> +#include <net/ieee80211.h> + +#include <linux/dma-mapping.h> +#include <net/checksum.h> +#include <asm/firmware.h> +#include <asm/ps3.h> +#include <asm/lv1call.h> + +#include "ps3_gelic_net.h" +#include "ps3_gelic_wireless.h" + + +static int gelic_wl_start_scan(struct gelic_wl_info *wl, int always_scan); +static int gelic_wl_try_associate(struct net_device *netdev); + +/* + * tables + */ + +/* 802.11b/g channel to freq in MHz */ +static const int channel_freq[] = { + 2412, 2417, 2422, 2427, 2432, + 2437, 2442, 2447, 2452, 2457, + 2462, 2467, 2472, 2484 +}; +#define NUM_CHANNELS ARRAY_SIZE(channel_freq) + +/* in bps */ +static const int bitrate_list[] = { + 1000000, + 2000000, + 5500000, + 11000000, + 6000000, + 9000000, + 12000000, + 18000000, + 24000000, + 36000000, + 48000000, + 54000000 +}; +#define NUM_BITRATES ARRAY_SIZE(bitrate_list) + +/* + * wpa2 support requires the hypervisor version 2.0 or later + */ +static inline int wpa2_capable(void) +{ + return (0 <= ps3_compare_firmware_version(2, 0, 0)); +} + +static inline int precise_ie(void) +{ + return 0; /* FIXME */ +} +/* + * post_eurus_cmd helpers + */ +struct eurus_cmd_arg_info { + int pre_arg; /* command requres arg1, arg2 at POST COMMAND */ + int post_arg; /* command requires arg1, arg2 at GET_RESULT */ +}; + +static const struct eurus_cmd_arg_info cmd_info[GELIC_EURUS_CMD_MAX_INDEX] = { + [GELIC_EURUS_CMD_SET_COMMON_CFG] = { .pre_arg = 1}, + [GELIC_EURUS_CMD_SET_WEP_CFG] = { .pre_arg = 1}, + [GELIC_EURUS_CMD_SET_WPA_CFG] = { .pre_arg = 1}, + [GELIC_EURUS_CMD_GET_COMMON_CFG] = { .post_arg = 1}, + [GELIC_EURUS_CMD_GET_WEP_CFG] = { .post_arg = 1}, + [GELIC_EURUS_CMD_GET_WPA_CFG] = { .post_arg = 1}, + [GELIC_EURUS_CMD_GET_RSSI_CFG] = { .post_arg = 1}, + [GELIC_EURUS_CMD_GET_SCAN] = { .post_arg = 1}, +}; + +#ifdef DEBUG +static const char *cmdstr(enum gelic_eurus_command ix) +{ + switch (ix) { + case GELIC_EURUS_CMD_ASSOC: + return "ASSOC"; + case GELIC_EURUS_CMD_DISASSOC: + return "DISASSOC"; + case GELIC_EURUS_CMD_START_SCAN: + return "SCAN"; + case GELIC_EURUS_CMD_GET_SCAN: + return "GET SCAN"; + case GELIC_EURUS_CMD_SET_COMMON_CFG: + return "SET_COMMON_CFG"; + case GELIC_EURUS_CMD_GET_COMMON_CFG: + return "GET_COMMON_CFG"; + case GELIC_EURUS_CMD_SET_WEP_CFG: + return "SET_WEP_CFG"; + case GELIC_EURUS_CMD_GET_WEP_CFG: + return "GET_WEP_CFG"; + case GELIC_EURUS_CMD_SET_WPA_CFG: + return "SET_WPA_CFG"; + case GELIC_EURUS_CMD_GET_WPA_CFG: + return "GET_WPA_CFG"; + case GELIC_EURUS_CMD_GET_RSSI_CFG: + return "GET_RSSI"; + default: + break; + } + return ""; +}; +#else +static inline const char *cmdstr(enum gelic_eurus_command ix) +{ + return ""; +} +#endif + +/* synchronously do eurus commands */ +static void gelic_eurus_sync_cmd_worker(struct work_struct *work) +{ + struct gelic_eurus_cmd *cmd; + struct gelic_card *card; + struct gelic_wl_info *wl; + + u64 arg1, arg2; + + pr_debug("%s: <-\n", __func__); + cmd = container_of(work, struct gelic_eurus_cmd, work); + BUG_ON(cmd_info[cmd->cmd].pre_arg && + cmd_info[cmd->cmd].post_arg); + wl = cmd->wl; + card = port_to_card(wl_port(wl)); + + if (cmd_info[cmd->cmd].pre_arg) { + arg1 = ps3_mm_phys_to_lpar(__pa(cmd->buffer)); + arg2 = cmd->buf_size; + } else { + arg1 = 0; + arg2 = 0; + } + init_completion(&wl->cmd_done_intr); + pr_debug("%s: cmd='%s' start\n", __func__, cmdstr(cmd->cmd)); + cmd->status = lv1_net_control(bus_id(card), dev_id(card), + GELIC_LV1_POST_WLAN_CMD, + cmd->cmd, arg1, arg2, + &cmd->tag, &cmd->size); + if (cmd->status) { + complete(&cmd->done); + pr_info("%s: cmd issue failed\n", __func__); + return; + } + + wait_for_completion(&wl->cmd_done_intr); + + if (cmd_info[cmd->cmd].post_arg) { + arg1 = ps3_mm_phys_to_lpar(__pa(cmd->buffer)); + arg2 = cmd->buf_size; + } else { + arg1 = 0; + arg2 = 0; + } + + cmd->status = lv1_net_control(bus_id(card), dev_id(card), + GELIC_LV1_GET_WLAN_CMD_RESULT, + cmd->tag, arg1, arg2, + &cmd->cmd_status, &cmd->size); +#ifdef DEBUG + if (cmd->status || cmd->cmd_status) { + pr_debug("%s: cmd done tag=%#lx arg1=%#lx, arg2=%#lx\n", __func__, + cmd->tag, arg1, arg2); + pr_debug("%s: cmd done status=%#x cmd_status=%#lx size=%#lx\n", + __func__, cmd->status, cmd->cmd_status, cmd->size); + } +#endif + complete(&cmd->done); + pr_debug("%s: cmd='%s' done\n", __func__, cmdstr(cmd->cmd)); +} + +static struct gelic_eurus_cmd *gelic_eurus_sync_cmd(struct gelic_wl_info *wl, + unsigned int eurus_cmd, + void *buffer, + unsigned int buf_size) +{ + struct gelic_eurus_cmd *cmd; + + /* allocate cmd */ + cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); + if (!cmd) + return NULL; + + /* initialize members */ + cmd->cmd = eurus_cmd; + cmd->buffer = buffer; + cmd->buf_size = buf_size; + cmd->wl = wl; + INIT_WORK(&cmd->work, gelic_eurus_sync_cmd_worker); + init_completion(&cmd->done); + queue_work(wl->eurus_cmd_queue, &cmd->work); + + /* wait for command completion */ + wait_for_completion(&cmd->done); + + return cmd; +} + +static u32 gelic_wl_get_link(struct net_device *netdev) +{ + struct gelic_wl_info *wl = port_wl(netdev_port(netdev)); + u32 ret; + + pr_debug("%s: <-\n", __func__); + down(&wl->assoc_stat_lock); + if (wl->assoc_stat == GELIC_WL_ASSOC_STAT_ASSOCIATED) + ret = 1; + else + ret = 0; + up(&wl->assoc_stat_lock); + pr_debug("%s: ->\n", __func__); + return ret; +} + +static void gelic_wl_send_iwap_event(struct gelic_wl_info *wl, u8 *bssid) +{ + union iwreq_data data; + + memset(&data, 0, sizeof(data)); + if (bssid) + memcpy(data.ap_addr.sa_data, bssid, ETH_ALEN); + data.ap_addr.sa_family = ARPHRD_ETHER; + wireless_send_event(port_to_netdev(wl_port(wl)), SIOCGIWAP, + &data, NULL); +} + +/* + * wireless extension handlers and helpers + */ + +/* SIOGIWNAME */ +static int gelic_wl_get_name(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *iwreq, char *extra) +{ + strcpy(iwreq->name, "IEEE 802.11bg"); + return 0; +} + +static void gelic_wl_get_ch_info(struct gelic_wl_info *wl) +{ + struct gelic_card *card = port_to_card(wl_port(wl)); + u64 ch_info_raw, tmp; + int status; + + if (!test_and_set_bit(GELIC_WL_STAT_CH_INFO, &wl->stat)) { + status = lv1_net_control(bus_id(card), dev_id(card), + GELIC_LV1_GET_CHANNEL, 0, 0, 0, + &ch_info_raw, + &tmp); + /* some fw versions may return error */ + if (status) { + if (status != LV1_NO_ENTRY) + pr_info("%s: available ch unknown\n", __func__); + wl->ch_info = 0x07ff;/* 11 ch */ + } else + /* 16 bits of MSB has available channels */ + wl->ch_info = ch_info_raw >> 48; + } + return; +} + +/* SIOGIWRANGE */ +static int gelic_wl_get_range(struct net_device *netdev, + struct iw_request_info *info, + union iwreq_data *iwreq, char *extra) +{ + struct iw_point *point = &iwreq->data; + struct iw_range *range = (struct iw_range *)extra; + struct gelic_wl_info *wl = port_wl(netdev_port(netdev)); + unsigned int i, chs; + + pr_debug("%s: <-\n", __func__); + point->length = sizeof(struct iw_range); + memset(range, 0, sizeof(struct iw_range)); + + range->we_version_compiled = WIRELESS_EXT; + range->we_version_source = 22; + + /* available channels and frequencies */ + gelic_wl_get_ch_info(wl); + + for (i = 0, chs = 0; + i < NUM_CHANNELS && chs < IW_MAX_FREQUENCIES; i++) + if (wl->ch_info & (1 << i)) { + range->freq[chs].i = i + 1; + range->freq[chs].m = channel_freq[i]; + range->freq[chs].e = 6; + chs++; + } + range->num_frequency = chs; + range->old_num_frequency = chs; + range->num_channels = chs; + range->old_num_channels = chs; + + /* bitrates */ + for (i = 0; i < NUM_BITRATES; i++) + range->bitrate[i] = bitrate_list[i]; + range->num_bitrates = i; + + /* signal levels */ + range->max_qual.qual = 100; /* relative value */ + range->max_qual.level = 100; + range->avg_qual.qual = 50; + range->avg_qual.level = 50; + range->sensitivity = 0; + + /* Event capability */ + IW_EVENT_CAPA_SET_KERNEL(range->event_capa); + IW_EVENT_CAPA_SET(range->event_capa, SIOCGIWAP); + IW_EVENT_CAPA_SET(range->event_capa, SIOCGIWSCAN); + + /* encryption capability */ + range->enc_capa = IW_ENC_CAPA_WPA | + IW_ENC_CAPA_CIPHER_TKIP | IW_ENC_CAPA_CIPHER_CCMP; + if (wpa2_capable()) + range->enc_capa |= IW_ENC_CAPA_WPA2; + range->encoding_size[0] = 5; /* 40bit WEP */ + range->encoding_size[1] = 13; /* 104bit WEP */ + range->encoding_size[2] = 32; /* WPA-PSK */ + range->num_encoding_sizes = 3; + range->max_encoding_tokens = GELIC_WEP_KEYS; + + pr_debug("%s: ->\n", __func__); + return 0; + +} + +/* SIOC{G,S}IWSCAN */ +static int gelic_wl_set_scan(struct net_device *netdev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + struct gelic_wl_info *wl = port_wl(netdev_priv(netdev)); + + return gelic_wl_start_scan(wl, 1); +} + +#define OUI_LEN 3 +static const u8 rsn_oui[OUI_LEN] = { 0x00, 0x0f, 0xac }; +static const u8 wpa_oui[OUI_LEN] = { 0x00, 0x50, 0xf2 }; + +/* + * synthesize WPA/RSN IE data + * See WiFi WPA specification and IEEE 802.11-2007 7.3.2.25 + * for the format + */ +static size_t gelic_wl_synthesize_ie(u8 *buf, + struct gelic_eurus_scan_info *scan) +{ + + const u8 *oui_header; + u8 *start = buf; + int rsn; + int ccmp; + + pr_debug("%s: <- sec=%16x\n", __func__, scan->security); + switch (be16_to_cpu(scan->security) & GELIC_EURUS_SCAN_SEC_MASK) { + case GELIC_EURUS_SCAN_SEC_WPA: + rsn = 0; + break; + case GELIC_EURUS_SCAN_SEC_WPA2: + rsn = 1; + break; + default: + /* WEP or none. No IE returned */ + return 0; + } + + switch (be16_to_cpu(scan->security) & GELIC_EURUS_SCAN_SEC_WPA_MASK) { + case GELIC_EURUS_SCAN_SEC_WPA_TKIP: + ccmp = 0; + break; + case GELIC_EURUS_SCAN_SEC_WPA_AES: + ccmp = 1; + break; + default: + if (rsn) { + ccmp = 1; + pr_info("%s: no cipher info. defaulted to CCMP\n", + __func__); + } else { + ccmp = 0; + pr_info("%s: no cipher info. defaulted to TKIP\n", + __func__); + } + } + + if (rsn) + oui_header = rsn_oui; + else + oui_header = wpa_oui; + + /* element id */ + if (rsn) + *buf++ = MFIE_TYPE_RSN; + else + *buf++ = MFIE_TYPE_GENERIC; + + /* length filed; set later */ + buf++; + + /* wpa special header */ + if (!rsn) { + memcpy(buf, wpa_oui, OUI_LEN); + buf += OUI_LEN; + *buf++ = 0x01; + } + + /* version */ + *buf++ = 0x01; /* version 1.0 */ + *buf++ = 0x00; + + /* group cipher */ + memcpy(buf, oui_header, OUI_LEN); + buf += OUI_LEN; + + if (ccmp) + *buf++ = 0x04; /* CCMP */ + else + *buf++ = 0x02; /* TKIP */ + + /* pairwise key count always 1 */ + *buf++ = 0x01; + *buf++ = 0x00; + + /* pairwise key suit */ + memcpy(buf, oui_header, OUI_LEN); + buf += OUI_LEN; + if (ccmp) + *buf++ = 0x04; /* CCMP */ + else + *buf++ = 0x02; /* TKIP */ + + /* AKM count is 1 */ + *buf++ = 0x01; + *buf++ = 0x00; + + /* AKM suite is assumed as PSK*/ + memcpy(buf, oui_header, OUI_LEN); + buf += OUI_LEN; + *buf++ = 0x02; /* PSK */ + + /* RSN capabilities is 0 */ + *buf++ = 0x00; + *buf++ = 0x00; + + /* set length field */ + start[1] = (buf - start - 2); + + pr_debug("%s: ->\n", __func__); + return (buf - start); +} + +struct ie_item { + u8 *data; + u8 len; +}; + +struct ie_info { + struct ie_item wpa; + struct ie_item rsn; +}; + +static void gelic_wl_parse_ie(u8 *data, size_t len, + struct ie_info *ie_info) +{ + size_t data_left = len; + u8 *pos = data; + u8 item_len; + u8 item_id; + + pr_debug("%s: data=%p len=%ld \n", __func__, + data, len); + memset(ie_info, 0, sizeof(struct ie_info)); + + while (0 < data_left) { + item_id = *pos++; + item_len = *pos++; + + switch (item_id) { + case MFIE_TYPE_GENERIC: + if (!memcmp(pos, wpa_oui, OUI_LEN) && + pos[OUI_LEN] == 0x01) { + ie_info->wpa.data = pos - 2; + ie_info->wpa.len = item_len + 2; + } + break; + case MFIE_TYPE_RSN: + ie_info->rsn.data = pos - 2; + /* length includes the header */ + ie_info->rsn.len = item_len + 2; + break; + default: + pr_debug("%s: ignore %#x,%d\n", __func__, + item_id, item_len); + break; + } + pos += item_len; + data_left -= item_len + 2; + } + pr_debug("%s: wpa=%p,%d wpa2=%p,%d\n", __func__, + ie_info->wpa.data, ie_info->wpa.len, + ie_info->rsn.data, ie_info->rsn.len); +} + + +/* + * translate the scan informations from hypervisor to a + * independent format + */ +static char *gelic_wl_translate_scan(struct net_device *netdev, + char *ev, + char *stop, + struct gelic_wl_scan_info *network) +{ + struct iw_event iwe; + struct gelic_eurus_scan_info *scan = network->hwinfo; + char *tmp; + u8 rate; + unsigned int i, j, len; + u8 buf[MAX_WPA_IE_LEN]; + + pr_debug("%s: <-\n", __func__); + + /* first entry should be AP's mac address */ + iwe.cmd = SIOCGIWAP; + iwe.u.ap_addr.sa_family = ARPHRD_ETHER; + memcpy(iwe.u.ap_addr.sa_data, &scan->bssid[2], ETH_ALEN); + ev = iwe_stream_add_event(ev, stop, &iwe, IW_EV_ADDR_LEN); + + /* ESSID */ + iwe.cmd = SIOCGIWESSID; + iwe.u.data.flags = 1; + iwe.u.data.length = strnlen(scan->essid, 32); + ev = iwe_stream_add_point(ev, stop, &iwe, scan->essid); + + /* FREQUENCY */ + iwe.cmd = SIOCGIWFREQ; + iwe.u.freq.m = be16_to_cpu(scan->channel); + iwe.u.freq.e = 0; /* table value in MHz */ + iwe.u.freq.i = 0; + ev = iwe_stream_add_event(ev, stop, &iwe, IW_EV_FREQ_LEN); + + /* RATES */ + iwe.cmd = SIOCGIWRATE; + iwe.u.bitrate.fixed = iwe.u.bitrate.disabled = 0; + /* to stuff multiple values in one event */ + tmp = ev + IW_EV_LCP_LEN; + /* put them in ascendant order (older is first) */ + i = 0; + j = 0; + pr_debug("%s: rates=%d rate=%d\n", __func__, + network->rate_len, network->rate_ext_len); + while (i < network->rate_len) { + if (j < network->rate_ext_len && + ((scan->ext_rate[j] & 0x7f) < (scan->rate[i] & 0x7f))) + rate = scan->ext_rate[j++] & 0x7f; + else + rate = scan->rate[i++] & 0x7f; + iwe.u.bitrate.value = rate * 500000; /* 500kbps unit */ + tmp = iwe_stream_add_value(ev, tmp, stop, &iwe, + IW_EV_PARAM_LEN); + } + while (j < network->rate_ext_len) { + iwe.u.bitrate.value = (scan->ext_rate[j++] & 0x7f) * 500000; + tmp = iwe_stream_add_value(ev, tmp, stop, &iwe, + IW_EV_PARAM_LEN); + } + /* Check if we added any rate */ + if (IW_EV_LCP_LEN < (tmp - ev)) + ev = tmp; + + /* ENCODE */ + iwe.cmd = SIOCGIWENCODE; + if (be16_to_cpu(scan->capability) & WLAN_CAPABILITY_PRIVACY) + iwe.u.data.flags = IW_ENCODE_ENABLED | IW_ENCODE_NOKEY; + else + iwe.u.data.flags = IW_ENCODE_DISABLED; + iwe.u.data.length = 0; + ev = iwe_stream_add_point(ev, stop, &iwe, scan->essid); + + /* MODE */ + iwe.cmd = SIOCGIWMODE; + if (be16_to_cpu(scan->capability) & + (WLAN_CAPABILITY_ESS | WLAN_CAPABILITY_IBSS)) { + if (be16_to_cpu(scan->capability) & WLAN_CAPABILITY_ESS) + iwe.u.mode = IW_MODE_MASTER; + else + iwe.u.mode = IW_MODE_ADHOC; + ev = iwe_stream_add_event(ev, stop, &iwe, IW_EV_UINT_LEN); + } + + /* QUAL */ + iwe.cmd = IWEVQUAL; + iwe.u.qual.updated = IW_QUAL_ALL_UPDATED | + IW_QUAL_QUAL_INVALID | IW_QUAL_NOISE_INVALID; + iwe.u.qual.level = be16_to_cpu(scan->rssi); + iwe.u.qual.qual = be16_to_cpu(scan->rssi); + iwe.u.qual.noise = 0; + ev = iwe_stream_add_event(ev, stop, &iwe, IW_EV_QUAL_LEN); + + /* RSN */ + memset(&iwe, 0, sizeof(iwe)); + if (be16_to_cpu(scan->size) <= sizeof(*scan)) { + /* If wpa[2] capable station, synthesize IE and put it */ + len = gelic_wl_synthesize_ie(buf, scan); + if (len) { + iwe.cmd = IWEVGENIE; + iwe.u.data.length = len; + ev = iwe_stream_add_point(ev, stop, &iwe, buf); + } + } else { + /* this scan info has IE data */ + struct ie_info ie_info; + size_t data_len; + + data_len = be16_to_cpu(scan->size) - sizeof(*scan); + + gelic_wl_parse_ie(scan->elements, data_len, &ie_info); + + if (ie_info.wpa.len && (ie_info.wpa.len <= sizeof(buf))) { + memcpy(buf, ie_info.wpa.data, ie_info.wpa.len); + iwe.cmd = IWEVGENIE; + iwe.u.data.length = ie_info.wpa.len; + ev = iwe_stream_add_point(ev, stop, &iwe, buf); + } + + if (ie_info.rsn.len && (ie_info.rsn.len <= sizeof(buf))) { + memset(&iwe, 0, sizeof(iwe)); + memcpy(buf, ie_info.rsn.data, ie_info.rsn.len); + iwe.cmd = IWEVGENIE; + iwe.u.data.length = ie_info.rsn.len; + ev = iwe_stream_add_point(ev, stop, &iwe, buf); + } + } + + pr_debug("%s: ->\n", __func__); + return ev; +} + + +static int gelic_wl_get_scan(struct net_device *netdev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + struct gelic_wl_info *wl = port_wl(netdev_priv(netdev)); + struct gelic_wl_scan_info *scan_info; + char *ev = extra; + char *stop = ev + wrqu->data.length; + int ret = 0; + unsigned long this_time = jiffies; + + pr_debug("%s: <-\n", __func__); + if (down_interruptible(&wl->scan_lock)) + return -EAGAIN; + + switch (wl->scan_stat) { + case GELIC_WL_SCAN_STAT_SCANNING: + /* If a scan in progress, caller should call me again */ + ret = -EAGAIN; + goto out; + break; + + case GELIC_WL_SCAN_STAT_INIT: + /* last scan request failed or never issued */ + ret = -ENODEV; + goto out; + break; + case GELIC_WL_SCAN_STAT_GOT_LIST: + /* ok, use current list */ + break; + } + + list_for_each_entry(scan_info, &wl->network_list, list) { + if (wl->scan_age == 0 || + time_after(scan_info->last_scanned + wl->scan_age, + this_time)) + ev = gelic_wl_translate_scan(netdev, ev, stop, + scan_info); + else + pr_debug("%s:entry too old\n", __func__); + + if (stop - ev <= IW_EV_ADDR_LEN) { + ret = -E2BIG; + goto out; + } + } + + wrqu->data.length = ev - extra; + wrqu->data.flags = 0; +out: + up(&wl->scan_lock); + pr_debug("%s: -> %d %d\n", __func__, ret, wrqu->data.length); + return ret; +} + +#ifdef DEBUG +static void scan_list_dump(struct gelic_wl_info *wl) +{ + struct gelic_wl_scan_info *scan_info; + int i; + DECLARE_MAC_BUF(mac); + + i = 0; + list_for_each_entry(scan_info, &wl->network_list, list) { + pr_debug("%s: item %d\n", __func__, i++); + pr_debug("valid=%d eurusindex=%d last=%lx\n", + scan_info->valid, scan_info->eurus_index, + scan_info->last_scanned); + pr_debug("r_len=%d r_ext_len=%d essid_len=%d\n", + scan_info->rate_len, scan_info->rate_ext_len, + scan_info->essid_len); + /* -- */ + pr_debug("bssid=%s\n", + print_mac(mac, &scan_info->hwinfo->bssid[2])); + pr_debug("essid=%s\n", scan_info->hwinfo->essid); + } +} +#endif + +static int gelic_wl_set_auth(struct net_device *netdev, + struct iw_request_info *info, + union iwreq_data *data, char *extra) +{ + struct iw_param *param = &data->param; + struct gelic_wl_info *wl = port_wl(netdev_port(netdev)); + unsigned long irqflag; + int ret = 0; + + pr_debug("%s: <- %d\n", __func__, param->flags & IW_AUTH_INDEX); + spin_lock_irqsave(&wl->lock, irqflag); + switch (param->flags & IW_AUTH_INDEX) { + case IW_AUTH_WPA_VERSION: + if (param->value & IW_AUTH_WPA_VERSION_DISABLED) { + pr_debug("%s: NO WPA selected\n", __func__); + wl->wpa_level = GELIC_WL_WPA_LEVEL_NONE; + wl->group_cipher_method = GELIC_WL_CIPHER_WEP; + wl->pairwise_cipher_method = GELIC_WL_CIPHER_WEP; + } + if (param->value & IW_AUTH_WPA_VERSION_WPA) { + pr_debug("%s: WPA version 1 selected\n", __func__); + wl->wpa_level = GELIC_WL_WPA_LEVEL_WPA; + wl->group_cipher_method = GELIC_WL_CIPHER_TKIP; + wl->pairwise_cipher_method = GELIC_WL_CIPHER_TKIP; + wl->auth_method = GELIC_EURUS_AUTH_OPEN; + } + if (param->value & IW_AUTH_WPA_VERSION_WPA2) { + /* + * As the hypervisor may not tell the cipher + * information of the AP if it is WPA2, + * you will not decide suitable cipher from + * its beacon. + * You should have knowledge about the AP's + * cipher infomation in other method prior to + * the association. + */ + if (!precise_ie()) + pr_info("%s: WPA2 may not work\n", __func__); + if (wpa2_capable()) { + wl->wpa_level = GELIC_WL_WPA_LEVEL_WPA2; + wl->group_cipher_method = GELIC_WL_CIPHER_AES; + wl->pairwise_cipher_method = + GELIC_WL_CIPHER_AES; + wl->auth_method = GELIC_EURUS_AUTH_OPEN; + } else + ret = -EINVAL; + } + break; + + case IW_AUTH_CIPHER_PAIRWISE: + if (param->value & + (IW_AUTH_CIPHER_WEP104 | IW_AUTH_CIPHER_WEP40)) { + pr_debug("%s: WEP selected\n", __func__); + wl->pairwise_cipher_method = GELIC_WL_CIPHER_WEP; + } + if (param->value & IW_AUTH_CIPHER_TKIP) { + pr_debug("%s: TKIP selected\n", __func__); + wl->pairwise_cipher_method = GELIC_WL_CIPHER_TKIP; + } + if (param->value & IW_AUTH_CIPHER_CCMP) { + pr_debug("%s: CCMP selected\n", __func__); + wl->pairwise_cipher_method = GELIC_WL_CIPHER_AES; + } + if (param->value & IW_AUTH_CIPHER_NONE) { + pr_debug("%s: no auth selected\n", __func__); + wl->pairwise_cipher_method = GELIC_WL_CIPHER_NONE; + } + break; + case IW_AUTH_CIPHER_GROUP: + if (param->value & + (IW_AUTH_CIPHER_WEP104 | IW_AUTH_CIPHER_WEP40)) { + pr_debug("%s: WEP selected\n", __func__); + wl->group_cipher_method = GELIC_WL_CIPHER_WEP; + } + if (param->value & IW_AUTH_CIPHER_TKIP) { + pr_debug("%s: TKIP selected\n", __func__); + wl->group_cipher_method = GELIC_WL_CIPHER_TKIP; + } + if (param->value & IW_AUTH_CIPHER_CCMP) { + pr_debug("%s: CCMP selected\n", __func__); + wl->group_cipher_method = GELIC_WL_CIPHER_AES; + } + if (param->value & IW_AUTH_CIPHER_NONE) { + pr_debug("%s: no auth selected\n", __func__); + wl->group_cipher_method = GELIC_WL_CIPHER_NONE; + } + break; + case IW_AUTH_80211_AUTH_ALG: + if (param->value & IW_AUTH_ALG_SHARED_KEY) { + pr_debug("%s: shared key specified\n", __func__); + wl->auth_method = GELIC_EURUS_AUTH_SHARED; + } else if (param->value & IW_AUTH_ALG_OPEN_SYSTEM) { + pr_debug("%s: open system specified\n", __func__); + wl->auth_method = GELIC_EURUS_AUTH_OPEN; + } else + ret = -EINVAL; + break; + + case IW_AUTH_WPA_ENABLED: + if (param->value) { + pr_debug("%s: WPA enabled\n", __func__); + wl->wpa_level = GELIC_WL_WPA_LEVEL_WPA; + } else { + pr_debug("%s: WPA disabled\n", __func__); + wl->wpa_level = GELIC_WL_WPA_LEVEL_NONE; + } + break; + + case IW_AUTH_KEY_MGMT: + if (param->value & IW_AUTH_KEY_MGMT_PSK) + break; + /* intentionally fall through */ + default: + ret = -EOPNOTSUPP; + break; + }; + + if (!ret) + set_bit(GELIC_WL_STAT_CONFIGURED, &wl->stat); + + spin_unlock_irqrestore(&wl->lock, irqflag); + pr_debug("%s: -> %d\n", __func__, ret); + return ret; +} + +static int gelic_wl_get_auth(struct net_device *netdev, + struct iw_request_info *info, + union iwreq_data *iwreq, char *extra) +{ + struct iw_param *param = &iwreq->param; + struct gelic_wl_info *wl = port_wl(netdev_port(netdev)); + unsigned long irqflag; + int ret = 0; + + pr_debug("%s: <- %d\n", __func__, param->flags & IW_AUTH_INDEX); + spin_lock_irqsave(&wl->lock, irqflag); + switch (param->flags & IW_AUTH_INDEX) { + case IW_AUTH_WPA_VERSION: + switch (wl->wpa_level) { + case GELIC_WL_WPA_LEVEL_WPA: + param->value |= IW_AUTH_WPA_VERSION_WPA; + break; + case GELIC_WL_WPA_LEVEL_WPA2: + param->value |= IW_AUTH_WPA_VERSION_WPA2; + break; + default: + param->value |= IW_AUTH_WPA_VERSION_DISABLED; + } + break; + + case IW_AUTH_80211_AUTH_ALG: + if (wl->auth_method == GELIC_EURUS_AUTH_SHARED) + param->value = IW_AUTH_ALG_SHARED_KEY; + else if (wl->auth_method == GELIC_EURUS_AUTH_OPEN) + param->value = IW_AUTH_ALG_OPEN_SYSTEM; + break; + + case IW_AUTH_WPA_ENABLED: + switch (wl->wpa_level) { + case GELIC_WL_WPA_LEVEL_WPA: + case GELIC_WL_WPA_LEVEL_WPA2: + param->value = 1; + break; + default: + param->value = 0; + break; + } + break; + default: + ret = -EOPNOTSUPP; + } + + spin_unlock_irqrestore(&wl->lock, irqflag); + pr_debug("%s: -> %d\n", __func__, ret); + return ret; +} + +/* SIOC{S,G}IWESSID */ +static int gelic_wl_set_essid(struct net_device *netdev, + struct iw_request_info *info, + union iwreq_data *data, char *extra) +{ + struct gelic_wl_info *wl = port_wl(netdev_priv(netdev)); + unsigned long irqflag; + + pr_debug("%s: <- l=%d f=%d\n", __func__, + data->essid.length, data->essid.flags); + if (IW_ESSID_MAX_SIZE < data->essid.length) + return -EINVAL; + + spin_lock_irqsave(&wl->lock, irqflag); + if (data->essid.flags) { + wl->essid_len = data->essid.length; + memcpy(wl->essid, extra, wl->essid_len); + pr_debug("%s: essid = '%s'\n", __func__, extra); + set_bit(GELIC_WL_STAT_ESSID_SET, &wl->stat); + } else { + pr_debug("%s: ESSID any \n", __func__); + clear_bit(GELIC_WL_STAT_ESSID_SET, &wl->stat); + } + set_bit(GELIC_WL_STAT_CONFIGURED, &wl->stat); + spin_unlock_irqrestore(&wl->lock, irqflag); + + + gelic_wl_try_associate(netdev); /* FIXME */ + pr_debug("%s: -> \n", __func__); + return 0; +} + +static int gelic_wl_get_essid(struct net_device *netdev, + struct iw_request_info *info, + union iwreq_data *data, char *extra) +{ + struct gelic_wl_info *wl = port_wl(netdev_priv(netdev)); + unsigned long irqflag; + + pr_debug("%s: <- \n", __func__); + down(&wl->assoc_stat_lock); + spin_lock_irqsave(&wl->lock, irqflag); + if (test_bit(GELIC_WL_STAT_ESSID_SET, &wl->stat) || + wl->assoc_stat == GELIC_WL_ASSOC_STAT_ASSOCIATED) { + memcpy(extra, wl->essid, wl->essid_len); + data->essid.length = wl->essid_len; + data->essid.flags = 1; + } else + data->essid.flags = 0; + + up(&wl->assoc_stat_lock); + spin_unlock_irqrestore(&wl->lock, irqflag); + pr_debug("%s: -> len=%d \n", __func__, data->essid.length); + + return 0; +} + +/* SIO{S,G}IWENCODE */ +static int gelic_wl_set_encode(struct net_device *netdev, + struct iw_request_info *info, + union iwreq_data *data, char *extra) +{ + struct gelic_wl_info *wl = port_wl(netdev_priv(netdev)); + struct iw_point *enc = &data->encoding; + __u16 flags; + unsigned int irqflag; + int key_index, index_specified; + int ret = 0; + + pr_debug("%s: <- \n", __func__); + flags = enc->flags & IW_ENCODE_FLAGS; + key_index = enc->flags & IW_ENCODE_INDEX; + + pr_debug("%s: key_index = %d\n", __func__, key_index); + pr_debug("%s: key_len = %d\n", __func__, enc->length); + pr_debug("%s: flag=%x\n", __func__, enc->flags & IW_ENCODE_FLAGS); + + if (GELIC_WEP_KEYS < key_index) + return -EINVAL; + + spin_lock_irqsave(&wl->lock, irqflag); + if (key_index) { + index_specified = 1; + key_index--; + } else { + index_specified = 0; + key_index = wl->current_key; + } + + if (flags & IW_ENCODE_NOKEY) { + /* if just IW_ENCODE_NOKEY, change current key index */ + if (!flags && index_specified) { + wl->current_key = key_index; + goto done; + } + + if (flags & IW_ENCODE_DISABLED) { + if (!index_specified) { + /* disable encryption */ + wl->group_cipher_method = GELIC_WL_CIPHER_NONE; + wl->pairwise_cipher_method = + GELIC_WL_CIPHER_NONE; + /* invalidate all key */ + wl->key_enabled = 0; + } else + clear_bit(key_index, &wl->key_enabled); + } + + if (flags & IW_ENCODE_OPEN) + wl->auth_method = GELIC_EURUS_AUTH_OPEN; + if (flags & IW_ENCODE_RESTRICTED) { + pr_info("%s: shared key mode enabled\n", __func__); + wl->auth_method = GELIC_EURUS_AUTH_SHARED; + } + } else { + if (IW_ENCODING_TOKEN_MAX < enc->length) { + ret = -EINVAL; + goto done; + } + wl->key_len[key_index] = enc->length; + memcpy(wl->key[key_index], extra, enc->length); + set_bit(key_index, &wl->key_enabled); + wl->pairwise_cipher_method = GELIC_WL_CIPHER_WEP; + wl->group_cipher_method = GELIC_WL_CIPHER_WEP; + } + set_bit(GELIC_WL_STAT_CONFIGURED, &wl->stat); +done: + spin_unlock_irqrestore(&wl->lock, irqflag); + pr_debug("%s: -> \n", __func__); + return ret; +} + +static int gelic_wl_get_encode(struct net_device *netdev, + struct iw_request_info *info, + union iwreq_data *data, char *extra) +{ + struct gelic_wl_info *wl = port_wl(netdev_priv(netdev)); + struct iw_point *enc = &data->encoding; + unsigned int irqflag; + unsigned int key_index, index_specified; + int ret = 0; + + pr_debug("%s: <- \n", __func__); + key_index = enc->flags & IW_ENCODE_INDEX; + pr_debug("%s: flag=%#x point=%p len=%d extra=%p\n", __func__, + enc->flags, enc->pointer, enc->length, extra); + if (GELIC_WEP_KEYS < key_index) + return -EINVAL; + + spin_lock_irqsave(&wl->lock, irqflag); + if (key_index) { + index_specified = 1; + key_index--; + } else { + index_specified = 0; + key_index = wl->current_key; + } + + if (wl->group_cipher_method == GELIC_WL_CIPHER_WEP) { + switch (wl->auth_method) { + case GELIC_EURUS_AUTH_OPEN: + enc->flags = IW_ENCODE_OPEN; + break; + case GELIC_EURUS_AUTH_SHARED: + enc->flags = IW_ENCODE_RESTRICTED; + break; + } + } else + enc->flags = IW_ENCODE_DISABLED; + + if (test_bit(key_index, &wl->key_enabled)) { + if (enc->length < wl->key_len[key_index]) { + ret = -EINVAL; + goto done; + } + enc->length = wl->key_len[key_index]; + memcpy(extra, wl->key[key_index], wl->key_len[key_index]); + } else { + enc->length = 0; + enc->flags |= IW_ENCODE_NOKEY; + } + enc->flags |= key_index + 1; + pr_debug("%s: -> flag=%x len=%d\n", __func__, + enc->flags, enc->length); + +done: + spin_unlock_irqrestore(&wl->lock, irqflag); + return ret; +} + +/* SIOC{S,G}IWAP */ +static int gelic_wl_set_ap(struct net_device *netdev, + struct iw_request_info *info, + union iwreq_data *data, char *extra) +{ + struct gelic_wl_info *wl = port_wl(netdev_priv(netdev)); + unsigned long irqflag; + + pr_debug("%s: <-\n", __func__); + if (data->ap_addr.sa_family != ARPHRD_ETHER) + return -EINVAL; + + spin_lock_irqsave(&wl->lock, irqflag); + if (is_valid_ether_addr(data->ap_addr.sa_data)) { + memcpy(wl->bssid, data->ap_addr.sa_data, + ETH_ALEN); + set_bit(GELIC_WL_STAT_BSSID_SET, &wl->stat); + set_bit(GELIC_WL_STAT_CONFIGURED, &wl->stat); + pr_debug("%s: bss=%02x:%02x:%02x:%02x:%02x:%02x\n", + __func__, + wl->bssid[0], wl->bssid[1], + wl->bssid[2], wl->bssid[3], + wl->bssid[4], wl->bssid[5]); + } else { + pr_debug("%s: clear bssid\n", __func__); + clear_bit(GELIC_WL_STAT_BSSID_SET, &wl->stat); + memset(wl->bssid, 0, ETH_ALEN); + } + spin_unlock_irqrestore(&wl->lock, irqflag); + pr_debug("%s: ->\n", __func__); + return 0; +} + +static int gelic_wl_get_ap(struct net_device *netdev, + struct iw_request_info *info, + union iwreq_data *data, char *extra) +{ + struct gelic_wl_info *wl = port_wl(netdev_priv(netdev)); + unsigned long irqflag; + + pr_debug("%s: <-\n", __func__); + down(&wl->assoc_stat_lock); + spin_lock_irqsave(&wl->lock, irqflag); + if (wl->assoc_stat == GELIC_WL_ASSOC_STAT_ASSOCIATED) { + data->ap_addr.sa_family = ARPHRD_ETHER; + memcpy(data->ap_addr.sa_data, wl->active_bssid, + ETH_ALEN); + } else + memset(data->ap_addr.sa_data, 0, ETH_ALEN); + + spin_unlock_irqrestore(&wl->lock, irqflag); + up(&wl->assoc_stat_lock); + pr_debug("%s: ->\n", __func__); + return 0; +} + +/* SIOC{S,G}IWENCODEEXT */ +static int gelic_wl_set_encodeext(struct net_device *netdev, + struct iw_request_info *info, + union iwreq_data *data, char *extra) +{ + struct gelic_wl_info *wl = port_wl(netdev_priv(netdev)); + struct iw_point *enc = &data->encoding; + struct iw_encode_ext *ext = (struct iw_encode_ext *)extra; + __u16 alg; + __u16 flags; + unsigned int irqflag; + int key_index; + int ret = 0; + + pr_debug("%s: <- \n", __func__); + flags = enc->flags & IW_ENCODE_FLAGS; + alg = ext->alg; + key_index = enc->flags & IW_ENCODE_INDEX; + + pr_debug("%s: key_index = %d\n", __func__, key_index); + pr_debug("%s: key_len = %d\n", __func__, enc->length); + pr_debug("%s: flag=%x\n", __func__, enc->flags & IW_ENCODE_FLAGS); + pr_debug("%s: ext_flag=%x\n", __func__, ext->ext_flags); + pr_debug("%s: ext_key_len=%x\n", __func__, ext->key_len); + + if (GELIC_WEP_KEYS < key_index) + return -EINVAL; + + spin_lock_irqsave(&wl->lock, irqflag); + if (key_index) + key_index--; + else + key_index = wl->current_key; + + if (!enc->length && (ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY)) { + /* reques to change default key index */ + pr_debug("%s: request to change default key to %d\n", + __func__, key_index); + wl->current_key = key_index; + goto done; + } + + if (alg == IW_ENCODE_ALG_NONE || (flags & IW_ENCODE_DISABLED)) { + pr_debug("%s: alg disabled\n", __func__); + wl->wpa_level = GELIC_WL_WPA_LEVEL_NONE; + wl->group_cipher_method = GELIC_WL_CIPHER_NONE; + wl->pairwise_cipher_method = GELIC_WL_CIPHER_NONE; + wl->auth_method = GELIC_EURUS_AUTH_OPEN; /* should be open */ + } else if (alg == IW_ENCODE_ALG_WEP) { + pr_debug("%s: WEP requested\n", __func__); + if (flags & IW_ENCODE_OPEN) { + pr_debug("%s: open key mode\n", __func__); + wl->auth_method = GELIC_EURUS_AUTH_OPEN; + } + if (flags & IW_ENCODE_RESTRICTED) { + pr_debug("%s: shared key mode\n", __func__); + wl->auth_method = GELIC_EURUS_AUTH_SHARED; + } + if (IW_ENCODING_TOKEN_MAX < ext->key_len) { + pr_info("%s: key is too long %d\n", __func__, + ext->key_len); + ret = -EINVAL; + goto done; + } + /* OK, update the key */ + wl->key_len[key_index] = ext->key_len; + memset(wl->key[key_index], 0, IW_ENCODING_TOKEN_MAX); + memcpy(wl->key[key_index], ext->key, ext->key_len); + set_bit(key_index, &wl->key_enabled); + /* remember wep info changed */ + set_bit(GELIC_WL_STAT_CONFIGURED, &wl->stat); + } else if ((alg == IW_ENCODE_ALG_TKIP) || (alg == IW_ENCODE_ALG_CCMP)) { + pr_debug("%s: TKIP/CCMP requested alg=%d\n", __func__, alg); + /* check key length */ + if (IW_ENCODING_TOKEN_MAX < ext->key_len) { + pr_info("%s: key is too long %d\n", __func__, + ext->key_len); + ret = -EINVAL; + goto done; + } + if (alg == IW_ENCODE_ALG_CCMP) { + pr_debug("%s: AES selected\n", __func__); + wl->group_cipher_method = GELIC_WL_CIPHER_AES; + wl->pairwise_cipher_method = GELIC_WL_CIPHER_AES; + wl->wpa_level = GELIC_WL_WPA_LEVEL_WPA2; + } else { + pr_debug("%s: TKIP selected, WPA forced\n", __func__); + wl->group_cipher_method = GELIC_WL_CIPHER_TKIP; + wl->pairwise_cipher_method = GELIC_WL_CIPHER_TKIP; + /* FIXME: how do we do if WPA2 + TKIP? */ + wl->wpa_level = GELIC_WL_WPA_LEVEL_WPA; + } + if (flags & IW_ENCODE_RESTRICTED) + BUG(); + wl->auth_method = GELIC_EURUS_AUTH_OPEN; + /* We should use same key for both and unicast */ + if (ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY) + pr_debug("%s: group key \n", __func__); + else + pr_debug("%s: unicast key \n", __func__); + /* OK, update the key */ + wl->key_len[key_index] = ext->key_len; + memset(wl->key[key_index], 0, IW_ENCODING_TOKEN_MAX); + memcpy(wl->key[key_index], ext->key, ext->key_len); + set_bit(key_index, &wl->key_enabled); + /* remember info changed */ + set_bit(GELIC_WL_STAT_CONFIGURED, &wl->stat); + } +done: + spin_unlock_irqrestore(&wl->lock, irqflag); + pr_debug("%s: -> \n", __func__); + return ret; +} + +static int gelic_wl_get_encodeext(struct net_device *netdev, + struct iw_request_info *info, + union iwreq_data *data, char *extra) +{ + struct gelic_wl_info *wl = port_wl(netdev_priv(netdev)); + struct iw_point *enc = &data->encoding; + struct iw_encode_ext *ext = (struct iw_encode_ext *)extra; + unsigned int irqflag; + int key_index; + int ret = 0; + int max_key_len; + + pr_debug("%s: <- \n", __func__); + + max_key_len = enc->length - sizeof(struct iw_encode_ext); + if (max_key_len < 0) + return -EINVAL; + key_index = enc->flags & IW_ENCODE_INDEX; + + pr_debug("%s: key_index = %d\n", __func__, key_index); + pr_debug("%s: key_len = %d\n", __func__, enc->length); + pr_debug("%s: flag=%x\n", __func__, enc->flags & IW_ENCODE_FLAGS); + + if (GELIC_WEP_KEYS < key_index) + return -EINVAL; + + spin_lock_irqsave(&wl->lock, irqflag); + if (key_index) + key_index--; + else + key_index = wl->current_key; + + memset(ext, 0, sizeof(struct iw_encode_ext)); + switch (wl->group_cipher_method) { + case GELIC_WL_CIPHER_WEP: + ext->alg = IW_ENCODE_ALG_WEP; + enc->flags |= IW_ENCODE_ENABLED; + break; + case GELIC_WL_CIPHER_TKIP: + ext->alg = IW_ENCODE_ALG_TKIP; + enc->flags |= IW_ENCODE_ENABLED; + break; + case GELIC_WL_CIPHER_AES: + ext->alg = IW_ENCODE_ALG_CCMP; + enc->flags |= IW_ENCODE_ENABLED; + break; + case GELIC_WL_CIPHER_NONE: + default: + ext->alg = IW_ENCODE_ALG_NONE; + enc->flags |= IW_ENCODE_NOKEY; + break; + } + + if (!(enc->flags & IW_ENCODE_NOKEY)) { + if (max_key_len < wl->key_len[key_index]) { + ret = -E2BIG; + goto out; + } + if (test_bit(key_index, &wl->key_enabled)) + memcpy(ext->key, wl->key[key_index], + wl->key_len[key_index]); + else + pr_debug("%s: disabled key requested ix=%d\n", + __func__, key_index); + } +out: + spin_unlock_irqrestore(&wl->lock, irqflag); + pr_debug("%s: -> \n", __func__); + return ret; +} +/* SIOC{S,G}IWMODE */ +static int gelic_wl_set_mode(struct net_device *netdev, + struct iw_request_info *info, + union iwreq_data *data, char *extra) +{ + __u32 mode = data->mode; + int ret; + + pr_debug("%s: <- \n", __func__); + if (mode == IW_MODE_INFRA) + ret = 0; + else + ret = -EOPNOTSUPP; + pr_debug("%s: -> %d\n", __func__, ret); + return ret; +} + +static int gelic_wl_get_mode(struct net_device *netdev, + struct iw_request_info *info, + union iwreq_data *data, char *extra) +{ + __u32 *mode = &data->mode; + pr_debug("%s: <- \n", __func__); + *mode = IW_MODE_INFRA; + pr_debug("%s: ->\n", __func__); + return 0; +} + +/* SIOCIWFIRSTPRIV */ +static int hex2bin(u8 *str, u8 *bin, unsigned int len) +{ + unsigned int i; + static unsigned char *hex = "0123456789ABCDEF"; + unsigned char *p, *q; + u8 tmp; + + if (len != WPA_PSK_LEN * 2) + return -EINVAL; + + for (i = 0; i < WPA_PSK_LEN * 2; i += 2) { + p = strchr(hex, toupper(str[i])); + q = strchr(hex, toupper(str[i + 1])); + if (!p || !q) { + pr_info("%s: unconvertible PSK digit=%d\n", + __func__, i); + return -EINVAL; + } + tmp = ((p - hex) << 4) + (q - hex); + *bin++ = tmp; + } + return 0; +}; + +static int gelic_wl_priv_set_psk(struct net_device *net_dev, + struct iw_request_info *info, + union iwreq_data *data, char *extra) +{ + struct gelic_wl_info *wl = port_wl(netdev_priv(net_dev)); + unsigned int len; + unsigned int irqflag; + int ret = 0; + + pr_debug("%s:<- len=%d\n", __func__, data->data.length); + len = data->data.length - 1; + if (len <= 2) + return -EINVAL; + + spin_lock_irqsave(&wl->lock, irqflag); + if (extra[0] == '"' && extra[len - 1] == '"') { + pr_debug("%s: passphrase mode\n", __func__); + /* pass phrase */ + if (GELIC_WL_EURUS_PSK_MAX_LEN < (len - 2)) { + pr_info("%s: passphrase too long\n", __func__); + ret = -E2BIG; + goto out; + } + memset(wl->psk, 0, sizeof(wl->psk)); + wl->psk_len = len - 2; + memcpy(wl->psk, &(extra[1]), wl->psk_len); + wl->psk_type = GELIC_EURUS_WPA_PSK_PASSPHRASE; + } else { + ret = hex2bin(extra, wl->psk, len); + if (ret) + goto out; + wl->psk_len = WPA_PSK_LEN; + wl->psk_type = GELIC_EURUS_WPA_PSK_BIN; + } + set_bit(GELIC_WL_STAT_WPA_PSK_SET, &wl->stat); +out: + spin_unlock_irqrestore(&wl->lock, irqflag); + pr_debug("%s:->\n", __func__); + return ret; +} + +static int gelic_wl_priv_get_psk(struct net_device *net_dev, + struct iw_request_info *info, + union iwreq_data *data, char *extra) +{ + struct gelic_wl_info *wl = port_wl(netdev_priv(net_dev)); + char *p; + unsigned int irqflag; + unsigned int i; + + pr_debug("%s:<-\n", __func__); + if (!capable(CAP_NET_ADMIN)) + return -EPERM; + + spin_lock_irqsave(&wl->lock, irqflag); + p = extra; + if (test_bit(GELIC_WL_STAT_WPA_PSK_SET, &wl->stat)) { + if (wl->psk_type == GELIC_EURUS_WPA_PSK_BIN) { + for (i = 0; i < wl->psk_len; i++) { + sprintf(p, "%02xu", wl->psk[i]); + p += 2; + } + *p = '\0'; + data->data.length = wl->psk_len * 2; + } else { + *p++ = '"'; + memcpy(p, wl->psk, wl->psk_len); + p += wl->psk_len; + *p++ = '"'; + *p = '\0'; + data->data.length = wl->psk_len + 2; + } + } else + /* no psk set */ + data->data.length = 0; + spin_unlock_irqrestore(&wl->lock, irqflag); + pr_debug("%s:-> %d\n", __func__, data->data.length); + return 0; +} + +/* SIOCGIWNICKN */ +static int gelic_wl_get_nick(struct net_device *net_dev, + struct iw_request_info *info, + union iwreq_data *data, char *extra) +{ + strcpy(extra, "gelic_wl"); + data->data.length = strlen(extra); + data->data.flags = 1; + return 0; +} + + +/* --- */ + +static struct iw_statistics *gelic_wl_get_wireless_stats( + struct net_device *netdev) +{ + + struct gelic_wl_info *wl = port_wl(netdev_priv(netdev)); + struct gelic_eurus_cmd *cmd; + struct iw_statistics *is; + struct gelic_eurus_rssi_info *rssi; + + pr_debug("%s: <-\n", __func__); + + is = &wl->iwstat; + memset(is, 0, sizeof(*is)); + cmd = gelic_eurus_sync_cmd(wl, GELIC_EURUS_CMD_GET_RSSI_CFG, + wl->buf, sizeof(*rssi)); + if (cmd && !cmd->status && !cmd->cmd_status) { + rssi = wl->buf; + is->qual.level = be16_to_cpu(rssi->rssi); + is->qual.updated = IW_QUAL_LEVEL_UPDATED | + IW_QUAL_QUAL_INVALID | IW_QUAL_NOISE_INVALID; + } else + /* not associated */ + is->qual.updated = IW_QUAL_ALL_INVALID; + + kfree(cmd); + pr_debug("%s: ->\n", __func__); + return is; +} + +/* + * scanning helpers + */ +static int gelic_wl_start_scan(struct gelic_wl_info *wl, int always_scan) +{ + struct gelic_eurus_cmd *cmd; + int ret = 0; + + pr_debug("%s: <- always=%d\n", __func__, always_scan); + if (down_interruptible(&wl->scan_lock)) + return -ERESTARTSYS; + + /* + * If already a scan in progress, do not trigger more + */ + if (wl->scan_stat == GELIC_WL_SCAN_STAT_SCANNING) { + pr_debug("%s: scanning now\n", __func__); + goto out; + } + + init_completion(&wl->scan_done); + /* + * If we have already a bss list, don't try to get new + */ + if (!always_scan && wl->scan_stat == GELIC_WL_SCAN_STAT_GOT_LIST) { + pr_debug("%s: already has the list\n", __func__); + complete(&wl->scan_done); + goto out; + } + /* + * issue start scan request + */ + wl->scan_stat = GELIC_WL_SCAN_STAT_SCANNING; + cmd = gelic_eurus_sync_cmd(wl, GELIC_EURUS_CMD_START_SCAN, + NULL, 0); + if (!cmd || cmd->status || cmd->cmd_status) { + wl->scan_stat = GELIC_WL_SCAN_STAT_INIT; + complete(&wl->scan_done); + ret = -ENOMEM; + goto out; + } + kfree(cmd); +out: + up(&wl->scan_lock); + pr_debug("%s: ->\n", __func__); + return ret; +} + +/* + * retrieve scan result from the chip (hypervisor) + * this function is invoked by schedule work. + */ +static void gelic_wl_scan_complete_event(struct gelic_wl_info *wl) +{ + struct gelic_eurus_cmd *cmd = NULL; + struct gelic_wl_scan_info *target, *tmp; + struct gelic_wl_scan_info *oldest = NULL; + struct gelic_eurus_scan_info *scan_info; + unsigned int scan_info_size; + union iwreq_data data; + unsigned long this_time = jiffies; + unsigned int data_len, i, found, r; + DECLARE_MAC_BUF(mac); + + pr_debug("%s:start\n", __func__); + down(&wl->scan_lock); + + if (wl->scan_stat != GELIC_WL_SCAN_STAT_SCANNING) { + /* + * stop() may be called while scanning, ignore result + */ + pr_debug("%s: scan complete when stat != scanning(%d)\n", + __func__, wl->scan_stat); + goto out; + } + + cmd = gelic_eurus_sync_cmd(wl, GELIC_EURUS_CMD_GET_SCAN, + wl->buf, PAGE_SIZE); + if (!cmd || cmd->status || cmd->cmd_status) { + wl->scan_stat = GELIC_WL_SCAN_STAT_INIT; + pr_info("%s:cmd failed\n", __func__); + kfree(cmd); + goto out; + } + data_len = cmd->size; + pr_debug("%s: data_len = %d\n", __func__, data_len); + kfree(cmd); + + /* OK, bss list retrieved */ + wl->scan_stat = GELIC_WL_SCAN_STAT_GOT_LIST; + + /* mark all entries are old */ + list_for_each_entry_safe(target, tmp, &wl->network_list, list) { + target->valid = 0; + /* expire too old entries */ + if (time_before(target->last_scanned + wl->scan_age, + this_time)) { + kfree(target->hwinfo); + target->hwinfo = NULL; + list_move_tail(&target->list, &wl->network_free_list); + } + } + + /* put them in the newtork_list */ + scan_info = wl->buf; + scan_info_size = 0; + i = 0; + while (scan_info_size < data_len) { + pr_debug("%s:size=%d bssid=%s scan_info=%p\n", __func__, + be16_to_cpu(scan_info->size), + print_mac(mac, &scan_info->bssid[2]), scan_info); + found = 0; + oldest = NULL; + list_for_each_entry(target, &wl->network_list, list) { + if (!compare_ether_addr(&target->hwinfo->bssid[2], + &scan_info->bssid[2])) { + found = 1; + pr_debug("%s: same BBS found scanned list\n", + __func__); + break; + } + if (!oldest || + (target->last_scanned < oldest->last_scanned)) + oldest = target; + } + + if (!found) { + /* not found in the list */ + if (list_empty(&wl->network_free_list)) { + /* expire oldest */ + target = oldest; + } else { + target = list_entry(wl->network_free_list.next, + struct gelic_wl_scan_info, + list); + } + } + + /* update the item */ + target->last_scanned = this_time; + target->valid = 1; + target->eurus_index = i; + kfree(target->hwinfo); + target->hwinfo = kzalloc(be16_to_cpu(scan_info->size), + GFP_KERNEL); + if (!target->hwinfo) { + pr_info("%s: kzalloc failed\n", __func__); + i++; + scan_info_size += be16_to_cpu(scan_info->size); + scan_info = (void *)scan_info + + be16_to_cpu(scan_info->size); + continue; + } + /* copy hw scan info */ + memcpy(target->hwinfo, scan_info, scan_info->size); + target->essid_len = strnlen(scan_info->essid, + sizeof(scan_info->essid)); + target->rate_len = 0; + for (r = 0; r < MAX_RATES_LENGTH; r++) + if (scan_info->rate[r]) + target->rate_len++; + if (8 < target->rate_len) + pr_info("%s: AP returns %d rates\n", __func__, + target->rate_len); + target->rate_ext_len = 0; + for (r = 0; r < MAX_RATES_EX_LENGTH; r++) + if (scan_info->ext_rate[r]) + target->rate_ext_len++; + list_move_tail(&target->list, &wl->network_list); + /* bump pointer */ + i++; + scan_info_size += be16_to_cpu(scan_info->size); + scan_info = (void *)scan_info + be16_to_cpu(scan_info->size); + } + memset(&data, 0, sizeof(data)); + wireless_send_event(port_to_netdev(wl_port(wl)), SIOCGIWSCAN, &data, + NULL); +out: + complete(&wl->scan_done); + up(&wl->scan_lock); + pr_debug("%s:end\n", __func__); +} + +/* + * Select an appropriate bss from current scan list regarding + * current settings from userspace. + * The caller must hold wl->scan_lock, + * and on the state of wl->scan_state == GELIC_WL_SCAN_GOT_LIST + */ +static void update_best(struct gelic_wl_scan_info **best, + struct gelic_wl_scan_info *candid, + int *best_weight, + int *weight) +{ + if (*best_weight < ++(*weight)) { + *best_weight = *weight; + *best = candid; + } +} + +static +struct gelic_wl_scan_info *gelic_wl_find_best_bss(struct gelic_wl_info *wl) +{ + struct gelic_wl_scan_info *scan_info; + struct gelic_wl_scan_info *best_bss; + int weight, best_weight; + u16 security; + DECLARE_MAC_BUF(mac); + + pr_debug("%s: <-\n", __func__); + + best_bss = NULL; + best_weight = 0; + + list_for_each_entry(scan_info, &wl->network_list, list) { + pr_debug("%s: station %p\n", __func__, scan_info); + + if (!scan_info->valid) { + pr_debug("%s: station invalid\n", __func__); + continue; + } + + /* If bss specified, check it only */ + if (test_bit(GELIC_WL_STAT_BSSID_SET, &wl->stat)) { + if (!compare_ether_addr(&scan_info->hwinfo->bssid[2], + wl->bssid)) { + best_bss = scan_info; + pr_debug("%s: bssid matched\n", __func__); + break; + } else { + pr_debug("%s: bssid unmached\n", __func__); + continue; + } + } + + weight = 0; + + /* security */ + security = be16_to_cpu(scan_info->hwinfo->security) & + GELIC_EURUS_SCAN_SEC_MASK; + if (wl->wpa_level == GELIC_WL_WPA_LEVEL_WPA2) { + if (security == GELIC_EURUS_SCAN_SEC_WPA2) + update_best(&best_bss, scan_info, + &best_weight, &weight); + else + continue; + } else if (wl->wpa_level == GELIC_WL_WPA_LEVEL_WPA) { + if (security == GELIC_EURUS_SCAN_SEC_WPA) + update_best(&best_bss, scan_info, + &best_weight, &weight); + else + continue; + } else if (wl->wpa_level == GELIC_WL_WPA_LEVEL_NONE && + wl->group_cipher_method == GELIC_WL_CIPHER_WEP) { + if (security == GELIC_EURUS_SCAN_SEC_WEP) + update_best(&best_bss, scan_info, + &best_weight, &weight); + else + continue; + } + + /* If ESSID is set, check it */ + if (test_bit(GELIC_WL_STAT_ESSID_SET, &wl->stat)) { + if ((scan_info->essid_len == wl->essid_len) && + !strncmp(wl->essid, + scan_info->hwinfo->essid, + scan_info->essid_len)) + update_best(&best_bss, scan_info, + &best_weight, &weight); + else + continue; + } + } + +#ifdef DEBUG + pr_debug("%s: -> bss=%p\n", __func__, best_bss); + if (best_bss) { + pr_debug("%s:addr=%s\n", __func__, + print_mac(mac, &best_bss->hwinfo->bssid[2])); + } +#endif + return best_bss; +} + +/* + * Setup WEP configuration to the chip + * The caller must hold wl->scan_lock, + * and on the state of wl->scan_state == GELIC_WL_SCAN_GOT_LIST + */ +static int gelic_wl_do_wep_setup(struct gelic_wl_info *wl) +{ + unsigned int i; + struct gelic_eurus_wep_cfg *wep; + struct gelic_eurus_cmd *cmd; + int wep104 = 0; + int have_key = 0; + int ret = 0; + + pr_debug("%s: <-\n", __func__); + /* we can assume no one should uses the buffer */ + wep = wl->buf; + memset(wep, 0, sizeof(*wep)); + + if (wl->group_cipher_method == GELIC_WL_CIPHER_WEP) { + pr_debug("%s: WEP mode\n", __func__); + for (i = 0; i < GELIC_WEP_KEYS; i++) { + if (!test_bit(i, &wl->key_enabled)) + continue; + + pr_debug("%s: key#%d enabled\n", __func__, i); + have_key = 1; + if (wl->key_len[i] == 13) + wep104 = 1; + else if (wl->key_len[i] != 5) { + pr_info("%s: wrong wep key[%d]=%d\n", + __func__, i, wl->key_len[i]); + ret = -EINVAL; + goto out; + } + memcpy(wep->key[i], wl->key[i], wl->key_len[i]); + } + + if (!have_key) { + pr_info("%s: all wep key disabled\n", __func__); + ret = -EINVAL; + goto out; + } + + if (wep104) { + pr_debug("%s: 104bit key\n", __func__); + wep->security = cpu_to_be16(GELIC_EURUS_WEP_SEC_104BIT); + } else { + pr_debug("%s: 40bit key\n", __func__); + wep->security = cpu_to_be16(GELIC_EURUS_WEP_SEC_40BIT); + } + } else { + pr_debug("%s: NO encryption\n", __func__); + wep->security = cpu_to_be16(GELIC_EURUS_WEP_SEC_NONE); + } + + /* issue wep setup */ + cmd = gelic_eurus_sync_cmd(wl, GELIC_EURUS_CMD_SET_WEP_CFG, + wep, sizeof(*wep)); + if (!cmd) + ret = -ENOMEM; + else if (cmd->status || cmd->cmd_status) + ret = -ENXIO; + + kfree(cmd); +out: + pr_debug("%s: ->\n", __func__); + return ret; +} + +#ifdef DEBUG +static const char *wpasecstr(enum gelic_eurus_wpa_security sec) +{ + switch (sec) { + case GELIC_EURUS_WPA_SEC_NONE: + return "NONE"; + break; + case GELIC_EURUS_WPA_SEC_WPA_TKIP_TKIP: + return "WPA_TKIP_TKIP"; + break; + case GELIC_EURUS_WPA_SEC_WPA_TKIP_AES: + return "WPA_TKIP_AES"; + break; + case GELIC_EURUS_WPA_SEC_WPA_AES_AES: + return "WPA_AES_AES"; + break; + case GELIC_EURUS_WPA_SEC_WPA2_TKIP_TKIP: + return "WPA2_TKIP_TKIP"; + break; + case GELIC_EURUS_WPA_SEC_WPA2_TKIP_AES: + return "WPA2_TKIP_AES"; + break; + case GELIC_EURUS_WPA_SEC_WPA2_AES_AES: + return "WPA2_AES_AES"; + break; + } + return ""; +}; +#endif + +static int gelic_wl_do_wpa_setup(struct gelic_wl_info *wl) +{ + struct gelic_eurus_wpa_cfg *wpa; + struct gelic_eurus_cmd *cmd; + u16 security; + int ret = 0; + + pr_debug("%s: <-\n", __func__); + /* we can assume no one should uses the buffer */ + wpa = wl->buf; + memset(wpa, 0, sizeof(*wpa)); + + if (!test_bit(GELIC_WL_STAT_WPA_PSK_SET, &wl->stat)) + pr_info("%s: PSK not configured yet\n", __func__); + + /* copy key */ + memcpy(wpa->psk, wl->psk, wl->psk_len); + + /* set security level */ + if (wl->wpa_level == GELIC_WL_WPA_LEVEL_WPA2) { + if (wl->group_cipher_method == GELIC_WL_CIPHER_AES) { + security = GELIC_EURUS_WPA_SEC_WPA2_AES_AES; + } else { + if (wl->pairwise_cipher_method == GELIC_WL_CIPHER_AES && + precise_ie()) + security = GELIC_EURUS_WPA_SEC_WPA2_TKIP_AES; + else + security = GELIC_EURUS_WPA_SEC_WPA2_TKIP_TKIP; + } + } else { + if (wl->group_cipher_method == GELIC_WL_CIPHER_AES) { + security = GELIC_EURUS_WPA_SEC_WPA_AES_AES; + } else { + if (wl->pairwise_cipher_method == GELIC_WL_CIPHER_AES && + precise_ie()) + security = GELIC_EURUS_WPA_SEC_WPA_TKIP_AES; + else + security = GELIC_EURUS_WPA_SEC_WPA_TKIP_TKIP; + } + } + wpa->security = cpu_to_be16(security); + + /* PSK type */ + wpa->psk_type = cpu_to_be16(wl->psk_type); +#ifdef DEBUG + pr_debug("%s: sec=%s psktype=%s\nn", __func__, + wpasecstr(wpa->security), + (wpa->psk_type == GELIC_EURUS_WPA_PSK_BIN) ? + "BIN" : "passphrase"); +#if 0 + /* + * don't enable here if you plan to submit + * the debug log because this dumps your precious + * passphrase/key. + */ + pr_debug("%s: psk=%s\n", + (wpa->psk_type == GELIC_EURUS_WPA_PSK_BIN) ? + (char *)"N/A" : (char *)wpa->psk); +#endif +#endif + /* issue wpa setup */ + cmd = gelic_eurus_sync_cmd(wl, GELIC_EURUS_CMD_SET_WPA_CFG, + wpa, sizeof(*wpa)); + if (!cmd) + ret = -ENOMEM; + else if (cmd->status || cmd->cmd_status) + ret = -ENXIO; + kfree(cmd); + pr_debug("%s: --> %d\n", __func__, ret); + return ret; +} + +/* + * Start association. caller must hold assoc_stat_lock + */ +static int gelic_wl_associate_bss(struct gelic_wl_info *wl, + struct gelic_wl_scan_info *bss) +{ + struct gelic_eurus_cmd *cmd; + struct gelic_eurus_common_cfg *common; + int ret = 0; + unsigned long rc; + + pr_debug("%s: <-\n", __func__); + + /* do common config */ + common = wl->buf; + memset(common, 0, sizeof(*common)); + common->bss_type = cpu_to_be16(GELIC_EURUS_BSS_INFRA); + common->op_mode = cpu_to_be16(GELIC_EURUS_OPMODE_11BG); + + common->scan_index = cpu_to_be16(bss->eurus_index); + switch (wl->auth_method) { + case GELIC_EURUS_AUTH_OPEN: + common->auth_method = cpu_to_be16(GELIC_EURUS_AUTH_OPEN); + break; + case GELIC_EURUS_AUTH_SHARED: + common->auth_method = cpu_to_be16(GELIC_EURUS_AUTH_SHARED); + break; + } + +#ifdef DEBUG + scan_list_dump(wl); +#endif + pr_debug("%s: common cfg index=%d bsstype=%d auth=%d\n", __func__, + be16_to_cpu(common->scan_index), + be16_to_cpu(common->bss_type), + be16_to_cpu(common->auth_method)); + + cmd = gelic_eurus_sync_cmd(wl, GELIC_EURUS_CMD_SET_COMMON_CFG, + common, sizeof(*common)); + if (!cmd || cmd->status || cmd->cmd_status) { + ret = -ENOMEM; + kfree(cmd); + goto out; + } + kfree(cmd); + + /* WEP/WPA */ + switch (wl->wpa_level) { + case GELIC_WL_WPA_LEVEL_NONE: + /* If WEP or no security, setup WEP config */ + ret = gelic_wl_do_wep_setup(wl); + break; + case GELIC_WL_WPA_LEVEL_WPA: + case GELIC_WL_WPA_LEVEL_WPA2: + ret = gelic_wl_do_wpa_setup(wl); + break; + }; + + if (ret) { + pr_debug("%s: WEP/WPA setup failed %d\n", __func__, + ret); + } + + /* start association */ + init_completion(&wl->assoc_done); + wl->assoc_stat = GELIC_WL_ASSOC_STAT_ASSOCIATING; + cmd = gelic_eurus_sync_cmd(wl, GELIC_EURUS_CMD_ASSOC, + NULL, 0); + if (!cmd || cmd->status || cmd->cmd_status) { + pr_debug("%s: assoc request failed\n", __func__); + wl->assoc_stat = GELIC_WL_ASSOC_STAT_DISCONN; + kfree(cmd); + ret = -ENOMEM; + gelic_wl_send_iwap_event(wl, NULL); + goto out; + } + kfree(cmd); + + /* wait for connected event */ + rc = wait_for_completion_timeout(&wl->assoc_done, HZ * 4);/*FIXME*/ + + if (!rc) { + /* timeouted. Maybe key or cyrpt mode is wrong */ + pr_info("%s: connect timeout \n", __func__); + cmd = gelic_eurus_sync_cmd(wl, GELIC_EURUS_CMD_DISASSOC, + NULL, 0); + kfree(cmd); + wl->assoc_stat = GELIC_WL_ASSOC_STAT_DISCONN; + gelic_wl_send_iwap_event(wl, NULL); + ret = -ENXIO; + } else { + wl->assoc_stat = GELIC_WL_ASSOC_STAT_ASSOCIATED; + /* copy bssid */ + memcpy(wl->active_bssid, &bss->hwinfo->bssid[2], ETH_ALEN); + + /* send connect event */ + gelic_wl_send_iwap_event(wl, wl->active_bssid); + pr_info("%s: connected\n", __func__); + } +out: + pr_debug("%s: ->\n", __func__); + return ret; +} + +/* + * connected event + */ +static void gelic_wl_connected_event(struct gelic_wl_info *wl, + u64 event) +{ + u64 desired_event = 0; + + switch (wl->wpa_level) { + case GELIC_WL_WPA_LEVEL_NONE: + desired_event = GELIC_LV1_WL_EVENT_CONNECTED; + break; + case GELIC_WL_WPA_LEVEL_WPA: + case GELIC_WL_WPA_LEVEL_WPA2: + desired_event = GELIC_LV1_WL_EVENT_WPA_CONNECTED; + break; + } + + if (desired_event == event) { + pr_debug("%s: completed \n", __func__); + complete(&wl->assoc_done); + netif_carrier_on(port_to_netdev(wl_port(wl))); + } else + pr_debug("%s: event %#lx under wpa\n", + __func__, event); +} + +/* + * disconnect event + */ +static void gelic_wl_disconnect_event(struct gelic_wl_info *wl, + u64 event) +{ + struct gelic_eurus_cmd *cmd; + int lock; + + /* + * If we fall here in the middle of association, + * associate_bss() should be waiting for complation of + * wl->assoc_done. + * As it waits with timeout, just leave assoc_done + * uncompleted, then it terminates with timeout + */ + if (down_trylock(&wl->assoc_stat_lock)) { + pr_debug("%s: already locked\n", __func__); + lock = 0; + } else { + pr_debug("%s: obtain lock\n", __func__); + lock = 1; + } + + cmd = gelic_eurus_sync_cmd(wl, GELIC_EURUS_CMD_DISASSOC, NULL, 0); + kfree(cmd); + + /* send disconnected event to the supplicant */ + if (wl->assoc_stat == GELIC_WL_ASSOC_STAT_ASSOCIATED) + gelic_wl_send_iwap_event(wl, NULL); + + wl->assoc_stat = GELIC_WL_ASSOC_STAT_DISCONN; + netif_carrier_off(port_to_netdev(wl_port(wl))); + + if (lock) + up(&wl->assoc_stat_lock); +} +/* + * event worker + */ +#ifdef DEBUG +static const char *eventstr(enum gelic_lv1_wl_event event) +{ + static char buf[32]; + char *ret; + if (event & GELIC_LV1_WL_EVENT_DEVICE_READY) + ret = "EURUS_READY"; + else if (event & GELIC_LV1_WL_EVENT_SCAN_COMPLETED) + ret = "SCAN_COMPLETED"; + else if (event & GELIC_LV1_WL_EVENT_DEAUTH) + ret = "DEAUTH"; + else if (event & GELIC_LV1_WL_EVENT_BEACON_LOST) + ret = "BEACON_LOST"; + else if (event & GELIC_LV1_WL_EVENT_CONNECTED) + ret = "CONNECTED"; + else if (event & GELIC_LV1_WL_EVENT_WPA_CONNECTED) + ret = "WPA_CONNECTED"; + else if (event & GELIC_LV1_WL_EVENT_WPA_ERROR) + ret = "WPA_ERROR"; + else { + sprintf(buf, "Unknown(%#x)", event); + ret = buf; + } + return ret; +} +#else +static const char *eventstr(enum gelic_lv1_wl_event event) +{ + return NULL; +} +#endif +static void gelic_wl_event_worker(struct work_struct *work) +{ + struct gelic_wl_info *wl; + struct gelic_port *port; + u64 event, tmp; + int status; + + pr_debug("%s:start\n", __func__); + wl = container_of(work, struct gelic_wl_info, event_work.work); + port = wl_port(wl); + while (1) { + status = lv1_net_control(bus_id(port->card), dev_id(port->card), + GELIC_LV1_GET_WLAN_EVENT, 0, 0, 0, + &event, &tmp); + if (status) { + if (status != LV1_NO_ENTRY) + pr_debug("%s:wlan event failed %d\n", + __func__, status); + /* got all events */ + pr_debug("%s:end\n", __func__); + return; + } + pr_debug("%s: event=%s\n", __func__, eventstr(event)); + switch (event) { + case GELIC_LV1_WL_EVENT_SCAN_COMPLETED: + gelic_wl_scan_complete_event(wl); + break; + case GELIC_LV1_WL_EVENT_BEACON_LOST: + case GELIC_LV1_WL_EVENT_DEAUTH: + gelic_wl_disconnect_event(wl, event); + break; + case GELIC_LV1_WL_EVENT_CONNECTED: + case GELIC_LV1_WL_EVENT_WPA_CONNECTED: + gelic_wl_connected_event(wl, event); + break; + default: + break; + } + } /* while */ +} +/* + * association worker + */ +static void gelic_wl_assoc_worker(struct work_struct *work) +{ + struct gelic_wl_info *wl; + + struct gelic_wl_scan_info *best_bss; + int ret; + + wl = container_of(work, struct gelic_wl_info, assoc_work.work); + + down(&wl->assoc_stat_lock); + + if (wl->assoc_stat != GELIC_WL_ASSOC_STAT_DISCONN) + goto out; + + ret = gelic_wl_start_scan(wl, 0); + if (ret == -ERESTARTSYS) { + pr_debug("%s: scan start failed association\n", __func__); + schedule_delayed_work(&wl->assoc_work, HZ/10); /*FIXME*/ + goto out; + } else if (ret) { + pr_info("%s: scan prerequisite failed\n", __func__); + goto out; + } + + /* + * Wait for bss scan completion + * If we have scan list already, gelic_wl_start_scan() + * returns OK and raises the complete. Thus, + * it's ok to wait unconditionally here + */ + wait_for_completion(&wl->scan_done); + + pr_debug("%s: scan done\n", __func__); + down(&wl->scan_lock); + if (wl->scan_stat != GELIC_WL_SCAN_STAT_GOT_LIST) { + gelic_wl_send_iwap_event(wl, NULL); + pr_info("%s: no scan list. association failed\n", __func__); + goto scan_lock_out; + } + + /* find best matching bss */ + best_bss = gelic_wl_find_best_bss(wl); + if (!best_bss) { + gelic_wl_send_iwap_event(wl, NULL); + pr_info("%s: no bss matched. association failed\n", __func__); + goto scan_lock_out; + } + + /* ok, do association */ + ret = gelic_wl_associate_bss(wl, best_bss); + if (ret) + pr_info("%s: association failed %d\n", __func__, ret); +scan_lock_out: + up(&wl->scan_lock); +out: + up(&wl->assoc_stat_lock); +} +/* + * Interrupt handler + * Called from the ethernet interrupt handler + * Processes wireless specific virtual interrupts only + */ +void gelic_wl_interrupt(struct net_device *netdev, u64 status) +{ + struct gelic_wl_info *wl = port_wl(netdev_priv(netdev)); + + if (status & GELIC_CARD_WLAN_COMMAND_COMPLETED) { + pr_debug("%s:cmd complete\n", __func__); + complete(&wl->cmd_done_intr); + } + + if (status & GELIC_CARD_WLAN_EVENT_RECEIVED) { + pr_debug("%s:event received\n", __func__); + queue_delayed_work(wl->event_queue, &wl->event_work, 0); + } +} + +/* + * driver helpers + */ +#define IW_IOCTL(n) [(n) - SIOCSIWCOMMIT] +static const iw_handler gelic_wl_wext_handler[] = +{ + IW_IOCTL(SIOCGIWNAME) = gelic_wl_get_name, + IW_IOCTL(SIOCGIWRANGE) = gelic_wl_get_range, + IW_IOCTL(SIOCSIWSCAN) = gelic_wl_set_scan, + IW_IOCTL(SIOCGIWSCAN) = gelic_wl_get_scan, + IW_IOCTL(SIOCSIWAUTH) = gelic_wl_set_auth, + IW_IOCTL(SIOCGIWAUTH) = gelic_wl_get_auth, + IW_IOCTL(SIOCSIWESSID) = gelic_wl_set_essid, + IW_IOCTL(SIOCGIWESSID) = gelic_wl_get_essid, + IW_IOCTL(SIOCSIWENCODE) = gelic_wl_set_encode, + IW_IOCTL(SIOCGIWENCODE) = gelic_wl_get_encode, + IW_IOCTL(SIOCSIWAP) = gelic_wl_set_ap, + IW_IOCTL(SIOCGIWAP) = gelic_wl_get_ap, + IW_IOCTL(SIOCSIWENCODEEXT) = gelic_wl_set_encodeext, + IW_IOCTL(SIOCGIWENCODEEXT) = gelic_wl_get_encodeext, + IW_IOCTL(SIOCSIWMODE) = gelic_wl_set_mode, + IW_IOCTL(SIOCGIWMODE) = gelic_wl_get_mode, + IW_IOCTL(SIOCGIWNICKN) = gelic_wl_get_nick, +}; + +static struct iw_priv_args gelic_wl_private_args[] = +{ + { + .cmd = GELIC_WL_PRIV_SET_PSK, + .set_args = IW_PRIV_TYPE_CHAR | + (GELIC_WL_EURUS_PSK_MAX_LEN + 2), + .name = "set_psk" + }, + { + .cmd = GELIC_WL_PRIV_GET_PSK, + .get_args = IW_PRIV_TYPE_CHAR | + (GELIC_WL_EURUS_PSK_MAX_LEN + 2), + .name = "get_psk" + } +}; + +static const iw_handler gelic_wl_private_handler[] = +{ + gelic_wl_priv_set_psk, + gelic_wl_priv_get_psk, +}; + +static const struct iw_handler_def gelic_wl_wext_handler_def = { + .num_standard = ARRAY_SIZE(gelic_wl_wext_handler), + .standard = gelic_wl_wext_handler, + .get_wireless_stats = gelic_wl_get_wireless_stats, + .num_private = ARRAY_SIZE(gelic_wl_private_handler), + .num_private_args = ARRAY_SIZE(gelic_wl_private_args), + .private = gelic_wl_private_handler, + .private_args = gelic_wl_private_args, +}; + +static struct net_device *gelic_wl_alloc(struct gelic_card *card) +{ + struct net_device *netdev; + struct gelic_port *port; + struct gelic_wl_info *wl; + unsigned int i; + + pr_debug("%s:start\n", __func__); + netdev = alloc_etherdev(sizeof(struct gelic_port) + + sizeof(struct gelic_wl_info)); + pr_debug("%s: netdev =%p card=%p \np", __func__, netdev, card); + if (!netdev) + return NULL; + + port = netdev_priv(netdev); + port->netdev = netdev; + port->card = card; + port->type = GELIC_PORT_WIRELESS; + + wl = port_wl(port); + pr_debug("%s: wl=%p port=%p\n", __func__, wl, port); + + /* allocate scan list */ + wl->networks = kzalloc(sizeof(struct gelic_wl_scan_info) * + GELIC_WL_BSS_MAX_ENT, GFP_KERNEL); + + if (!wl->networks) + goto fail_bss; + + wl->eurus_cmd_queue = create_singlethread_workqueue("gelic_cmd"); + if (!wl->eurus_cmd_queue) + goto fail_cmd_workqueue; + + wl->event_queue = create_singlethread_workqueue("gelic_event"); + if (!wl->event_queue) + goto fail_event_workqueue; + + INIT_LIST_HEAD(&wl->network_free_list); + INIT_LIST_HEAD(&wl->network_list); + for (i = 0; i < GELIC_WL_BSS_MAX_ENT; i++) + list_add_tail(&wl->networks[i].list, + &wl->network_free_list); + init_completion(&wl->cmd_done_intr); + + INIT_DELAYED_WORK(&wl->event_work, gelic_wl_event_worker); + INIT_DELAYED_WORK(&wl->assoc_work, gelic_wl_assoc_worker); + init_MUTEX(&wl->scan_lock); + init_MUTEX(&wl->assoc_stat_lock); + + init_completion(&wl->scan_done); + /* for the case that no scan request is issued and stop() is called */ + complete(&wl->scan_done); + + spin_lock_init(&wl->lock); + + wl->scan_age = 5*HZ; /* FIXME */ + + /* buffer for receiving scanned list etc */ + BUILD_BUG_ON(PAGE_SIZE < + sizeof(struct gelic_eurus_scan_info) * + GELIC_EURUS_MAX_SCAN); + wl->buf = (void *)get_zeroed_page(GFP_KERNEL); + if (!wl->buf) { + pr_info("%s:buffer allocation failed\n", __func__); + goto fail_getpage; + } + pr_debug("%s:end\n", __func__); + return netdev; + +fail_getpage: + destroy_workqueue(wl->event_queue); +fail_event_workqueue: + destroy_workqueue(wl->eurus_cmd_queue); +fail_cmd_workqueue: + kfree(wl->networks); +fail_bss: + free_netdev(netdev); + pr_debug("%s:end error\n", __func__); + return NULL; + +} + +static void gelic_wl_free(struct gelic_wl_info *wl) +{ + struct gelic_wl_scan_info *scan_info; + unsigned int i; + + pr_debug("%s: <-\n", __func__); + + pr_debug("%s: destroy queues\n", __func__); + destroy_workqueue(wl->eurus_cmd_queue); + destroy_workqueue(wl->event_queue); + + scan_info = wl->networks; + for (i = 0; i < GELIC_WL_BSS_MAX_ENT; i++, scan_info++) + kfree(scan_info->hwinfo); + kfree(wl->networks); + + free_netdev(port_to_netdev(wl_port(wl))); + + pr_debug("%s: ->\n", __func__); +} + +static int gelic_wl_try_associate(struct net_device *netdev) +{ + struct gelic_wl_info *wl = port_wl(netdev_priv(netdev)); + int ret = -1; + unsigned int i; + + pr_debug("%s: <-\n", __func__); + + /* check constraits for start association */ + /* for no access restriction AP */ + if (wl->group_cipher_method == GELIC_WL_CIPHER_NONE) { + if (test_bit(GELIC_WL_STAT_CONFIGURED, + &wl->stat)) + goto do_associate; + else { + pr_debug("%s: no wep, not configured\n", __func__); + return ret; + } + } + + /* for WEP, one of four keys should be set */ + if (wl->group_cipher_method == GELIC_WL_CIPHER_WEP) { + /* one of keys set */ + for (i = 0; i < GELIC_WEP_KEYS; i++) { + if (test_bit(i, &wl->key_enabled)) + goto do_associate; + } + pr_debug("%s: WEP, but no key specified\n", __func__); + return ret; + } + + /* for WPA[2], psk should be set */ + if ((wl->group_cipher_method == GELIC_WL_CIPHER_TKIP) || + (wl->group_cipher_method == GELIC_WL_CIPHER_AES)) { + if (test_bit(GELIC_WL_STAT_WPA_PSK_SET, + &wl->stat)) + goto do_associate; + else { + pr_debug("%s: AES/TKIP, but PSK not configured\n", + __func__); + return ret; + } + } + +do_associate: + ret = schedule_delayed_work(&wl->assoc_work, 0); + pr_debug("%s: start association work %d\n", __func__, ret); + return ret; +} + +/* + * netdev handlers + */ +static int gelic_wl_open(struct net_device *netdev) +{ + struct gelic_card *card = netdev_card(netdev); + + pr_debug("%s:->%p\n", __func__, netdev); + + gelic_card_up(card); + + /* try to associate */ + gelic_wl_try_associate(netdev); + + netif_start_queue(netdev); + + pr_debug("%s:<-\n", __func__); + return 0; +} + +/* + * reset state machine + */ +static int gelic_wl_reset_state(struct gelic_wl_info *wl) +{ + struct gelic_wl_scan_info *target; + struct gelic_wl_scan_info *tmp; + + /* empty scan list */ + list_for_each_entry_safe(target, tmp, &wl->network_list, list) { + list_move_tail(&target->list, &wl->network_free_list); + } + wl->scan_stat = GELIC_WL_SCAN_STAT_INIT; + + /* clear configuration */ + wl->auth_method = GELIC_EURUS_AUTH_OPEN; + wl->group_cipher_method = GELIC_WL_CIPHER_NONE; + wl->pairwise_cipher_method = GELIC_WL_CIPHER_NONE; + wl->wpa_level = GELIC_WL_WPA_LEVEL_NONE; + + wl->key_enabled = 0; + wl->current_key = 0; + + wl->psk_type = GELIC_EURUS_WPA_PSK_PASSPHRASE; + wl->psk_len = 0; + + wl->essid_len = 0; + memset(wl->essid, 0, sizeof(wl->essid)); + memset(wl->bssid, 0, sizeof(wl->bssid)); + memset(wl->active_bssid, 0, sizeof(wl->active_bssid)); + + wl->assoc_stat = GELIC_WL_ASSOC_STAT_DISCONN; + + memset(&wl->iwstat, 0, sizeof(wl->iwstat)); + /* all status bit clear */ + wl->stat = 0; + return 0; +} + +/* + * Tell eurus to terminate association + */ +static void gelic_wl_disconnect(struct net_device *netdev) +{ + struct gelic_port *port = netdev_priv(netdev); + struct gelic_wl_info *wl = port_wl(port); + struct gelic_eurus_cmd *cmd; + + /* + * If scann process is running on chip, + * further requests will be rejected + */ + if (wl->scan_stat == GELIC_WL_SCAN_STAT_SCANNING) + wait_for_completion_timeout(&wl->scan_done, HZ); + + cmd = gelic_eurus_sync_cmd(wl, GELIC_EURUS_CMD_DISASSOC, NULL, 0); + kfree(cmd); + gelic_wl_send_iwap_event(wl, NULL); +}; + +static int gelic_wl_stop(struct net_device *netdev) +{ + struct gelic_port *port = netdev_priv(netdev); + struct gelic_wl_info *wl = port_wl(port); + struct gelic_card *card = netdev_card(netdev); + + pr_debug("%s:<-\n", __func__); + + /* + * Cancel pending association work. + * event work can run after netdev down + */ + cancel_delayed_work(&wl->assoc_work); + + if (wl->assoc_stat == GELIC_WL_ASSOC_STAT_ASSOCIATED) + gelic_wl_disconnect(netdev); + + /* reset our state machine */ + gelic_wl_reset_state(wl); + + netif_stop_queue(netdev); + + gelic_card_down(card); + + pr_debug("%s:->\n", __func__); + return 0; +} + +/* -- */ + +static struct ethtool_ops gelic_wl_ethtool_ops = { + .get_drvinfo = gelic_net_get_drvinfo, + .get_link = gelic_wl_get_link, + .get_tx_csum = ethtool_op_get_tx_csum, + .set_tx_csum = ethtool_op_set_tx_csum, + .get_rx_csum = gelic_net_get_rx_csum, + .set_rx_csum = gelic_net_set_rx_csum, +}; + +static void gelic_wl_setup_netdev_ops(struct net_device *netdev) +{ + struct gelic_wl_info *wl; + wl = port_wl(netdev_priv(netdev)); + BUG_ON(!wl); + netdev->open = &gelic_wl_open; + netdev->stop = &gelic_wl_stop; + netdev->hard_start_xmit = &gelic_net_xmit; + netdev->set_multicast_list = &gelic_net_set_multi; + netdev->change_mtu = &gelic_net_change_mtu; + netdev->wireless_data = &wl->wireless_data; + netdev->wireless_handlers = &gelic_wl_wext_handler_def; + /* tx watchdog */ + netdev->tx_timeout = &gelic_net_tx_timeout; + netdev->watchdog_timeo = GELIC_NET_WATCHDOG_TIMEOUT; + + netdev->ethtool_ops = &gelic_wl_ethtool_ops; +#ifdef CONFIG_NET_POLL_CONTROLLER + netdev->poll_controller = gelic_net_poll_controller; +#endif +} + +/* + * driver probe/remove + */ +int gelic_wl_driver_probe(struct gelic_card *card) +{ + int ret; + struct net_device *netdev; + + pr_debug("%s:start\n", __func__); + + if (ps3_compare_firmware_version(1, 6, 0) < 0) + return 0; + if (!card->vlan[GELIC_PORT_WIRELESS].tx) + return 0; + + /* alloc netdevice for wireless */ + netdev = gelic_wl_alloc(card); + if (!netdev) + return -ENOMEM; + + /* setup net_device structure */ + gelic_wl_setup_netdev_ops(netdev); + + /* setup some of net_device and register it */ + ret = gelic_net_setup_netdev(netdev, card); + if (ret) + goto fail_setup; + card->netdev[GELIC_PORT_WIRELESS] = netdev; + + /* add enable wireless interrupt */ + card->irq_mask |= GELIC_CARD_WLAN_EVENT_RECEIVED | + GELIC_CARD_WLAN_COMMAND_COMPLETED; + /* to allow wireless commands while both interfaces are down */ + gelic_card_set_irq_mask(card, GELIC_CARD_WLAN_EVENT_RECEIVED | + GELIC_CARD_WLAN_COMMAND_COMPLETED); + pr_debug("%s:end\n", __func__); + return 0; + +fail_setup: + gelic_wl_free(port_wl(netdev_port(netdev))); + + return ret; +} + +int gelic_wl_driver_remove(struct gelic_card *card) +{ + struct gelic_wl_info *wl; + struct net_device *netdev; + + pr_debug("%s:start\n", __func__); + + if (ps3_compare_firmware_version(1, 6, 0) < 0) + return 0; + if (!card->vlan[GELIC_PORT_WIRELESS].tx) + return 0; + + netdev = card->netdev[GELIC_PORT_WIRELESS]; + wl = port_wl(netdev_priv(netdev)); + + /* if the interface was not up, but associated */ + if (wl->assoc_stat == GELIC_WL_ASSOC_STAT_ASSOCIATED) + gelic_wl_disconnect(netdev); + + complete(&wl->cmd_done_intr); + + /* cancel all work queue */ + cancel_delayed_work(&wl->assoc_work); + cancel_delayed_work(&wl->event_work); + flush_workqueue(wl->eurus_cmd_queue); + flush_workqueue(wl->event_queue); + + unregister_netdev(netdev); + + /* disable wireless interrupt */ + pr_debug("%s: disable intr\n", __func__); + card->irq_mask &= ~(GELIC_CARD_WLAN_EVENT_RECEIVED | + GELIC_CARD_WLAN_COMMAND_COMPLETED); + /* free bss list, netdev*/ + gelic_wl_free(wl); + pr_debug("%s:end\n", __func__); + return 0; +} diff --git a/drivers/net/ps3_gelic_wireless.h b/drivers/net/ps3_gelic_wireless.h new file mode 100644 index 00000000000..10369716672 --- /dev/null +++ b/drivers/net/ps3_gelic_wireless.h @@ -0,0 +1,329 @@ +/* + * PS3 gelic network driver. + * + * Copyright (C) 2007 Sony Computer Entertainment Inc. + * Copyright 2007 Sony Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation version 2. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#ifndef _GELIC_WIRELESS_H +#define _GELIC_WIRELESS_H + +#include <linux/wireless.h> +#include <net/iw_handler.h> + + +/* return value from GELIC_LV1_GET_WLAN_EVENT netcontrol */ +enum gelic_lv1_wl_event { + GELIC_LV1_WL_EVENT_DEVICE_READY = 0x01, /* Eurus ready */ + GELIC_LV1_WL_EVENT_SCAN_COMPLETED = 0x02, /* Scan has completed */ + GELIC_LV1_WL_EVENT_DEAUTH = 0x04, /* Deauthed by the AP */ + GELIC_LV1_WL_EVENT_BEACON_LOST = 0x08, /* Beacon lost detected */ + GELIC_LV1_WL_EVENT_CONNECTED = 0x10, /* Connected to AP */ + GELIC_LV1_WL_EVENT_WPA_CONNECTED = 0x20, /* WPA connection */ + GELIC_LV1_WL_EVENT_WPA_ERROR = 0x40, /* MIC error */ +}; + +/* arguments for GELIC_LV1_POST_WLAN_COMMAND netcontrol */ +enum gelic_eurus_command { + GELIC_EURUS_CMD_ASSOC = 1, /* association start */ + GELIC_EURUS_CMD_DISASSOC = 2, /* disassociate */ + GELIC_EURUS_CMD_START_SCAN = 3, /* scan start */ + GELIC_EURUS_CMD_GET_SCAN = 4, /* get scan result */ + GELIC_EURUS_CMD_SET_COMMON_CFG = 5, /* set common config */ + GELIC_EURUS_CMD_GET_COMMON_CFG = 6, /* set common config */ + GELIC_EURUS_CMD_SET_WEP_CFG = 7, /* set WEP config */ + GELIC_EURUS_CMD_GET_WEP_CFG = 8, /* get WEP config */ + GELIC_EURUS_CMD_SET_WPA_CFG = 9, /* set WPA config */ + GELIC_EURUS_CMD_GET_WPA_CFG = 10, /* get WPA config */ + GELIC_EURUS_CMD_GET_RSSI_CFG = 11, /* get RSSI info. */ + GELIC_EURUS_CMD_MAX_INDEX +}; + +/* for GELIC_EURUS_CMD_COMMON_CFG */ +enum gelic_eurus_bss_type { + GELIC_EURUS_BSS_INFRA = 0, + GELIC_EURUS_BSS_ADHOC = 1, /* not supported */ +}; + +enum gelic_eurus_auth_method { + GELIC_EURUS_AUTH_OPEN = 0, /* FIXME: WLAN_AUTH_OPEN */ + GELIC_EURUS_AUTH_SHARED = 1, /* not supported */ +}; + +enum gelic_eurus_opmode { + GELIC_EURUS_OPMODE_11BG = 0, /* 802.11b/g */ + GELIC_EURUS_OPMODE_11B = 1, /* 802.11b only */ + GELIC_EURUS_OPMODE_11G = 2, /* 802.11g only */ +}; + +struct gelic_eurus_common_cfg { + /* all fields are big endian */ + u16 scan_index; + u16 bss_type; /* infra or adhoc */ + u16 auth_method; /* shared key or open */ + u16 op_mode; /* B/G */ +} __attribute__((packed)); + + +/* for GELIC_EURUS_CMD_WEP_CFG */ +enum gelic_eurus_wep_security { + GELIC_EURUS_WEP_SEC_NONE = 0, + GELIC_EURUS_WEP_SEC_40BIT = 1, + GELIC_EURUS_WEP_SEC_104BIT = 2, +}; + +struct gelic_eurus_wep_cfg { + /* all fields are big endian */ + u16 security; + u8 key[4][16]; +} __attribute__((packed)); + +/* for GELIC_EURUS_CMD_WPA_CFG */ +enum gelic_eurus_wpa_security { + GELIC_EURUS_WPA_SEC_NONE = 0x0000, + /* group=TKIP, pairwise=TKIP */ + GELIC_EURUS_WPA_SEC_WPA_TKIP_TKIP = 0x0001, + /* group=AES, pairwise=AES */ + GELIC_EURUS_WPA_SEC_WPA_AES_AES = 0x0002, + /* group=TKIP, pairwise=TKIP */ + GELIC_EURUS_WPA_SEC_WPA2_TKIP_TKIP = 0x0004, + /* group=AES, pairwise=AES */ + GELIC_EURUS_WPA_SEC_WPA2_AES_AES = 0x0008, + /* group=TKIP, pairwise=AES */ + GELIC_EURUS_WPA_SEC_WPA_TKIP_AES = 0x0010, + /* group=TKIP, pairwise=AES */ + GELIC_EURUS_WPA_SEC_WPA2_TKIP_AES = 0x0020, +}; + +enum gelic_eurus_wpa_psk_type { + GELIC_EURUS_WPA_PSK_PASSPHRASE = 0, /* passphrase string */ + GELIC_EURUS_WPA_PSK_BIN = 1, /* 32 bytes binary key */ +}; + +#define GELIC_WL_EURUS_PSK_MAX_LEN 64 +#define WPA_PSK_LEN 32 /* WPA spec says 256bit */ + +struct gelic_eurus_wpa_cfg { + /* all fields are big endian */ + u16 security; + u16 psk_type; /* psk key encoding type */ + u8 psk[GELIC_WL_EURUS_PSK_MAX_LEN]; /* psk key; hex or passphrase */ +} __attribute__((packed)); + +/* for GELIC_EURUS_CMD_{START,GET}_SCAN */ +enum gelic_eurus_scan_capability { + GELIC_EURUS_SCAN_CAP_ADHOC = 0x0000, + GELIC_EURUS_SCAN_CAP_INFRA = 0x0001, + GELIC_EURUS_SCAN_CAP_MASK = 0x0001, +}; + +enum gelic_eurus_scan_sec_type { + GELIC_EURUS_SCAN_SEC_NONE = 0x0000, + GELIC_EURUS_SCAN_SEC_WEP = 0x0100, + GELIC_EURUS_SCAN_SEC_WPA = 0x0200, + GELIC_EURUS_SCAN_SEC_WPA2 = 0x0400, + GELIC_EURUS_SCAN_SEC_MASK = 0x0f00, +}; + +enum gelic_eurus_scan_sec_wep_type { + GELIC_EURUS_SCAN_SEC_WEP_UNKNOWN = 0x0000, + GELIC_EURUS_SCAN_SEC_WEP_40 = 0x0001, + GELIC_EURUS_SCAN_SEC_WEP_104 = 0x0002, + GELIC_EURUS_SCAN_SEC_WEP_MASK = 0x0003, +}; + +enum gelic_eurus_scan_sec_wpa_type { + GELIC_EURUS_SCAN_SEC_WPA_UNKNOWN = 0x0000, + GELIC_EURUS_SCAN_SEC_WPA_TKIP = 0x0001, + GELIC_EURUS_SCAN_SEC_WPA_AES = 0x0002, + GELIC_EURUS_SCAN_SEC_WPA_MASK = 0x0003, +}; + +/* + * hw BSS information structure returned from GELIC_EURUS_CMD_GET_SCAN + */ +struct gelic_eurus_scan_info { + /* all fields are big endian */ + __be16 size; + __be16 rssi; /* percentage */ + __be16 channel; /* channel number */ + __be16 beacon_period; /* FIXME: in msec unit */ + __be16 capability; + __be16 security; + u8 bssid[8]; /* last ETH_ALEN are valid. bssid[0],[1] are unused */ + u8 essid[32]; /* IW_ESSID_MAX_SIZE */ + u8 rate[16]; /* first MAX_RATES_LENGTH(12) are valid */ + u8 ext_rate[16]; /* first MAX_RATES_EX_LENGTH(16) are valid */ + __be32 reserved1; + __be32 reserved2; + __be32 reserved3; + __be32 reserved4; + u8 elements[0]; /* ie */ +} __attribute__ ((packed)); + +/* the hypervisor returns bbs up to 16 */ +#define GELIC_EURUS_MAX_SCAN (16) +struct gelic_wl_scan_info { + struct list_head list; + struct gelic_eurus_scan_info *hwinfo; + + int valid; /* set 1 if this entry was in latest scanned list + * from Eurus */ + unsigned int eurus_index; /* index in the Eurus list */ + unsigned long last_scanned; /* acquired time */ + + unsigned int rate_len; + unsigned int rate_ext_len; + unsigned int essid_len; +}; + +/* for GELIC_EURUS_CMD_GET_RSSI */ +struct gelic_eurus_rssi_info { + /* big endian */ + __be16 rssi; +} __attribute__ ((packed)); + + +/* for 'stat' member of gelic_wl_info */ +enum gelic_wl_info_status_bit { + GELIC_WL_STAT_CONFIGURED, + GELIC_WL_STAT_CH_INFO, /* ch info aquired */ + GELIC_WL_STAT_ESSID_SET, /* ESSID specified by userspace */ + GELIC_WL_STAT_BSSID_SET, /* BSSID specified by userspace */ + GELIC_WL_STAT_WPA_PSK_SET, /* PMK specified by userspace */ + GELIC_WL_STAT_WPA_LEVEL_SET, /* WEP or WPA[2] selected */ +}; + +/* for 'scan_stat' member of gelic_wl_info */ +enum gelic_wl_scan_state { + /* just initialized or get last scan result failed */ + GELIC_WL_SCAN_STAT_INIT, + /* scan request issued, accepted or chip is scanning */ + GELIC_WL_SCAN_STAT_SCANNING, + /* scan results retrieved */ + GELIC_WL_SCAN_STAT_GOT_LIST, +}; + +/* for 'cipher_method' */ +enum gelic_wl_cipher_method { + GELIC_WL_CIPHER_NONE, + GELIC_WL_CIPHER_WEP, + GELIC_WL_CIPHER_TKIP, + GELIC_WL_CIPHER_AES, +}; + +/* for 'wpa_level' */ +enum gelic_wl_wpa_level { + GELIC_WL_WPA_LEVEL_NONE, + GELIC_WL_WPA_LEVEL_WPA, + GELIC_WL_WPA_LEVEL_WPA2, +}; + +/* for 'assoc_stat' */ +enum gelic_wl_assoc_state { + GELIC_WL_ASSOC_STAT_DISCONN, + GELIC_WL_ASSOC_STAT_ASSOCIATING, + GELIC_WL_ASSOC_STAT_ASSOCIATED, +}; +/* part of private data alloc_etherdev() allocated */ +#define GELIC_WEP_KEYS 4 +struct gelic_wl_info { + /* bss list */ + struct semaphore scan_lock; + struct list_head network_list; + struct list_head network_free_list; + struct gelic_wl_scan_info *networks; + + unsigned long scan_age; /* last scanned time */ + enum gelic_wl_scan_state scan_stat; + struct completion scan_done; + + /* eurus command queue */ + struct workqueue_struct *eurus_cmd_queue; + struct completion cmd_done_intr; + + /* eurus event handling */ + struct workqueue_struct *event_queue; + struct delayed_work event_work; + + /* wl status bits */ + unsigned long stat; + enum gelic_eurus_auth_method auth_method; /* open/shared */ + enum gelic_wl_cipher_method group_cipher_method; + enum gelic_wl_cipher_method pairwise_cipher_method; + enum gelic_wl_wpa_level wpa_level; /* wpa/wpa2 */ + + /* association handling */ + struct semaphore assoc_stat_lock; + struct delayed_work assoc_work; + enum gelic_wl_assoc_state assoc_stat; + struct completion assoc_done; + + spinlock_t lock; + u16 ch_info; /* available channels. bit0 = ch1 */ + /* WEP keys */ + u8 key[GELIC_WEP_KEYS][IW_ENCODING_TOKEN_MAX]; + unsigned long key_enabled; + unsigned int key_len[GELIC_WEP_KEYS]; + unsigned int current_key; + /* WWPA PSK */ + u8 psk[GELIC_WL_EURUS_PSK_MAX_LEN]; + enum gelic_eurus_wpa_psk_type psk_type; + unsigned int psk_len; + + u8 essid[IW_ESSID_MAX_SIZE]; + u8 bssid[ETH_ALEN]; /* userland requested */ + u8 active_bssid[ETH_ALEN]; /* associated bssid */ + unsigned int essid_len; + + /* buffer for hypervisor IO */ + void *buf; + + struct iw_public_data wireless_data; + struct iw_statistics iwstat; +}; + +#define GELIC_WL_BSS_MAX_ENT 32 +#define GELIC_WL_ASSOC_RETRY 50 +static inline struct gelic_port *wl_port(struct gelic_wl_info *wl) +{ + return container_of((void *)wl, struct gelic_port, priv); +} +static inline struct gelic_wl_info *port_wl(struct gelic_port *port) +{ + return port_priv(port); +} + +struct gelic_eurus_cmd { + struct work_struct work; + struct gelic_wl_info *wl; + unsigned int cmd; /* command code */ + u64 tag; + u64 size; + void *buffer; + unsigned int buf_size; + struct completion done; + int status; + u64 cmd_status; +}; + +/* private ioctls to pass PSK */ +#define GELIC_WL_PRIV_SET_PSK (SIOCIWFIRSTPRIV + 0) +#define GELIC_WL_PRIV_GET_PSK (SIOCIWFIRSTPRIV + 1) + +extern int gelic_wl_driver_probe(struct gelic_card *card); +extern int gelic_wl_driver_remove(struct gelic_card *card); +extern void gelic_wl_interrupt(struct net_device *netdev, u64 status); +#endif /* _GELIC_WIRELESS_H */ diff --git a/drivers/net/r6040.c b/drivers/net/r6040.c index 2334f4ebf90..19184e486ae 100644 --- a/drivers/net/r6040.c +++ b/drivers/net/r6040.c @@ -61,7 +61,6 @@ /* Time in jiffies before concluding the transmitter is hung. */ #define TX_TIMEOUT (6000 * HZ / 1000) -#define TIMER_WUT (jiffies + HZ * 1)/* timer wakeup time : 1 second */ /* RDC MAC I/O Size */ #define R6040_IO_SIZE 256 @@ -174,8 +173,6 @@ struct r6040_private { struct net_device *dev; struct mii_if_info mii_if; struct napi_struct napi; - struct net_device_stats stats; - u16 napi_rx_running; void __iomem *base; }; @@ -235,17 +232,53 @@ static void mdio_write(struct net_device *dev, int mii_id, int reg, int val) phy_write(ioaddr, lp->phy_addr, reg, val); } -static void r6040_tx_timeout(struct net_device *dev) +static void r6040_free_txbufs(struct net_device *dev) { - struct r6040_private *priv = netdev_priv(dev); + struct r6040_private *lp = netdev_priv(dev); + int i; - disable_irq(dev->irq); - napi_disable(&priv->napi); - spin_lock(&priv->lock); - dev->stats.tx_errors++; - spin_unlock(&priv->lock); + for (i = 0; i < TX_DCNT; i++) { + if (lp->tx_insert_ptr->skb_ptr) { + pci_unmap_single(lp->pdev, lp->tx_insert_ptr->buf, + MAX_BUF_SIZE, PCI_DMA_TODEVICE); + dev_kfree_skb(lp->tx_insert_ptr->skb_ptr); + lp->rx_insert_ptr->skb_ptr = NULL; + } + lp->tx_insert_ptr = lp->tx_insert_ptr->vndescp; + } +} - netif_stop_queue(dev); +static void r6040_free_rxbufs(struct net_device *dev) +{ + struct r6040_private *lp = netdev_priv(dev); + int i; + + for (i = 0; i < RX_DCNT; i++) { + if (lp->rx_insert_ptr->skb_ptr) { + pci_unmap_single(lp->pdev, lp->rx_insert_ptr->buf, + MAX_BUF_SIZE, PCI_DMA_FROMDEVICE); + dev_kfree_skb(lp->rx_insert_ptr->skb_ptr); + lp->rx_insert_ptr->skb_ptr = NULL; + } + lp->rx_insert_ptr = lp->rx_insert_ptr->vndescp; + } +} + +static void r6040_init_ring_desc(struct r6040_descriptor *desc_ring, + dma_addr_t desc_dma, int size) +{ + struct r6040_descriptor *desc = desc_ring; + dma_addr_t mapping = desc_dma; + + while (size-- > 0) { + mapping += sizeof(sizeof(*desc)); + desc->ndesc = cpu_to_le32(mapping); + desc->vndescp = desc + 1; + desc++; + } + desc--; + desc->ndesc = cpu_to_le32(desc_dma); + desc->vndescp = desc_ring; } /* Allocate skb buffer for rx descriptor */ @@ -256,7 +289,7 @@ static void rx_buf_alloc(struct r6040_private *lp, struct net_device *dev) descptr = lp->rx_insert_ptr; while (lp->rx_free_desc < RX_DCNT) { - descptr->skb_ptr = dev_alloc_skb(MAX_BUF_SIZE); + descptr->skb_ptr = netdev_alloc_skb(dev, MAX_BUF_SIZE); if (!descptr->skb_ptr) break; @@ -272,6 +305,63 @@ static void rx_buf_alloc(struct r6040_private *lp, struct net_device *dev) lp->rx_insert_ptr = descptr; } +static void r6040_alloc_txbufs(struct net_device *dev) +{ + struct r6040_private *lp = netdev_priv(dev); + void __iomem *ioaddr = lp->base; + + lp->tx_free_desc = TX_DCNT; + + lp->tx_remove_ptr = lp->tx_insert_ptr = lp->tx_ring; + r6040_init_ring_desc(lp->tx_ring, lp->tx_ring_dma, TX_DCNT); + + iowrite16(lp->tx_ring_dma, ioaddr + MTD_SA0); + iowrite16(lp->tx_ring_dma >> 16, ioaddr + MTD_SA1); +} + +static void r6040_alloc_rxbufs(struct net_device *dev) +{ + struct r6040_private *lp = netdev_priv(dev); + void __iomem *ioaddr = lp->base; + + lp->rx_free_desc = 0; + + lp->rx_remove_ptr = lp->rx_insert_ptr = lp->rx_ring; + r6040_init_ring_desc(lp->rx_ring, lp->rx_ring_dma, RX_DCNT); + + rx_buf_alloc(lp, dev); + + iowrite16(lp->rx_ring_dma, ioaddr + MRD_SA0); + iowrite16(lp->rx_ring_dma >> 16, ioaddr + MRD_SA1); +} + +static void r6040_tx_timeout(struct net_device *dev) +{ + struct r6040_private *priv = netdev_priv(dev); + void __iomem *ioaddr = priv->base; + + printk(KERN_WARNING "%s: transmit timed out, status %4.4x, PHY status " + "%4.4x\n", + dev->name, ioread16(ioaddr + MIER), + mdio_read(dev, priv->mii_if.phy_id, MII_BMSR)); + + disable_irq(dev->irq); + napi_disable(&priv->napi); + spin_lock(&priv->lock); + /* Clear all descriptors */ + r6040_free_txbufs(dev); + r6040_free_rxbufs(dev); + r6040_alloc_txbufs(dev); + r6040_alloc_rxbufs(dev); + + /* Reset MAC */ + iowrite16(MAC_RST, ioaddr + MCR1); + spin_unlock(&priv->lock); + enable_irq(dev->irq); + + dev->stats.tx_errors++; + netif_wake_queue(dev); +} static struct net_device_stats *r6040_get_stats(struct net_device *dev) { @@ -280,11 +370,11 @@ static struct net_device_stats *r6040_get_stats(struct net_device *dev) unsigned long flags; spin_lock_irqsave(&priv->lock, flags); - priv->stats.rx_crc_errors += ioread8(ioaddr + ME_CNT1); - priv->stats.multicast += ioread8(ioaddr + ME_CNT0); + dev->stats.rx_crc_errors += ioread8(ioaddr + ME_CNT1); + dev->stats.multicast += ioread8(ioaddr + ME_CNT0); spin_unlock_irqrestore(&priv->lock, flags); - return &priv->stats; + return &dev->stats; } /* Stop RDC MAC and Free the allocated resource */ @@ -293,7 +383,6 @@ static void r6040_down(struct net_device *dev) struct r6040_private *lp = netdev_priv(dev); void __iomem *ioaddr = lp->base; struct pci_dev *pdev = lp->pdev; - int i; int limit = 2048; u16 *adrp; u16 cmd; @@ -313,27 +402,12 @@ static void r6040_down(struct net_device *dev) iowrite16(adrp[1], ioaddr + MID_0M); iowrite16(adrp[2], ioaddr + MID_0H); free_irq(dev->irq, dev); + /* Free RX buffer */ - for (i = 0; i < RX_DCNT; i++) { - if (lp->rx_insert_ptr->skb_ptr) { - pci_unmap_single(lp->pdev, lp->rx_insert_ptr->buf, - MAX_BUF_SIZE, PCI_DMA_FROMDEVICE); - dev_kfree_skb(lp->rx_insert_ptr->skb_ptr); - lp->rx_insert_ptr->skb_ptr = NULL; - } - lp->rx_insert_ptr = lp->rx_insert_ptr->vndescp; - } + r6040_free_rxbufs(dev); /* Free TX buffer */ - for (i = 0; i < TX_DCNT; i++) { - if (lp->tx_insert_ptr->skb_ptr) { - pci_unmap_single(lp->pdev, lp->tx_insert_ptr->buf, - MAX_BUF_SIZE, PCI_DMA_TODEVICE); - dev_kfree_skb(lp->tx_insert_ptr->skb_ptr); - lp->rx_insert_ptr->skb_ptr = NULL; - } - lp->tx_insert_ptr = lp->tx_insert_ptr->vndescp; - } + r6040_free_txbufs(dev); /* Free Descriptor memory */ pci_free_consistent(pdev, RX_DESC_SIZE, lp->rx_ring, lp->rx_ring_dma); @@ -432,19 +506,24 @@ static int r6040_rx(struct net_device *dev, int limit) /* Check for errors */ err = ioread16(ioaddr + MLSR); - if (err & 0x0400) priv->stats.rx_errors++; + if (err & 0x0400) + dev->stats.rx_errors++; /* RX FIFO over-run */ - if (err & 0x8000) priv->stats.rx_fifo_errors++; + if (err & 0x8000) + dev->stats.rx_fifo_errors++; /* RX descriptor unavailable */ - if (err & 0x0080) priv->stats.rx_frame_errors++; + if (err & 0x0080) + dev->stats.rx_frame_errors++; /* Received packet with length over buffer lenght */ - if (err & 0x0020) priv->stats.rx_over_errors++; + if (err & 0x0020) + dev->stats.rx_over_errors++; /* Received packet with too long or short */ - if (err & (0x0010|0x0008)) priv->stats.rx_length_errors++; + if (err & (0x0010 | 0x0008)) + dev->stats.rx_length_errors++; /* Received packet with CRC errors */ if (err & 0x0004) { spin_lock(&priv->lock); - priv->stats.rx_crc_errors++; + dev->stats.rx_crc_errors++; spin_unlock(&priv->lock); } @@ -469,8 +548,8 @@ static int r6040_rx(struct net_device *dev, int limit) /* Send to upper layer */ netif_receive_skb(skb_ptr); dev->last_rx = jiffies; - priv->dev->stats.rx_packets++; - priv->dev->stats.rx_bytes += descptr->len; + dev->stats.rx_packets++; + dev->stats.rx_bytes += descptr->len; /* To next descriptor */ descptr = descptr->vndescp; priv->rx_free_desc--; @@ -498,11 +577,13 @@ static void r6040_tx(struct net_device *dev) /* Check for errors */ err = ioread16(ioaddr + MLSR); - if (err & 0x0200) priv->stats.rx_fifo_errors++; - if (err & (0x2000 | 0x4000)) priv->stats.tx_carrier_errors++; + if (err & 0x0200) + dev->stats.rx_fifo_errors++; + if (err & (0x2000 | 0x4000)) + dev->stats.tx_carrier_errors++; if (descptr->status & 0x8000) - break; /* Not complte */ + break; /* Not complete */ skb_ptr = descptr->skb_ptr; pci_unmap_single(priv->pdev, descptr->buf, skb_ptr->len, PCI_DMA_TODEVICE); @@ -545,7 +626,6 @@ static irqreturn_t r6040_interrupt(int irq, void *dev_id) struct r6040_private *lp = netdev_priv(dev); void __iomem *ioaddr = lp->base; u16 status; - int handled = 1; /* Mask off RDC MAC interrupt */ iowrite16(MSK_INT, ioaddr + MIER); @@ -565,7 +645,7 @@ static irqreturn_t r6040_interrupt(int irq, void *dev_id) if (status & 0x10) r6040_tx(dev); - return IRQ_RETVAL(handled); + return IRQ_HANDLED; } #ifdef CONFIG_NET_POLL_CONTROLLER @@ -577,53 +657,15 @@ static void r6040_poll_controller(struct net_device *dev) } #endif -static void r6040_init_ring_desc(struct r6040_descriptor *desc_ring, - dma_addr_t desc_dma, int size) -{ - struct r6040_descriptor *desc = desc_ring; - dma_addr_t mapping = desc_dma; - - while (size-- > 0) { - mapping += sizeof(sizeof(*desc)); - desc->ndesc = cpu_to_le32(mapping); - desc->vndescp = desc + 1; - desc++; - } - desc--; - desc->ndesc = cpu_to_le32(desc_dma); - desc->vndescp = desc_ring; -} - /* Init RDC MAC */ static void r6040_up(struct net_device *dev) { struct r6040_private *lp = netdev_priv(dev); void __iomem *ioaddr = lp->base; - /* Initialize */ - lp->tx_free_desc = TX_DCNT; - lp->rx_free_desc = 0; - /* Init descriptor */ - lp->tx_remove_ptr = lp->tx_insert_ptr = lp->tx_ring; - lp->rx_remove_ptr = lp->rx_insert_ptr = lp->rx_ring; - /* Init TX descriptor */ - r6040_init_ring_desc(lp->tx_ring, lp->tx_ring_dma, TX_DCNT); - - /* Init RX descriptor */ - r6040_init_ring_desc(lp->rx_ring, lp->rx_ring_dma, RX_DCNT); - - /* Allocate buffer for RX descriptor */ - rx_buf_alloc(lp, dev); - - /* - * TX and RX descriptor start registers. - * Lower 16-bits to MxD_SA0. Higher 16-bits to MxD_SA1. - */ - iowrite16(lp->tx_ring_dma, ioaddr + MTD_SA0); - iowrite16(lp->tx_ring_dma >> 16, ioaddr + MTD_SA1); - - iowrite16(lp->rx_ring_dma, ioaddr + MRD_SA0); - iowrite16(lp->rx_ring_dma >> 16, ioaddr + MRD_SA1); + /* Initialise and alloc RX/TX buffers */ + r6040_alloc_txbufs(dev); + r6040_alloc_rxbufs(dev); /* Buffer Size Register */ iowrite16(MAX_BUF_SIZE, ioaddr + MR_BSR); @@ -689,8 +731,7 @@ static void r6040_timer(unsigned long data) } /* Timer active again */ - lp->timer.expires = TIMER_WUT; - add_timer(&lp->timer); + mod_timer(&lp->timer, jiffies + round_jiffies(HZ)); } /* Read/set MAC address routines */ @@ -746,14 +787,10 @@ static int r6040_open(struct net_device *dev) napi_enable(&lp->napi); netif_start_queue(dev); - if (lp->switch_sig != ICPLUS_PHY_ID) { - /* set and active a timer process */ - init_timer(&lp->timer); - lp->timer.expires = TIMER_WUT; - lp->timer.data = (unsigned long)dev; - lp->timer.function = &r6040_timer; - add_timer(&lp->timer); - } + /* set and active a timer process */ + setup_timer(&lp->timer, r6040_timer, (unsigned long) dev); + if (lp->switch_sig != ICPLUS_PHY_ID) + mod_timer(&lp->timer, jiffies + HZ); return 0; } diff --git a/drivers/net/sis190.c b/drivers/net/sis190.c index 2e9e88be7b3..202fdf35662 100644 --- a/drivers/net/sis190.c +++ b/drivers/net/sis190.c @@ -1630,7 +1630,8 @@ static inline void sis190_init_rxfilter(struct net_device *dev) SIS_PCI_COMMIT(); } -static int sis190_get_mac_addr(struct pci_dev *pdev, struct net_device *dev) +static int __devinit sis190_get_mac_addr(struct pci_dev *pdev, + struct net_device *dev) { u8 from; diff --git a/drivers/net/tsi108_eth.c b/drivers/net/tsi108_eth.c index 35d15e85007..6f33f84d37b 100644 --- a/drivers/net/tsi108_eth.c +++ b/drivers/net/tsi108_eth.c @@ -36,6 +36,7 @@ #include <linux/net.h> #include <linux/netdevice.h> #include <linux/etherdevice.h> +#include <linux/ethtool.h> #include <linux/skbuff.h> #include <linux/slab.h> #include <linux/spinlock.h> @@ -297,18 +298,11 @@ static void tsi108_check_phy(struct net_device *dev) u32 speed; unsigned long flags; - /* Do a dummy read, as for some reason the first read - * after a link becomes up returns link down, even if - * it's been a while since the link came up. - */ - spin_lock_irqsave(&phy_lock, flags); if (!data->phy_ok) goto out; - tsi108_read_mii(data, MII_BMSR); - duplex = mii_check_media(&data->mii_if, netif_msg_link(data), data->init_media); data->init_media = 0; @@ -345,22 +339,21 @@ static void tsi108_check_phy(struct net_device *dev) TSI_WRITE(TSI108_MAC_CFG2, mac_cfg2_reg); TSI_WRITE(TSI108_EC_PORTCTRL, portctrl_reg); + } - if (data->link_up == 0) { - /* The manual says it can take 3-4 usecs for the speed change - * to take effect. - */ - udelay(5); + if (data->link_up == 0) { + /* The manual says it can take 3-4 usecs for the speed change + * to take effect. + */ + udelay(5); - spin_lock(&data->txlock); - if (is_valid_ether_addr(dev->dev_addr) && data->txfree) - netif_wake_queue(dev); + spin_lock(&data->txlock); + if (is_valid_ether_addr(dev->dev_addr) && data->txfree) + netif_wake_queue(dev); - data->link_up = 1; - spin_unlock(&data->txlock); - } + data->link_up = 1; + spin_unlock(&data->txlock); } - } else { if (data->link_up == 1) { netif_stop_queue(dev); @@ -1274,12 +1267,11 @@ static void tsi108_init_phy(struct net_device *dev) * PHY_STAT register before the link up status bit is set. */ - data->link_up = 1; + data->link_up = 0; while (!((phyval = tsi108_read_mii(data, MII_BMSR)) & BMSR_LSTATUS)) { if (i++ > (MII_READ_DELAY / 10)) { - data->link_up = 0; break; } spin_unlock_irqrestore(&phy_lock, flags); @@ -1287,6 +1279,7 @@ static void tsi108_init_phy(struct net_device *dev) spin_lock_irqsave(&phy_lock, flags); } + data->mii_if.supports_gmii = mii_check_gmii_support(&data->mii_if); printk(KERN_DEBUG "PHY_STAT reg contains %08x\n", phyval); data->phy_ok = 1; data->init_media = 1; @@ -1527,12 +1520,46 @@ static void tsi108_init_mac(struct net_device *dev) TSI_WRITE(TSI108_EC_INTMASK, ~0); } +static int tsi108_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) +{ + struct tsi108_prv_data *data = netdev_priv(dev); + unsigned long flags; + int rc; + + spin_lock_irqsave(&data->txlock, flags); + rc = mii_ethtool_gset(&data->mii_if, cmd); + spin_unlock_irqrestore(&data->txlock, flags); + + return rc; +} + +static int tsi108_set_settings(struct net_device *dev, struct ethtool_cmd *cmd) +{ + struct tsi108_prv_data *data = netdev_priv(dev); + unsigned long flags; + int rc; + + spin_lock_irqsave(&data->txlock, flags); + rc = mii_ethtool_sset(&data->mii_if, cmd); + spin_unlock_irqrestore(&data->txlock, flags); + + return rc; +} + static int tsi108_do_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) { struct tsi108_prv_data *data = netdev_priv(dev); + if (!netif_running(dev)) + return -EINVAL; return generic_mii_ioctl(&data->mii_if, if_mii(rq), cmd, NULL); } +static const struct ethtool_ops tsi108_ethtool_ops = { + .get_link = ethtool_op_get_link, + .get_settings = tsi108_get_settings, + .set_settings = tsi108_set_settings, +}; + static int tsi108_init_one(struct platform_device *pdev) { @@ -1584,7 +1611,6 @@ tsi108_init_one(struct platform_device *pdev) data->mii_if.phy_id = einfo->phy; data->mii_if.phy_id_mask = 0x1f; data->mii_if.reg_num_mask = 0x1f; - data->mii_if.supports_gmii = mii_check_gmii_support(&data->mii_if); data->phy = einfo->phy; data->phy_type = einfo->phy_type; @@ -1598,6 +1624,7 @@ tsi108_init_one(struct platform_device *pdev) dev->get_stats = tsi108_get_stats; netif_napi_add(dev, &data->napi, tsi108_poll, 64); dev->do_ioctl = tsi108_do_ioctl; + dev->ethtool_ops = &tsi108_ethtool_ops; /* Apparently, the Linux networking code won't use scatter-gather * if the hardware doesn't do checksums. However, it's faster @@ -1629,6 +1656,7 @@ tsi108_init_one(struct platform_device *pdev) goto register_fail; } + platform_set_drvdata(pdev, dev); printk(KERN_INFO "%s: Tsi108 Gigabit Ethernet, MAC: %s\n", dev->name, print_mac(mac, dev->dev_addr)); #ifdef DEBUG diff --git a/drivers/net/wireless/ath5k/base.c b/drivers/net/wireless/ath5k/base.c index ddc87149fe3..dfdaec02073 100644 --- a/drivers/net/wireless/ath5k/base.c +++ b/drivers/net/wireless/ath5k/base.c @@ -1256,7 +1256,7 @@ ath5k_txbuf_setup(struct ath5k_softc *sc, struct ath5k_buf *bf, if (ctl->flags & IEEE80211_TXCTL_NO_ACK) flags |= AR5K_TXDESC_NOACK; - pktlen = skb->len + FCS_LEN; + pktlen = skb->len; if (!(ctl->flags & IEEE80211_TXCTL_DO_NOT_ENCRYPT)) { keyidx = ctl->key_idx; @@ -1952,7 +1952,7 @@ ath5k_beacon_setup(struct ath5k_softc *sc, struct ath5k_buf *bf, } ds->ds_data = bf->skbaddr; - ret = ah->ah_setup_tx_desc(ah, ds, skb->len + FCS_LEN, + ret = ah->ah_setup_tx_desc(ah, ds, skb->len, ieee80211_get_hdrlen_from_skb(skb), AR5K_PKT_TYPE_BEACON, (ctl->power_level * 2), ctl->tx_rate, 1, AR5K_TXKEYIX_INVALID, antenna, flags, 0, 0); diff --git a/drivers/net/wireless/ath5k/hw.c b/drivers/net/wireless/ath5k/hw.c index 3a4bf4035a2..1ab57aa6e4d 100644 --- a/drivers/net/wireless/ath5k/hw.c +++ b/drivers/net/wireless/ath5k/hw.c @@ -3506,7 +3506,7 @@ ath5k_hw_setup_2word_tx_desc(struct ath5k_hw *ah, struct ath5k_desc *desc, { u32 frame_type; struct ath5k_hw_2w_tx_desc *tx_desc; - unsigned int buff_len; + unsigned int frame_len; tx_desc = (struct ath5k_hw_2w_tx_desc *)&desc->ds_ctl0; @@ -3537,22 +3537,25 @@ ath5k_hw_setup_2word_tx_desc(struct ath5k_hw *ah, struct ath5k_desc *desc, /* Setup control descriptor */ /* Verify and set frame length */ - if (pkt_len & ~AR5K_2W_TX_DESC_CTL0_FRAME_LEN) + + /* remove padding we might have added before */ + frame_len = pkt_len - (hdr_len & 3) + FCS_LEN; + + if (frame_len & ~AR5K_2W_TX_DESC_CTL0_FRAME_LEN) return -EINVAL; - tx_desc->tx_control_0 = pkt_len & AR5K_2W_TX_DESC_CTL0_FRAME_LEN; + tx_desc->tx_control_0 = frame_len & AR5K_2W_TX_DESC_CTL0_FRAME_LEN; /* Verify and set buffer length */ - buff_len = pkt_len - FCS_LEN; /* NB: beacon's BufLen must be a multiple of 4 bytes */ if(type == AR5K_PKT_TYPE_BEACON) - buff_len = roundup(buff_len, 4); + pkt_len = roundup(pkt_len, 4); - if (buff_len & ~AR5K_2W_TX_DESC_CTL1_BUF_LEN) + if (pkt_len & ~AR5K_2W_TX_DESC_CTL1_BUF_LEN) return -EINVAL; - tx_desc->tx_control_1 = buff_len & AR5K_2W_TX_DESC_CTL1_BUF_LEN; + tx_desc->tx_control_1 = pkt_len & AR5K_2W_TX_DESC_CTL1_BUF_LEN; /* * Verify and set header length @@ -3634,7 +3637,7 @@ static int ath5k_hw_setup_4word_tx_desc(struct ath5k_hw *ah, { struct ath5k_hw_4w_tx_desc *tx_desc; struct ath5k_hw_tx_status *tx_status; - unsigned int buff_len; + unsigned int frame_len; ATH5K_TRACE(ah->ah_sc); tx_desc = (struct ath5k_hw_4w_tx_desc *)&desc->ds_ctl0; @@ -3669,22 +3672,25 @@ static int ath5k_hw_setup_4word_tx_desc(struct ath5k_hw *ah, /* Setup control descriptor */ /* Verify and set frame length */ - if (pkt_len & ~AR5K_4W_TX_DESC_CTL0_FRAME_LEN) + + /* remove padding we might have added before */ + frame_len = pkt_len - (hdr_len & 3) + FCS_LEN; + + if (frame_len & ~AR5K_4W_TX_DESC_CTL0_FRAME_LEN) return -EINVAL; - tx_desc->tx_control_0 = pkt_len & AR5K_4W_TX_DESC_CTL0_FRAME_LEN; + tx_desc->tx_control_0 = frame_len & AR5K_4W_TX_DESC_CTL0_FRAME_LEN; /* Verify and set buffer length */ - buff_len = pkt_len - FCS_LEN; /* NB: beacon's BufLen must be a multiple of 4 bytes */ if(type == AR5K_PKT_TYPE_BEACON) - buff_len = roundup(buff_len, 4); + pkt_len = roundup(pkt_len, 4); - if (buff_len & ~AR5K_4W_TX_DESC_CTL1_BUF_LEN) + if (pkt_len & ~AR5K_4W_TX_DESC_CTL1_BUF_LEN) return -EINVAL; - tx_desc->tx_control_1 = buff_len & AR5K_4W_TX_DESC_CTL1_BUF_LEN; + tx_desc->tx_control_1 = pkt_len & AR5K_4W_TX_DESC_CTL1_BUF_LEN; tx_desc->tx_control_0 |= AR5K_REG_SM(tx_power, AR5K_4W_TX_DESC_CTL0_XMIT_POWER) | diff --git a/drivers/net/wireless/b43/b43.h b/drivers/net/wireless/b43/b43.h index 08a011f0834..f13346ba9dd 100644 --- a/drivers/net/wireless/b43/b43.h +++ b/drivers/net/wireless/b43/b43.h @@ -14,6 +14,12 @@ #include "lo.h" #include "phy.h" + +/* The unique identifier of the firmware that's officially supported by + * this driver version. */ +#define B43_SUPPORTED_FIRMWARE_ID "FW13" + + #ifdef CONFIG_B43_DEBUG # define B43_DEBUG 1 #else diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c index ef65c41af00..51dfce16178 100644 --- a/drivers/net/wireless/b43/main.c +++ b/drivers/net/wireless/b43/main.c @@ -58,6 +58,8 @@ MODULE_AUTHOR("Stefano Brivio"); MODULE_AUTHOR("Michael Buesch"); MODULE_LICENSE("GPL"); +MODULE_FIRMWARE(B43_SUPPORTED_FIRMWARE_ID); + static int modparam_bad_frames_preempt; module_param_named(bad_frames_preempt, modparam_bad_frames_preempt, int, 0444); @@ -1859,11 +1861,11 @@ static int b43_upload_microcode(struct b43_wldev *dev) err = -EOPNOTSUPP; goto error; } - b43dbg(dev->wl, "Loading firmware version %u.%u " - "(20%.2i-%.2i-%.2i %.2i:%.2i:%.2i)\n", - fwrev, fwpatch, - (fwdate >> 12) & 0xF, (fwdate >> 8) & 0xF, fwdate & 0xFF, - (fwtime >> 11) & 0x1F, (fwtime >> 5) & 0x3F, fwtime & 0x1F); + b43info(dev->wl, "Loading firmware version %u.%u " + "(20%.2i-%.2i-%.2i %.2i:%.2i:%.2i)\n", + fwrev, fwpatch, + (fwdate >> 12) & 0xF, (fwdate >> 8) & 0xF, fwdate & 0xFF, + (fwtime >> 11) & 0x1F, (fwtime >> 5) & 0x3F, fwtime & 0x1F); dev->fw.rev = fwrev; dev->fw.patch = fwpatch; @@ -4200,6 +4202,33 @@ static struct ssb_driver b43_ssb_driver = { .resume = b43_resume, }; +static void b43_print_driverinfo(void) +{ + const char *feat_pci = "", *feat_pcmcia = "", *feat_nphy = "", + *feat_leds = "", *feat_rfkill = ""; + +#ifdef CONFIG_B43_PCI_AUTOSELECT + feat_pci = "P"; +#endif +#ifdef CONFIG_B43_PCMCIA + feat_pcmcia = "M"; +#endif +#ifdef CONFIG_B43_NPHY + feat_nphy = "N"; +#endif +#ifdef CONFIG_B43_LEDS + feat_leds = "L"; +#endif +#ifdef CONFIG_B43_RFKILL + feat_rfkill = "R"; +#endif + printk(KERN_INFO "Broadcom 43xx driver loaded " + "[ Features: %s%s%s%s%s, Firmware-ID: " + B43_SUPPORTED_FIRMWARE_ID " ]\n", + feat_pci, feat_pcmcia, feat_nphy, + feat_leds, feat_rfkill); +} + static int __init b43_init(void) { int err; @@ -4211,6 +4240,7 @@ static int __init b43_init(void) err = ssb_driver_register(&b43_ssb_driver); if (err) goto err_pcmcia_exit; + b43_print_driverinfo(); return err; diff --git a/drivers/net/wireless/b43legacy/b43legacy.h b/drivers/net/wireless/b43legacy/b43legacy.h index c80edd2b904..93d45b71799 100644 --- a/drivers/net/wireless/b43legacy/b43legacy.h +++ b/drivers/net/wireless/b43legacy/b43legacy.h @@ -23,6 +23,10 @@ #include "phy.h" +/* The unique identifier of the firmware that's officially supported by this + * driver version. */ +#define B43legacy_SUPPORTED_FIRMWARE_ID "FW10" + #define B43legacy_IRQWAIT_MAX_RETRIES 20 #define B43legacy_RX_MAX_SSI 60 /* best guess at max ssi */ diff --git a/drivers/net/wireless/b43legacy/dma.c b/drivers/net/wireless/b43legacy/dma.c index 6e08405e802..e87b427d5e4 100644 --- a/drivers/net/wireless/b43legacy/dma.c +++ b/drivers/net/wireless/b43legacy/dma.c @@ -354,7 +354,8 @@ return 0; } -u16 b43legacy_dmacontroller_base(int dma64bit, int controller_idx) +static u16 b43legacy_dmacontroller_base(enum b43legacy_dmatype type, + int controller_idx) { static const u16 map64[] = { B43legacy_MMIO_DMA64_BASE0, @@ -373,7 +374,7 @@ u16 b43legacy_dmacontroller_base(int dma64bit, int controller_idx) B43legacy_MMIO_DMA32_BASE5, }; - if (dma64bit) { + if (type == B43legacy_DMA_64BIT) { B43legacy_WARN_ON(!(controller_idx >= 0 && controller_idx < ARRAY_SIZE(map64))); return map64[controller_idx]; @@ -480,8 +481,9 @@ static void free_ringmemory(struct b43legacy_dmaring *ring) } /* Reset the RX DMA channel */ -int b43legacy_dmacontroller_rx_reset(struct b43legacy_wldev *dev, - u16 mmio_base, int dma64) +static int b43legacy_dmacontroller_rx_reset(struct b43legacy_wldev *dev, + u16 mmio_base, + enum b43legacy_dmatype type) { int i; u32 value; @@ -489,13 +491,14 @@ int b43legacy_dmacontroller_rx_reset(struct b43legacy_wldev *dev, might_sleep(); - offset = dma64 ? B43legacy_DMA64_RXCTL : B43legacy_DMA32_RXCTL; + offset = (type == B43legacy_DMA_64BIT) ? + B43legacy_DMA64_RXCTL : B43legacy_DMA32_RXCTL; b43legacy_write32(dev, mmio_base + offset, 0); for (i = 0; i < 10; i++) { - offset = dma64 ? B43legacy_DMA64_RXSTATUS : - B43legacy_DMA32_RXSTATUS; + offset = (type == B43legacy_DMA_64BIT) ? + B43legacy_DMA64_RXSTATUS : B43legacy_DMA32_RXSTATUS; value = b43legacy_read32(dev, mmio_base + offset); - if (dma64) { + if (type == B43legacy_DMA_64BIT) { value &= B43legacy_DMA64_RXSTAT; if (value == B43legacy_DMA64_RXSTAT_DISABLED) { i = -1; @@ -519,8 +522,9 @@ int b43legacy_dmacontroller_rx_reset(struct b43legacy_wldev *dev, } /* Reset the RX DMA channel */ -int b43legacy_dmacontroller_tx_reset(struct b43legacy_wldev *dev, - u16 mmio_base, int dma64) +static int b43legacy_dmacontroller_tx_reset(struct b43legacy_wldev *dev, + u16 mmio_base, + enum b43legacy_dmatype type) { int i; u32 value; @@ -529,10 +533,10 @@ int b43legacy_dmacontroller_tx_reset(struct b43legacy_wldev *dev, might_sleep(); for (i = 0; i < 10; i++) { - offset = dma64 ? B43legacy_DMA64_TXSTATUS : - B43legacy_DMA32_TXSTATUS; + offset = (type == B43legacy_DMA_64BIT) ? + B43legacy_DMA64_TXSTATUS : B43legacy_DMA32_TXSTATUS; value = b43legacy_read32(dev, mmio_base + offset); - if (dma64) { + if (type == B43legacy_DMA_64BIT) { value &= B43legacy_DMA64_TXSTAT; if (value == B43legacy_DMA64_TXSTAT_DISABLED || value == B43legacy_DMA64_TXSTAT_IDLEWAIT || @@ -547,13 +551,14 @@ int b43legacy_dmacontroller_tx_reset(struct b43legacy_wldev *dev, } msleep(1); } - offset = dma64 ? B43legacy_DMA64_TXCTL : B43legacy_DMA32_TXCTL; + offset = (type == B43legacy_DMA_64BIT) ? B43legacy_DMA64_TXCTL : + B43legacy_DMA32_TXCTL; b43legacy_write32(dev, mmio_base + offset, 0); for (i = 0; i < 10; i++) { - offset = dma64 ? B43legacy_DMA64_TXSTATUS : - B43legacy_DMA32_TXSTATUS; + offset = (type == B43legacy_DMA_64BIT) ? + B43legacy_DMA64_TXSTATUS : B43legacy_DMA32_TXSTATUS; value = b43legacy_read32(dev, mmio_base + offset); - if (dma64) { + if (type == B43legacy_DMA_64BIT) { value &= B43legacy_DMA64_TXSTAT; if (value == B43legacy_DMA64_TXSTAT_DISABLED) { i = -1; @@ -578,6 +583,32 @@ int b43legacy_dmacontroller_tx_reset(struct b43legacy_wldev *dev, return 0; } +/* Check if a DMA mapping address is invalid. */ +static bool b43legacy_dma_mapping_error(struct b43legacy_dmaring *ring, + dma_addr_t addr, + size_t buffersize) +{ + if (unlikely(dma_mapping_error(addr))) + return 1; + + switch (ring->type) { + case B43legacy_DMA_30BIT: + if ((u64)addr + buffersize > (1ULL << 30)) + return 1; + break; + case B43legacy_DMA_32BIT: + if ((u64)addr + buffersize > (1ULL << 32)) + return 1; + break; + case B43legacy_DMA_64BIT: + /* Currently we can't have addresses beyond 64 bits in the kernel. */ + break; + } + + /* The address is OK. */ + return 0; +} + static int setup_rx_descbuffer(struct b43legacy_dmaring *ring, struct b43legacy_dmadesc_generic *desc, struct b43legacy_dmadesc_meta *meta, @@ -595,7 +626,7 @@ static int setup_rx_descbuffer(struct b43legacy_dmaring *ring, return -ENOMEM; dmaaddr = map_descbuffer(ring, skb->data, ring->rx_buffersize, 0); - if (dma_mapping_error(dmaaddr)) { + if (b43legacy_dma_mapping_error(ring, dmaaddr, ring->rx_buffersize)) { /* ugh. try to realloc in zone_dma */ gfp_flags |= GFP_DMA; @@ -608,7 +639,7 @@ static int setup_rx_descbuffer(struct b43legacy_dmaring *ring, ring->rx_buffersize, 0); } - if (dma_mapping_error(dmaaddr)) { + if (b43legacy_dma_mapping_error(ring, dmaaddr, ring->rx_buffersize)) { dev_kfree_skb_any(skb); return -EIO; } @@ -674,7 +705,7 @@ static int dmacontroller_setup(struct b43legacy_dmaring *ring) u32 trans = ssb_dma_translation(ring->dev->dev); if (ring->tx) { - if (ring->dma64) { + if (ring->type == B43legacy_DMA_64BIT) { u64 ringbase = (u64)(ring->dmabase); addrext = ((ringbase >> 32) & SSB_DMA_TRANSLATION_MASK) @@ -709,7 +740,7 @@ static int dmacontroller_setup(struct b43legacy_dmaring *ring) err = alloc_initial_descbuffers(ring); if (err) goto out; - if (ring->dma64) { + if (ring->type == B43legacy_DMA_64BIT) { u64 ringbase = (u64)(ring->dmabase); addrext = ((ringbase >> 32) & SSB_DMA_TRANSLATION_MASK) @@ -760,16 +791,16 @@ static void dmacontroller_cleanup(struct b43legacy_dmaring *ring) { if (ring->tx) { b43legacy_dmacontroller_tx_reset(ring->dev, ring->mmio_base, - ring->dma64); - if (ring->dma64) { + ring->type); + if (ring->type == B43legacy_DMA_64BIT) { b43legacy_dma_write(ring, B43legacy_DMA64_TXRINGLO, 0); b43legacy_dma_write(ring, B43legacy_DMA64_TXRINGHI, 0); } else b43legacy_dma_write(ring, B43legacy_DMA32_TXRING, 0); } else { b43legacy_dmacontroller_rx_reset(ring->dev, ring->mmio_base, - ring->dma64); - if (ring->dma64) { + ring->type); + if (ring->type == B43legacy_DMA_64BIT) { b43legacy_dma_write(ring, B43legacy_DMA64_RXRINGLO, 0); b43legacy_dma_write(ring, B43legacy_DMA64_RXRINGHI, 0); } else @@ -824,11 +855,10 @@ static u64 supported_dma_mask(struct b43legacy_wldev *dev) /* Main initialization function. */ static -struct b43legacy_dmaring *b43legacy_setup_dmaring( - struct b43legacy_wldev *dev, - int controller_index, - int for_tx, - int dma64) +struct b43legacy_dmaring *b43legacy_setup_dmaring(struct b43legacy_wldev *dev, + int controller_index, + int for_tx, + enum b43legacy_dmatype type) { struct b43legacy_dmaring *ring; int err; @@ -838,6 +868,7 @@ struct b43legacy_dmaring *b43legacy_setup_dmaring( ring = kzalloc(sizeof(*ring), GFP_KERNEL); if (!ring) goto out; + ring->type = type; nr_slots = B43legacy_RXRING_SLOTS; if (for_tx) @@ -855,12 +886,12 @@ struct b43legacy_dmaring *b43legacy_setup_dmaring( goto err_kfree_meta; /* test for ability to dma to txhdr_cache */ - dma_test = dma_map_single(dev->dev->dev, - ring->txhdr_cache, - sizeof(struct b43legacy_txhdr_fw3), - DMA_TO_DEVICE); + dma_test = dma_map_single(dev->dev->dev, ring->txhdr_cache, + sizeof(struct b43legacy_txhdr_fw3), + DMA_TO_DEVICE); - if (dma_mapping_error(dma_test)) { + if (b43legacy_dma_mapping_error(ring, dma_test, + sizeof(struct b43legacy_txhdr_fw3))) { /* ugh realloc */ kfree(ring->txhdr_cache); ring->txhdr_cache = kcalloc(nr_slots, @@ -874,7 +905,8 @@ struct b43legacy_dmaring *b43legacy_setup_dmaring( sizeof(struct b43legacy_txhdr_fw3), DMA_TO_DEVICE); - if (dma_mapping_error(dma_test)) + if (b43legacy_dma_mapping_error(ring, dma_test, + sizeof(struct b43legacy_txhdr_fw3))) goto err_kfree_txhdr_cache; } @@ -885,11 +917,9 @@ struct b43legacy_dmaring *b43legacy_setup_dmaring( ring->dev = dev; ring->nr_slots = nr_slots; - ring->mmio_base = b43legacy_dmacontroller_base(dma64, - controller_index); + ring->mmio_base = b43legacy_dmacontroller_base(type, controller_index); ring->index = controller_index; - ring->dma64 = !!dma64; - if (dma64) + if (type == B43legacy_DMA_64BIT) ring->ops = &dma64_ops; else ring->ops = &dma32_ops; @@ -939,10 +969,10 @@ static void b43legacy_destroy_dmaring(struct b43legacy_dmaring *ring) if (!ring) return; - b43legacydbg(ring->dev->wl, "DMA-%s 0x%04X (%s) max used slots:" - " %d/%d\n", (ring->dma64) ? "64" : "32", ring->mmio_base, - (ring->tx) ? "TX" : "RX", - ring->max_used_slots, ring->nr_slots); + b43legacydbg(ring->dev->wl, "DMA-%u 0x%04X (%s) max used slots:" + " %d/%d\n", (unsigned int)(ring->type), ring->mmio_base, + (ring->tx) ? "TX" : "RX", ring->max_used_slots, + ring->nr_slots); /* Device IRQs are disabled prior entering this function, * so no need to take care of concurrency with rx handler stuff. */ @@ -988,11 +1018,22 @@ int b43legacy_dma_init(struct b43legacy_wldev *dev) struct b43legacy_dmaring *ring; int err; u64 dmamask; - int dma64 = 0; + enum b43legacy_dmatype type; dmamask = supported_dma_mask(dev); - if (dmamask == DMA_64BIT_MASK) - dma64 = 1; + switch (dmamask) { + default: + B43legacy_WARN_ON(1); + case DMA_30BIT_MASK: + type = B43legacy_DMA_30BIT; + break; + case DMA_32BIT_MASK: + type = B43legacy_DMA_32BIT; + break; + case DMA_64BIT_MASK: + type = B43legacy_DMA_64BIT; + break; + } err = ssb_dma_set_mask(dev->dev, dmamask); if (err) { @@ -1010,52 +1051,50 @@ int b43legacy_dma_init(struct b43legacy_wldev *dev) err = -ENOMEM; /* setup TX DMA channels. */ - ring = b43legacy_setup_dmaring(dev, 0, 1, dma64); + ring = b43legacy_setup_dmaring(dev, 0, 1, type); if (!ring) goto out; dma->tx_ring0 = ring; - ring = b43legacy_setup_dmaring(dev, 1, 1, dma64); + ring = b43legacy_setup_dmaring(dev, 1, 1, type); if (!ring) goto err_destroy_tx0; dma->tx_ring1 = ring; - ring = b43legacy_setup_dmaring(dev, 2, 1, dma64); + ring = b43legacy_setup_dmaring(dev, 2, 1, type); if (!ring) goto err_destroy_tx1; dma->tx_ring2 = ring; - ring = b43legacy_setup_dmaring(dev, 3, 1, dma64); + ring = b43legacy_setup_dmaring(dev, 3, 1, type); if (!ring) goto err_destroy_tx2; dma->tx_ring3 = ring; - ring = b43legacy_setup_dmaring(dev, 4, 1, dma64); + ring = b43legacy_setup_dmaring(dev, 4, 1, type); if (!ring) goto err_destroy_tx3; dma->tx_ring4 = ring; - ring = b43legacy_setup_dmaring(dev, 5, 1, dma64); + ring = b43legacy_setup_dmaring(dev, 5, 1, type); if (!ring) goto err_destroy_tx4; dma->tx_ring5 = ring; /* setup RX DMA channels. */ - ring = b43legacy_setup_dmaring(dev, 0, 0, dma64); + ring = b43legacy_setup_dmaring(dev, 0, 0, type); if (!ring) goto err_destroy_tx5; dma->rx_ring0 = ring; if (dev->dev->id.revision < 5) { - ring = b43legacy_setup_dmaring(dev, 3, 0, dma64); + ring = b43legacy_setup_dmaring(dev, 3, 0, type); if (!ring) goto err_destroy_rx0; dma->rx_ring3 = ring; } - b43legacydbg(dev->wl, "%d-bit DMA initialized\n", - (dmamask == DMA_64BIT_MASK) ? 64 : - (dmamask == DMA_32BIT_MASK) ? 32 : 30); + b43legacydbg(dev->wl, "%u-bit DMA initialized\n", (unsigned int)type); err = 0; out: return err; @@ -1194,9 +1233,13 @@ static int dma_tx_fragment(struct b43legacy_dmaring *ring, } meta_hdr->dmaaddr = map_descbuffer(ring, (unsigned char *)header, - sizeof(struct b43legacy_txhdr_fw3), 1); - if (dma_mapping_error(meta_hdr->dmaaddr)) + sizeof(struct b43legacy_txhdr_fw3), 1); + if (b43legacy_dma_mapping_error(ring, meta_hdr->dmaaddr, + sizeof(struct b43legacy_txhdr_fw3))) { + ring->current_slot = old_top_slot; + ring->used_slots = old_used_slots; return -EIO; + } ops->fill_descriptor(ring, desc, meta_hdr->dmaaddr, sizeof(struct b43legacy_txhdr_fw3), 1, 0, 0); @@ -1211,7 +1254,7 @@ static int dma_tx_fragment(struct b43legacy_dmaring *ring, meta->dmaaddr = map_descbuffer(ring, skb->data, skb->len, 1); /* create a bounce buffer in zone_dma on mapping failure. */ - if (dma_mapping_error(meta->dmaaddr)) { + if (b43legacy_dma_mapping_error(ring, meta->dmaaddr, skb->len)) { bounce_skb = __dev_alloc_skb(skb->len, GFP_ATOMIC | GFP_DMA); if (!bounce_skb) { ring->current_slot = old_top_slot; @@ -1225,7 +1268,7 @@ static int dma_tx_fragment(struct b43legacy_dmaring *ring, skb = bounce_skb; meta->skb = skb; meta->dmaaddr = map_descbuffer(ring, skb->data, skb->len, 1); - if (dma_mapping_error(meta->dmaaddr)) { + if (b43legacy_dma_mapping_error(ring, meta->dmaaddr, skb->len)) { ring->current_slot = old_top_slot; ring->used_slots = old_used_slots; err = -EIO; diff --git a/drivers/net/wireless/b43legacy/dma.h b/drivers/net/wireless/b43legacy/dma.h index 26f6ab08de7..2dd488c5be2 100644 --- a/drivers/net/wireless/b43legacy/dma.h +++ b/drivers/net/wireless/b43legacy/dma.h @@ -218,6 +218,12 @@ struct b43legacy_dma_ops { void (*set_current_rxslot)(struct b43legacy_dmaring *ring, int slot); }; +enum b43legacy_dmatype { + B43legacy_DMA_30BIT = 30, + B43legacy_DMA_32BIT = 32, + B43legacy_DMA_64BIT = 64, +}; + struct b43legacy_dmaring { /* Lowlevel DMA ops. */ const struct b43legacy_dma_ops *ops; @@ -250,8 +256,8 @@ struct b43legacy_dmaring { int index; /* Boolean. Is this a TX ring? */ bool tx; - /* Boolean. 64bit DMA if true, 32bit DMA otherwise. */ - bool dma64; + /* The type of DMA engine used. */ + enum b43legacy_dmatype type; /* Boolean. Is this ring stopped at ieee80211 level? */ bool stopped; /* Lock, only used for TX. */ @@ -284,15 +290,6 @@ void b43legacy_dma_write(struct b43legacy_dmaring *ring, int b43legacy_dma_init(struct b43legacy_wldev *dev); void b43legacy_dma_free(struct b43legacy_wldev *dev); -int b43legacy_dmacontroller_rx_reset(struct b43legacy_wldev *dev, - u16 dmacontroller_mmio_base, - int dma64); -int b43legacy_dmacontroller_tx_reset(struct b43legacy_wldev *dev, - u16 dmacontroller_mmio_base, - int dma64); - -u16 b43legacy_dmacontroller_base(int dma64bit, int dmacontroller_idx); - void b43legacy_dma_tx_suspend(struct b43legacy_wldev *dev); void b43legacy_dma_tx_resume(struct b43legacy_wldev *dev); @@ -320,20 +317,6 @@ void b43legacy_dma_free(struct b43legacy_wldev *dev) { } static inline -int b43legacy_dmacontroller_rx_reset(struct b43legacy_wldev *dev, - u16 dmacontroller_mmio_base, - int dma64) -{ - return 0; -} -static inline -int b43legacy_dmacontroller_tx_reset(struct b43legacy_wldev *dev, - u16 dmacontroller_mmio_base, - int dma64) -{ - return 0; -} -static inline void b43legacy_dma_get_tx_stats(struct b43legacy_wldev *dev, struct ieee80211_tx_queue_stats *stats) { diff --git a/drivers/net/wireless/b43legacy/main.c b/drivers/net/wireless/b43legacy/main.c index 53f7f2e9761..c39de422e22 100644 --- a/drivers/net/wireless/b43legacy/main.c +++ b/drivers/net/wireless/b43legacy/main.c @@ -3,7 +3,7 @@ * Broadcom B43legacy wireless driver * * Copyright (c) 2005 Martin Langer <martin-langer@gmx.de> - * Copyright (c) 2005-2007 Stefano Brivio <stefano.brivio@polimi.it> + * Copyright (c) 2005-2008 Stefano Brivio <stefano.brivio@polimi.it> * Copyright (c) 2005, 2006 Michael Buesch <mb@bu3sch.de> * Copyright (c) 2005 Danny van Dyk <kugelfang@gentoo.org> * Copyright (c) 2005 Andreas Jaggi <andreas.jaggi@waterwave.ch> @@ -60,6 +60,8 @@ MODULE_AUTHOR("Stefano Brivio"); MODULE_AUTHOR("Michael Buesch"); MODULE_LICENSE("GPL"); +MODULE_FIRMWARE(B43legacy_SUPPORTED_FIRMWARE_ID); + #if defined(CONFIG_B43LEGACY_DMA) && defined(CONFIG_B43LEGACY_PIO) static int modparam_pio; module_param_named(pio, modparam_pio, int, 0444); @@ -1640,10 +1642,11 @@ static int b43legacy_upload_microcode(struct b43legacy_wldev *dev) err = -EOPNOTSUPP; goto error; } - b43legacydbg(dev->wl, "Loading firmware version 0x%X, patch level %u " - "(20%.2i-%.2i-%.2i %.2i:%.2i:%.2i)\n", fwrev, fwpatch, - (fwdate >> 12) & 0xF, (fwdate >> 8) & 0xF, fwdate & 0xFF, - (fwtime >> 11) & 0x1F, (fwtime >> 5) & 0x3F, fwtime & 0x1F); + b43legacyinfo(dev->wl, "Loading firmware version 0x%X, patch level %u " + "(20%.2i-%.2i-%.2i %.2i:%.2i:%.2i)\n", fwrev, fwpatch, + (fwdate >> 12) & 0xF, (fwdate >> 8) & 0xF, fwdate & 0xFF, + (fwtime >> 11) & 0x1F, (fwtime >> 5) & 0x3F, + fwtime & 0x1F); dev->fw.rev = fwrev; dev->fw.patch = fwpatch; @@ -3806,6 +3809,32 @@ static struct ssb_driver b43legacy_ssb_driver = { .resume = b43legacy_resume, }; +static void b43legacy_print_driverinfo(void) +{ + const char *feat_pci = "", *feat_leds = "", *feat_rfkill = "", + *feat_pio = "", *feat_dma = ""; + +#ifdef CONFIG_B43LEGACY_PCI_AUTOSELECT + feat_pci = "P"; +#endif +#ifdef CONFIG_B43LEGACY_LEDS + feat_leds = "L"; +#endif +#ifdef CONFIG_B43LEGACY_RFKILL + feat_rfkill = "R"; +#endif +#ifdef CONFIG_B43LEGACY_PIO + feat_pio = "I"; +#endif +#ifdef CONFIG_B43LEGACY_DMA + feat_dma = "D"; +#endif + printk(KERN_INFO "Broadcom 43xx driver loaded " + "[ Features: %s%s%s%s%s, Firmware-ID: " + B43legacy_SUPPORTED_FIRMWARE_ID " ]\n", + feat_pci, feat_leds, feat_rfkill, feat_pio, feat_dma); +} + static int __init b43legacy_init(void) { int err; @@ -3816,6 +3845,8 @@ static int __init b43legacy_init(void) if (err) goto err_dfs_exit; + b43legacy_print_driverinfo(); + return err; err_dfs_exit: diff --git a/drivers/net/wireless/ipw2200.c b/drivers/net/wireless/ipw2200.c index 3e6ad7b92c8..a56d9fc6354 100644 --- a/drivers/net/wireless/ipw2200.c +++ b/drivers/net/wireless/ipw2200.c @@ -3365,7 +3365,6 @@ static void ipw_rx_queue_reset(struct ipw_priv *priv, /* Set us so that we have processed and used all buffers, but have * not restocked the Rx queue with fresh buffers */ rxq->read = rxq->write = 0; - rxq->processed = RX_QUEUE_SIZE - 1; rxq->free_count = 0; spin_unlock_irqrestore(&rxq->lock, flags); } @@ -3607,7 +3606,22 @@ static int ipw_load(struct ipw_priv *priv) * Driver allocates buffers of this size for Rx */ -static inline int ipw_queue_space(const struct clx2_queue *q) +/** + * ipw_rx_queue_space - Return number of free slots available in queue. + */ +static int ipw_rx_queue_space(const struct ipw_rx_queue *q) +{ + int s = q->read - q->write; + if (s <= 0) + s += RX_QUEUE_SIZE; + /* keep some buffer to not confuse full and empty queue */ + s -= 2; + if (s < 0) + s = 0; + return s; +} + +static inline int ipw_tx_queue_space(const struct clx2_queue *q) { int s = q->last_used - q->first_empty; if (s <= 0) @@ -4947,7 +4961,7 @@ static int ipw_queue_tx_reclaim(struct ipw_priv *priv, priv->tx_packets++; } done: - if ((ipw_queue_space(q) > q->low_mark) && + if ((ipw_tx_queue_space(q) > q->low_mark) && (qindex >= 0) && (priv->status & STATUS_ASSOCIATED) && netif_running(priv->net_dev)) netif_wake_queue(priv->net_dev); @@ -4965,7 +4979,7 @@ static int ipw_queue_tx_hcmd(struct ipw_priv *priv, int hcmd, void *buf, struct clx2_queue *q = &txq->q; struct tfd_frame *tfd; - if (ipw_queue_space(q) < (sync ? 1 : 2)) { + if (ipw_tx_queue_space(q) < (sync ? 1 : 2)) { IPW_ERROR("No space for Tx\n"); return -EBUSY; } @@ -5070,7 +5084,7 @@ static void ipw_rx_queue_restock(struct ipw_priv *priv) spin_lock_irqsave(&rxq->lock, flags); write = rxq->write; - while ((rxq->write != rxq->processed) && (rxq->free_count)) { + while ((ipw_rx_queue_space(rxq) > 0) && (rxq->free_count)) { element = rxq->rx_free.next; rxb = list_entry(element, struct ipw_rx_mem_buffer, list); list_del(element); @@ -5187,7 +5201,6 @@ static struct ipw_rx_queue *ipw_rx_queue_alloc(struct ipw_priv *priv) /* Set us so that we have processed and used all buffers, but have * not restocked the Rx queue with fresh buffers */ rxq->read = rxq->write = 0; - rxq->processed = RX_QUEUE_SIZE - 1; rxq->free_count = 0; return rxq; @@ -8223,13 +8236,17 @@ static void ipw_rx(struct ipw_priv *priv) struct ieee80211_hdr_4addr *header; u32 r, w, i; u8 network_packet; + u8 fill_rx = 0; DECLARE_MAC_BUF(mac); DECLARE_MAC_BUF(mac2); DECLARE_MAC_BUF(mac3); r = ipw_read32(priv, IPW_RX_READ_INDEX); w = ipw_read32(priv, IPW_RX_WRITE_INDEX); - i = (priv->rxq->processed + 1) % RX_QUEUE_SIZE; + i = priv->rxq->read; + + if (ipw_rx_queue_space (priv->rxq) > (RX_QUEUE_SIZE / 2)) + fill_rx = 1; while (i != r) { rxb = priv->rxq->queue[i]; @@ -8404,11 +8421,17 @@ static void ipw_rx(struct ipw_priv *priv) list_add_tail(&rxb->list, &priv->rxq->rx_used); i = (i + 1) % RX_QUEUE_SIZE; + + /* If there are a lot of unsued frames, restock the Rx queue + * so the ucode won't assert */ + if (fill_rx) { + priv->rxq->read = i; + ipw_rx_queue_replenish(priv); + } } /* Backtrack one entry */ - priv->rxq->processed = (i ? i : RX_QUEUE_SIZE) - 1; - + priv->rxq->read = i; ipw_rx_queue_restock(priv); } @@ -10336,7 +10359,7 @@ static int ipw_tx_skb(struct ipw_priv *priv, struct ieee80211_txb *txb, q->first_empty = ipw_queue_inc_wrap(q->first_empty, q->n_bd); ipw_write32(priv, q->reg_w, q->first_empty); - if (ipw_queue_space(q) < q->high_mark) + if (ipw_tx_queue_space(q) < q->high_mark) netif_stop_queue(priv->net_dev); return NETDEV_TX_OK; @@ -10357,7 +10380,7 @@ static int ipw_net_is_queue_full(struct net_device *dev, int pri) struct clx2_tx_queue *txq = &priv->txq[0]; #endif /* CONFIG_IPW2200_QOS */ - if (ipw_queue_space(&txq->q) < txq->q.high_mark) + if (ipw_tx_queue_space(&txq->q) < txq->q.high_mark) return 1; return 0; diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c index 5ee1ad69898..40b71bc2c4a 100644 --- a/drivers/net/wireless/iwlwifi/iwl3945-base.c +++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c @@ -687,6 +687,12 @@ static int iwl3945_enqueue_hcmd(struct iwl3945_priv *priv, struct iwl3945_host_c BUG_ON((fix_size > TFD_MAX_PAYLOAD_SIZE) && !(cmd->meta.flags & CMD_SIZE_HUGE)); + + if (iwl3945_is_rfkill(priv)) { + IWL_DEBUG_INFO("Not sending command - RF KILL"); + return -EIO; + } + if (iwl3945_queue_space(q) < ((cmd->meta.flags & CMD_ASYNC) ? 2 : 1)) { IWL_ERROR("No space for Tx\n"); return -ENOSPC; @@ -1580,7 +1586,7 @@ static inline int iwl3945_eeprom_acquire_semaphore(struct iwl3945_priv *priv) */ int iwl3945_eeprom_init(struct iwl3945_priv *priv) { - __le16 *e = (__le16 *)&priv->eeprom; + u16 *e = (u16 *)&priv->eeprom; u32 gp = iwl3945_read32(priv, CSR_EEPROM_GP); u32 r; int sz = sizeof(priv->eeprom); @@ -1623,7 +1629,7 @@ int iwl3945_eeprom_init(struct iwl3945_priv *priv) IWL_ERROR("Time out reading EEPROM[%d]", addr); return -ETIMEDOUT; } - e[addr / 2] = cpu_to_le16(r >> 16); + e[addr / 2] = le16_to_cpu((__force __le16)(r >> 16)); } return 0; @@ -2806,7 +2812,8 @@ static int iwl3945_tx_skb(struct iwl3945_priv *priv, #endif /* drop all data frame if we are not associated */ - if ((!iwl3945_is_associated(priv) || !priv->assoc_id) && + if ((!iwl3945_is_associated(priv) || + ((priv->iw_mode == IEEE80211_IF_TYPE_STA) && !priv->assoc_id)) && ((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA)) { IWL_DEBUG_DROP("Dropping - !iwl3945_is_associated\n"); goto drop_unlock; @@ -4281,7 +4288,7 @@ static void iwl3945_rx_handle(struct iwl3945_priv *priv) int reclaim; unsigned long flags; u8 fill_rx = 0; - u32 count = 0; + u32 count = 8; /* uCode's read index (stored in shared DRAM) indicates the last Rx * buffer that the driver may process (last buffer filled by ucode). */ @@ -6256,6 +6263,8 @@ static void __iwl3945_down(struct iwl3945_priv *priv) STATUS_RF_KILL_HW | test_bit(STATUS_RF_KILL_SW, &priv->status) << STATUS_RF_KILL_SW | + test_bit(STATUS_GEO_CONFIGURED, &priv->status) << + STATUS_GEO_CONFIGURED | test_bit(STATUS_IN_SUSPEND, &priv->status) << STATUS_IN_SUSPEND; goto exit; @@ -6267,6 +6276,8 @@ static void __iwl3945_down(struct iwl3945_priv *priv) STATUS_RF_KILL_HW | test_bit(STATUS_RF_KILL_SW, &priv->status) << STATUS_RF_KILL_SW | + test_bit(STATUS_GEO_CONFIGURED, &priv->status) << + STATUS_GEO_CONFIGURED | test_bit(STATUS_IN_SUSPEND, &priv->status) << STATUS_IN_SUSPEND | test_bit(STATUS_FW_ERROR, &priv->status) << diff --git a/drivers/net/wireless/iwlwifi/iwl4965-base.c b/drivers/net/wireless/iwlwifi/iwl4965-base.c index f423241b956..a23d4798653 100644 --- a/drivers/net/wireless/iwlwifi/iwl4965-base.c +++ b/drivers/net/wireless/iwlwifi/iwl4965-base.c @@ -692,6 +692,11 @@ static int iwl4965_enqueue_hcmd(struct iwl4965_priv *priv, struct iwl4965_host_c BUG_ON((fix_size > TFD_MAX_PAYLOAD_SIZE) && !(cmd->meta.flags & CMD_SIZE_HUGE)); + if (iwl4965_is_rfkill(priv)) { + IWL_DEBUG_INFO("Not sending command - RF KILL"); + return -EIO; + } + if (iwl4965_queue_space(q) < ((cmd->meta.flags & CMD_ASYNC) ? 2 : 1)) { IWL_ERROR("No space for Tx\n"); return -ENOSPC; @@ -1654,7 +1659,7 @@ static inline void iwl4965_eeprom_release_semaphore(struct iwl4965_priv *priv) */ int iwl4965_eeprom_init(struct iwl4965_priv *priv) { - __le16 *e = (__le16 *)&priv->eeprom; + u16 *e = (u16 *)&priv->eeprom; u32 gp = iwl4965_read32(priv, CSR_EEPROM_GP); u32 r; int sz = sizeof(priv->eeprom); @@ -1698,7 +1703,7 @@ int iwl4965_eeprom_init(struct iwl4965_priv *priv) rc = -ETIMEDOUT; goto done; } - e[addr / 2] = cpu_to_le16(r >> 16); + e[addr / 2] = le16_to_cpu((__force __le16)(r >> 16)); } rc = 0; @@ -2935,7 +2940,7 @@ static int iwl4965_tx_skb(struct iwl4965_priv *priv, /* drop all data frame if we are not associated */ if (((fc & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA) && (!iwl4965_is_associated(priv) || - !priv->assoc_id || + ((priv->iw_mode == IEEE80211_IF_TYPE_STA) && !priv->assoc_id) || !priv->assoc_station_added)) { IWL_DEBUG_DROP("Dropping - !iwl4965_is_associated\n"); goto drop_unlock; @@ -4664,7 +4669,7 @@ static void iwl4965_rx_handle(struct iwl4965_priv *priv) int reclaim; unsigned long flags; u8 fill_rx = 0; - u32 count = 0; + u32 count = 8; /* uCode's read index (stored in shared DRAM) indicates the last Rx * buffer that the driver may process (last buffer filled by ucode). */ @@ -6680,6 +6685,8 @@ static void __iwl4965_down(struct iwl4965_priv *priv) STATUS_RF_KILL_HW | test_bit(STATUS_RF_KILL_SW, &priv->status) << STATUS_RF_KILL_SW | + test_bit(STATUS_GEO_CONFIGURED, &priv->status) << + STATUS_GEO_CONFIGURED | test_bit(STATUS_IN_SUSPEND, &priv->status) << STATUS_IN_SUSPEND; goto exit; @@ -6691,6 +6698,8 @@ static void __iwl4965_down(struct iwl4965_priv *priv) STATUS_RF_KILL_HW | test_bit(STATUS_RF_KILL_SW, &priv->status) << STATUS_RF_KILL_SW | + test_bit(STATUS_GEO_CONFIGURED, &priv->status) << + STATUS_GEO_CONFIGURED | test_bit(STATUS_IN_SUSPEND, &priv->status) << STATUS_IN_SUSPEND | test_bit(STATUS_FW_ERROR, &priv->status) << diff --git a/drivers/net/wireless/rndis_wlan.c b/drivers/net/wireless/rndis_wlan.c index d3ecf89abd9..8ce2ddf8024 100644 --- a/drivers/net/wireless/rndis_wlan.c +++ b/drivers/net/wireless/rndis_wlan.c @@ -2300,7 +2300,7 @@ static void rndis_update_wireless_stats(struct work_struct *work) struct usbnet *usbdev = priv->usbdev; struct iw_statistics iwstats; __le32 rssi, tmp; - int len, ret, bitrate, j; + int len, ret, j; unsigned long flags; int update_jiffies = STATS_UPDATE_JIFFIES; void *buf; @@ -2352,14 +2352,10 @@ static void rndis_update_wireless_stats(struct work_struct *work) if (ret == 0) iwstats.discard.misc += le32_to_cpu(tmp); - /* Workaround transfer stalls on poor quality links. */ - len = sizeof(tmp); - ret = rndis_query_oid(usbdev, OID_GEN_LINK_SPEED, &tmp, &len); - if (ret == 0) { - bitrate = le32_to_cpu(tmp) * 100; - if (bitrate > 11000000) - goto end; - + /* Workaround transfer stalls on poor quality links. + * TODO: find right way to fix these stalls (as stalls do not happen + * with ndiswrapper/windows driver). */ + if (iwstats.qual.qual <= 25) { /* Decrease stats worker interval to catch stalls. * faster. Faster than 400-500ms causes packet loss, * Slower doesn't catch stalls fast enough. diff --git a/drivers/net/wireless/rt2x00/rt2500usb.c b/drivers/net/wireless/rt2x00/rt2500usb.c index 86ded4066f5..4ca9730e5e9 100644 --- a/drivers/net/wireless/rt2x00/rt2500usb.c +++ b/drivers/net/wireless/rt2x00/rt2500usb.c @@ -1839,11 +1839,11 @@ static struct usb_device_id rt2500usb_device_table[] = { /* Hercules */ { USB_DEVICE(0x06f8, 0xe000), USB_DEVICE_DATA(&rt2500usb_ops) }, /* Melco */ + { USB_DEVICE(0x0411, 0x005e), USB_DEVICE_DATA(&rt2500usb_ops) }, { USB_DEVICE(0x0411, 0x0066), USB_DEVICE_DATA(&rt2500usb_ops) }, { USB_DEVICE(0x0411, 0x0067), USB_DEVICE_DATA(&rt2500usb_ops) }, { USB_DEVICE(0x0411, 0x008b), USB_DEVICE_DATA(&rt2500usb_ops) }, { USB_DEVICE(0x0411, 0x0097), USB_DEVICE_DATA(&rt2500usb_ops) }, - /* MSI */ { USB_DEVICE(0x0db0, 0x6861), USB_DEVICE_DATA(&rt2500usb_ops) }, { USB_DEVICE(0x0db0, 0x6865), USB_DEVICE_DATA(&rt2500usb_ops) }, diff --git a/drivers/net/wireless/wavelan.h b/drivers/net/wireless/wavelan.h index 27172cde5a3..9ab360558ff 100644 --- a/drivers/net/wireless/wavelan.h +++ b/drivers/net/wireless/wavelan.h @@ -85,7 +85,7 @@ union hacs_u #define HASR_MMC_INTR 0x0002 /* Interrupt request from MMC */ #define HASR_MMC_BUSY 0x0004 /* MMC busy indication */ #define HASR_PSA_BUSY 0x0008 /* LAN parameter storage area busy */ -}; +} __attribute__ ((packed)); typedef struct ha_t ha_t; struct ha_t @@ -292,7 +292,7 @@ struct mmw_t #define MMW_EXT_ANT_INTERNAL 0x00 /* Internal antenna */ #define MMW_EXT_ANT_EXTERNAL 0x03 /* External antenna */ #define MMW_EXT_ANT_IQ_TEST 0x1C /* IQ test pattern (set to 0) */ -}; +} __attribute__ ((packed)); #define MMW_SIZE 37 @@ -347,7 +347,7 @@ struct mmr_t unsigned char mmr_unused4[1]; /* unused */ unsigned char mmr_fee_data_l; /* Read data from EEPROM (low) */ unsigned char mmr_fee_data_h; /* Read data from EEPROM (high) */ -}; +} __attribute__ ((packed)); #define MMR_SIZE 36 diff --git a/drivers/oprofile/buffer_sync.c b/drivers/oprofile/buffer_sync.c index 8134c7e198a..b07ba2a1411 100644 --- a/drivers/oprofile/buffer_sync.c +++ b/drivers/oprofile/buffer_sync.c @@ -187,23 +187,22 @@ void sync_stop(void) end_sync(); } - + /* Optimisation. We can manage without taking the dcookie sem * because we cannot reach this code without at least one * dcookie user still being registered (namely, the reader * of the event buffer). */ -static inline unsigned long fast_get_dcookie(struct dentry * dentry, - struct vfsmount * vfsmnt) +static inline unsigned long fast_get_dcookie(struct path *path) { unsigned long cookie; - - if (dentry->d_cookie) - return (unsigned long)dentry; - get_dcookie(dentry, vfsmnt, &cookie); + + if (path->dentry->d_cookie) + return (unsigned long)path->dentry; + get_dcookie(path, &cookie); return cookie; } - + /* Look up the dcookie for the task's first VM_EXECUTABLE mapping, * which corresponds loosely to "application name". This is * not strictly necessary but allows oprofile to associate @@ -222,8 +221,7 @@ static unsigned long get_exec_dcookie(struct mm_struct * mm) continue; if (!(vma->vm_flags & VM_EXECUTABLE)) continue; - cookie = fast_get_dcookie(vma->vm_file->f_path.dentry, - vma->vm_file->f_path.mnt); + cookie = fast_get_dcookie(&vma->vm_file->f_path); break; } @@ -248,8 +246,7 @@ static unsigned long lookup_dcookie(struct mm_struct * mm, unsigned long addr, o continue; if (vma->vm_file) { - cookie = fast_get_dcookie(vma->vm_file->f_path.dentry, - vma->vm_file->f_path.mnt); + cookie = fast_get_dcookie(&vma->vm_file->f_path); *offset = (vma->vm_pgoff << PAGE_SHIFT) + addr - vma->vm_start; } else { diff --git a/drivers/parport/parport_pc.c b/drivers/parport/parport_pc.c index 238628d3a85..d76d37bcb9c 100644 --- a/drivers/parport/parport_pc.c +++ b/drivers/parport/parport_pc.c @@ -1768,7 +1768,7 @@ static int parport_PS2_supported(struct parport *pb) } #ifdef CONFIG_PARPORT_PC_FIFO -static int __devinit parport_ECP_supported(struct parport *pb) +static int parport_ECP_supported(struct parport *pb) { int i; int config, configb; @@ -1992,7 +1992,7 @@ static int parport_ECPEPP_supported(struct parport *pb) /* Don't bother probing for modes we know we won't use. */ static int __devinit parport_PS2_supported(struct parport *pb) { return 0; } #ifdef CONFIG_PARPORT_PC_FIFO -static int __devinit parport_ECP_supported(struct parport *pb) { return 0; } +static int parport_ECP_supported(struct parport *pb) { return 0; } #endif static int __devinit parport_EPP_supported(struct parport *pb) { return 0; } static int __devinit parport_ECPEPP_supported(struct parport *pb){return 0;} diff --git a/drivers/pnp/pnpacpi/core.c b/drivers/pnp/pnpacpi/core.c index 662b4c279cf..c283a9a70d8 100644 --- a/drivers/pnp/pnpacpi/core.c +++ b/drivers/pnp/pnpacpi/core.c @@ -36,7 +36,7 @@ static int num = 0; * have irqs (PIC, Timer) because we call acpi_register_gsi. * Finally, only devices that have a CRS method need to be in this list. */ -static struct __initdata acpi_device_id excluded_id_list[] = { +static struct acpi_device_id excluded_id_list[] __initdata = { {"PNP0C09", 0}, /* EC */ {"PNP0C0F", 0}, /* Link device */ {"PNP0000", 0}, /* PIC */ diff --git a/drivers/pnp/pnpbios/core.c b/drivers/pnp/pnpbios/core.c index f7e67197a56..a8a51500e1e 100644 --- a/drivers/pnp/pnpbios/core.c +++ b/drivers/pnp/pnpbios/core.c @@ -105,8 +105,6 @@ static int pnp_dock_event(int dock, struct pnp_docking_station_info *info) char *argv[3], **envp, *buf, *scratch; int i = 0, value; - if (!current->fs->root) - return -EAGAIN; if (!(envp = kcalloc(20, sizeof(char *), GFP_KERNEL))) return -ENOMEM; if (!(buf = kzalloc(256, GFP_KERNEL))) { diff --git a/drivers/ps3/ps3-lpm.c b/drivers/ps3/ps3-lpm.c index 4c066545d17..6c9592ce499 100644 --- a/drivers/ps3/ps3-lpm.c +++ b/drivers/ps3/ps3-lpm.c @@ -76,7 +76,6 @@ * * @pm_control: Shadow of the processor's pm_control register. * @pm_start_stop: Shadow of the processor's pm_start_stop register. - * @pm_interval: Shadow of the processor's pm_interval register. * @group_control: Shadow of the processor's group_control register. * @debug_bus_control: Shadow of the processor's debug_bus_control register. * @@ -91,7 +90,6 @@ struct ps3_lpm_shadow_regs { u64 pm_control; u64 pm_start_stop; - u64 pm_interval; u64 group_control; u64 debug_bus_control; }; @@ -181,9 +179,9 @@ void ps3_set_bookmark(u64 bookmark) * includes cycles before the call. */ - asm volatile("or 29, 29, 29;"); /* db10cyc */ + asm volatile("nop;nop;nop;nop;nop;nop;nop;nop;nop;"); mtspr(SPRN_BKMK, bookmark); - asm volatile("or 29, 29, 29;"); /* db10cyc */ + asm volatile("nop;nop;nop;nop;nop;nop;nop;nop;nop;"); } EXPORT_SYMBOL_GPL(ps3_set_bookmark); @@ -408,7 +406,14 @@ u32 ps3_read_pm(u32 cpu, enum pm_reg_name reg) case pm_start_stop: return lpm_priv->shadow.pm_start_stop; case pm_interval: - return lpm_priv->shadow.pm_interval; + result = lv1_set_lpm_interval(lpm_priv->lpm_id, 0, 0, &val); + if (result) { + val = 0; + dev_dbg(sbd_core(), "%s:%u: lv1 set_inteval failed: " + "reg %u, %s\n", __func__, __LINE__, reg, + ps3_result(result)); + } + return (u32)val; case group_control: return lpm_priv->shadow.group_control; case debug_bus_control: @@ -475,10 +480,8 @@ void ps3_write_pm(u32 cpu, enum pm_reg_name reg, u32 val) lpm_priv->shadow.pm_control = val; break; case pm_interval: - if (val != lpm_priv->shadow.pm_interval) - result = lv1_set_lpm_interval(lpm_priv->lpm_id, val, - PS3_WRITE_PM_MASK, &dummy); - lpm_priv->shadow.pm_interval = val; + result = lv1_set_lpm_interval(lpm_priv->lpm_id, val, + PS3_WRITE_PM_MASK, &dummy); break; case pm_start_stop: if (val != lpm_priv->shadow.pm_start_stop) @@ -1140,7 +1143,6 @@ int ps3_lpm_open(enum ps3_lpm_tb_type tb_type, void *tb_cache, lpm_priv->shadow.pm_control = PS3_LPM_SHADOW_REG_INIT; lpm_priv->shadow.pm_start_stop = PS3_LPM_SHADOW_REG_INIT; - lpm_priv->shadow.pm_interval = PS3_LPM_SHADOW_REG_INIT; lpm_priv->shadow.group_control = PS3_LPM_SHADOW_REG_INIT; lpm_priv->shadow.debug_bus_control = PS3_LPM_SHADOW_REG_INIT; diff --git a/drivers/ps3/ps3-sys-manager.c b/drivers/ps3/ps3-sys-manager.c index c3c3aba3ffc..d4f6f960dd1 100644 --- a/drivers/ps3/ps3-sys-manager.c +++ b/drivers/ps3/ps3-sys-manager.c @@ -28,10 +28,6 @@ #include "vuart.h" -MODULE_AUTHOR("Sony Corporation"); -MODULE_LICENSE("GPL v2"); -MODULE_DESCRIPTION("PS3 System Manager"); - /** * ps3_sys_manager - PS3 system manager driver. * @@ -142,9 +138,11 @@ enum ps3_sys_manager_attr { /** * enum ps3_sys_manager_event - External event type, reported by system manager. - * @PS3_SM_EVENT_POWER_PRESSED: payload.value not used. + * @PS3_SM_EVENT_POWER_PRESSED: payload.value = + * enum ps3_sys_manager_button_event. * @PS3_SM_EVENT_POWER_RELEASED: payload.value = time pressed in millisec. - * @PS3_SM_EVENT_RESET_PRESSED: payload.value not used. + * @PS3_SM_EVENT_RESET_PRESSED: payload.value = + * enum ps3_sys_manager_button_event. * @PS3_SM_EVENT_RESET_RELEASED: payload.value = time pressed in millisec. * @PS3_SM_EVENT_THERMAL_ALERT: payload.value = thermal zone id. * @PS3_SM_EVENT_THERMAL_CLEARED: payload.value = thermal zone id. @@ -162,6 +160,17 @@ enum ps3_sys_manager_event { }; /** + * enum ps3_sys_manager_button_event - Button event payload values. + * @PS3_SM_BUTTON_EVENT_HARD: Hardware generated event. + * @PS3_SM_BUTTON_EVENT_SOFT: Software generated event. + */ + +enum ps3_sys_manager_button_event { + PS3_SM_BUTTON_EVENT_HARD = 0, + PS3_SM_BUTTON_EVENT_SOFT = 1, +}; + +/** * enum ps3_sys_manager_next_op - Operation to perform after lpar is destroyed. */ @@ -181,7 +190,9 @@ enum ps3_sys_manager_next_op { * @PS3_SM_WAKE_P_O_R: Power on reset. * * Additional wakeup sources when specifying PS3_SM_NEXT_OP_SYS_SHUTDOWN. - * System will always wake from the PS3_SM_WAKE_DEFAULT sources. + * The system will always wake from the PS3_SM_WAKE_DEFAULT sources. + * Sources listed here are the only ones available to guests in the + * other-os lpar. */ enum ps3_sys_manager_wake_source { @@ -189,7 +200,7 @@ enum ps3_sys_manager_wake_source { PS3_SM_WAKE_DEFAULT = 0, PS3_SM_WAKE_RTC = 0x00000040, PS3_SM_WAKE_RTC_ERROR = 0x00000080, - PS3_SM_WAKE_P_O_R = 0x10000000, + PS3_SM_WAKE_P_O_R = 0x80000000, }; /** @@ -418,8 +429,10 @@ static int ps3_sys_manager_handle_event(struct ps3_system_bus_device *dev) switch (event.type) { case PS3_SM_EVENT_POWER_PRESSED: - dev_dbg(&dev->core, "%s:%d: POWER_PRESSED\n", - __func__, __LINE__); + dev_dbg(&dev->core, "%s:%d: POWER_PRESSED (%s)\n", + __func__, __LINE__, + (event.value == PS3_SM_BUTTON_EVENT_SOFT ? "soft" + : "hard")); ps3_sm_force_power_off = 1; /* * A memory barrier is use here to sync memory since @@ -434,8 +447,10 @@ static int ps3_sys_manager_handle_event(struct ps3_system_bus_device *dev) __func__, __LINE__, event.value); break; case PS3_SM_EVENT_RESET_PRESSED: - dev_dbg(&dev->core, "%s:%d: RESET_PRESSED\n", - __func__, __LINE__); + dev_dbg(&dev->core, "%s:%d: RESET_PRESSED (%s)\n", + __func__, __LINE__, + (event.value == PS3_SM_BUTTON_EVENT_SOFT ? "soft" + : "hard")); ps3_sm_force_power_off = 0; /* * A memory barrier is use here to sync memory since @@ -622,7 +637,7 @@ static void ps3_sys_manager_final_restart(struct ps3_system_bus_device *dev) ps3_vuart_cancel_async(dev); ps3_sys_manager_send_attr(dev, 0); - ps3_sys_manager_send_next_op(dev, PS3_SM_NEXT_OP_LPAR_REBOOT, + ps3_sys_manager_send_next_op(dev, PS3_SM_NEXT_OP_SYS_REBOOT, PS3_SM_WAKE_DEFAULT); ps3_sys_manager_send_request_shutdown(dev); @@ -699,4 +714,7 @@ static int __init ps3_sys_manager_init(void) module_init(ps3_sys_manager_init); /* Module remove not supported. */ +MODULE_AUTHOR("Sony Corporation"); +MODULE_LICENSE("GPL v2"); +MODULE_DESCRIPTION("PS3 System Manager"); MODULE_ALIAS(PS3_MODULE_ALIAS_SYSTEM_MANAGER); diff --git a/drivers/s390/net/claw.h b/drivers/s390/net/claw.h index 1ee9a6f0654..1a89d989f34 100644 --- a/drivers/s390/net/claw.h +++ b/drivers/s390/net/claw.h @@ -114,11 +114,20 @@ do { \ debug_event(claw_dbf_##name,level,(void*)(addr),len); \ } while (0) +/* Allow to sort out low debug levels early to avoid wasted sprints */ +static inline int claw_dbf_passes(debug_info_t *dbf_grp, int level) +{ + return (level <= dbf_grp->level); +} + #define CLAW_DBF_TEXT_(level,name,text...) \ -do { \ - sprintf(debug_buffer, text); \ - debug_text_event(claw_dbf_##name,level, debug_buffer);\ -} while (0) + do { \ + if (claw_dbf_passes(claw_dbf_##name, level)) { \ + sprintf(debug_buffer, text); \ + debug_text_event(claw_dbf_##name, level, \ + debug_buffer); \ + } \ + } while (0) /******************************************************* * Define Control Blocks * @@ -278,8 +287,6 @@ struct claw_env { __u16 write_size; /* write buffer size */ __u16 dev_id; /* device ident */ __u8 packing; /* are we packing? */ - volatile __u8 queme_switch; /* gate for imed packing */ - volatile unsigned long pk_delay; /* Delay for adaptive packing */ __u8 in_use; /* device active flag */ struct net_device *ndev; /* backward ptr to the net dev*/ }; diff --git a/drivers/s390/net/lcs.c b/drivers/s390/net/lcs.c index 7bfe8d707a3..f51ed997258 100644 --- a/drivers/s390/net/lcs.c +++ b/drivers/s390/net/lcs.c @@ -94,7 +94,7 @@ static int lcs_register_debug_facility(void) { lcs_dbf_setup = debug_register("lcs_setup", 2, 1, 8); - lcs_dbf_trace = debug_register("lcs_trace", 2, 2, 8); + lcs_dbf_trace = debug_register("lcs_trace", 4, 1, 8); if (lcs_dbf_setup == NULL || lcs_dbf_trace == NULL) { PRINT_ERR("Not enough memory for debug facility.\n"); lcs_unregister_debug_facility(); diff --git a/drivers/s390/net/lcs.h b/drivers/s390/net/lcs.h index 8976fb0b070..d58fea52557 100644 --- a/drivers/s390/net/lcs.h +++ b/drivers/s390/net/lcs.h @@ -16,11 +16,19 @@ do { \ debug_event(lcs_dbf_##name,level,(void*)(addr),len); \ } while (0) +/* Allow to sort out low debug levels early to avoid wasted sprints */ +static inline int lcs_dbf_passes(debug_info_t *dbf_grp, int level) +{ + return (level <= dbf_grp->level); +} + #define LCS_DBF_TEXT_(level,name,text...) \ -do { \ - sprintf(debug_buffer, text); \ - debug_text_event(lcs_dbf_##name,level, debug_buffer);\ -} while (0) + do { \ + if (lcs_dbf_passes(lcs_dbf_##name, level)) { \ + sprintf(debug_buffer, text); \ + debug_text_event(lcs_dbf_##name, level, debug_buffer); \ + } \ + } while (0) /** * sysfs related stuff diff --git a/drivers/s390/net/netiucv.c b/drivers/s390/net/netiucv.c index f3d893cfe61..874a1999448 100644 --- a/drivers/s390/net/netiucv.c +++ b/drivers/s390/net/netiucv.c @@ -97,12 +97,22 @@ MODULE_DESCRIPTION ("Linux for S/390 IUCV network driver"); DECLARE_PER_CPU(char[256], iucv_dbf_txt_buf); -#define IUCV_DBF_TEXT_(name,level,text...) \ - do { \ - char* iucv_dbf_txt_buf = get_cpu_var(iucv_dbf_txt_buf); \ - sprintf(iucv_dbf_txt_buf, text); \ - debug_text_event(iucv_dbf_##name,level,iucv_dbf_txt_buf); \ - put_cpu_var(iucv_dbf_txt_buf); \ +/* Allow to sort out low debug levels early to avoid wasted sprints */ +static inline int iucv_dbf_passes(debug_info_t *dbf_grp, int level) +{ + return (level <= dbf_grp->level); +} + +#define IUCV_DBF_TEXT_(name, level, text...) \ + do { \ + if (iucv_dbf_passes(iucv_dbf_##name, level)) { \ + char* iucv_dbf_txt_buf = \ + get_cpu_var(iucv_dbf_txt_buf); \ + sprintf(iucv_dbf_txt_buf, text); \ + debug_text_event(iucv_dbf_##name, level, \ + iucv_dbf_txt_buf); \ + put_cpu_var(iucv_dbf_txt_buf); \ + } \ } while (0) #define IUCV_DBF_SPRINTF(name,level,text...) \ @@ -137,6 +147,7 @@ PRINT_##importance(header "%02x %02x %02x %02x %02x %02x %02x %02x " \ #define PRINTK_HEADER " iucv: " /* for debugging */ static struct device_driver netiucv_driver = { + .owner = THIS_MODULE, .name = "netiucv", .bus = &iucv_bus, }; @@ -572,9 +583,9 @@ static void netiucv_callback_connres(struct iucv_path *path, u8 ipuser[16]) } /** - * Dummy NOP action for all statemachines + * NOP action for statemachines */ -static void fsm_action_nop(fsm_instance *fi, int event, void *arg) +static void netiucv_action_nop(fsm_instance *fi, int event, void *arg) { } @@ -1110,7 +1121,7 @@ static const fsm_node dev_fsm[] = { { DEV_STATE_RUNNING, DEV_EVENT_STOP, dev_action_stop }, { DEV_STATE_RUNNING, DEV_EVENT_CONDOWN, dev_action_conndown }, - { DEV_STATE_RUNNING, DEV_EVENT_CONUP, fsm_action_nop }, + { DEV_STATE_RUNNING, DEV_EVENT_CONUP, netiucv_action_nop }, }; static const int DEV_FSM_LEN = sizeof(dev_fsm) / sizeof(fsm_node); diff --git a/drivers/scsi/Kconfig b/drivers/scsi/Kconfig index a5f0aaaf0dd..a7a0813b24c 100644 --- a/drivers/scsi/Kconfig +++ b/drivers/scsi/Kconfig @@ -722,7 +722,7 @@ config SCSI_FD_MCS config SCSI_GDTH tristate "Intel/ICP (former GDT SCSI Disk Array) RAID Controller support" - depends on (ISA || EISA || PCI) && SCSI && ISA_DMA_API && PCI_LEGACY + depends on (ISA || EISA || PCI) && SCSI && ISA_DMA_API ---help--- Formerly called GDT SCSI Disk Array Controller Support. diff --git a/drivers/scsi/aacraid/aachba.c b/drivers/scsi/aacraid/aachba.c index bfd0e64964a..c05092fd3a9 100644 --- a/drivers/scsi/aacraid/aachba.c +++ b/drivers/scsi/aacraid/aachba.c @@ -144,51 +144,77 @@ static char *aac_get_status_string(u32 status); */ static int nondasd = -1; -static int aac_cache = 0; +static int aac_cache; static int dacmode = -1; - +int aac_msi; int aac_commit = -1; int startup_timeout = 180; int aif_timeout = 120; module_param(nondasd, int, S_IRUGO|S_IWUSR); -MODULE_PARM_DESC(nondasd, "Control scanning of hba for nondasd devices. 0=off, 1=on"); +MODULE_PARM_DESC(nondasd, "Control scanning of hba for nondasd devices." + " 0=off, 1=on"); module_param_named(cache, aac_cache, int, S_IRUGO|S_IWUSR); -MODULE_PARM_DESC(cache, "Disable Queue Flush commands:\n\tbit 0 - Disable FUA in WRITE SCSI commands\n\tbit 1 - Disable SYNCHRONIZE_CACHE SCSI command\n\tbit 2 - Disable only if Battery not protecting Cache"); +MODULE_PARM_DESC(cache, "Disable Queue Flush commands:\n" + "\tbit 0 - Disable FUA in WRITE SCSI commands\n" + "\tbit 1 - Disable SYNCHRONIZE_CACHE SCSI command\n" + "\tbit 2 - Disable only if Battery not protecting Cache"); module_param(dacmode, int, S_IRUGO|S_IWUSR); -MODULE_PARM_DESC(dacmode, "Control whether dma addressing is using 64 bit DAC. 0=off, 1=on"); +MODULE_PARM_DESC(dacmode, "Control whether dma addressing is using 64 bit DAC." + " 0=off, 1=on"); module_param_named(commit, aac_commit, int, S_IRUGO|S_IWUSR); -MODULE_PARM_DESC(commit, "Control whether a COMMIT_CONFIG is issued to the adapter for foreign arrays.\nThis is typically needed in systems that do not have a BIOS. 0=off, 1=on"); +MODULE_PARM_DESC(commit, "Control whether a COMMIT_CONFIG is issued to the" + " adapter for foreign arrays.\n" + "This is typically needed in systems that do not have a BIOS." + " 0=off, 1=on"); +module_param_named(msi, aac_msi, int, S_IRUGO|S_IWUSR); +MODULE_PARM_DESC(msi, "IRQ handling." + " 0=PIC(default), 1=MSI, 2=MSI-X(unsupported, uses MSI)"); module_param(startup_timeout, int, S_IRUGO|S_IWUSR); -MODULE_PARM_DESC(startup_timeout, "The duration of time in seconds to wait for adapter to have it's kernel up and\nrunning. This is typically adjusted for large systems that do not have a BIOS."); +MODULE_PARM_DESC(startup_timeout, "The duration of time in seconds to wait for" + " adapter to have it's kernel up and\n" + "running. This is typically adjusted for large systems that do not" + " have a BIOS."); module_param(aif_timeout, int, S_IRUGO|S_IWUSR); -MODULE_PARM_DESC(aif_timeout, "The duration of time in seconds to wait for applications to pick up AIFs before\nderegistering them. This is typically adjusted for heavily burdened systems."); +MODULE_PARM_DESC(aif_timeout, "The duration of time in seconds to wait for" + " applications to pick up AIFs before\n" + "deregistering them. This is typically adjusted for heavily burdened" + " systems."); int numacb = -1; module_param(numacb, int, S_IRUGO|S_IWUSR); -MODULE_PARM_DESC(numacb, "Request a limit to the number of adapter control blocks (FIB) allocated. Valid values are 512 and down. Default is to use suggestion from Firmware."); +MODULE_PARM_DESC(numacb, "Request a limit to the number of adapter control" + " blocks (FIB) allocated. Valid values are 512 and down. Default is" + " to use suggestion from Firmware."); int acbsize = -1; module_param(acbsize, int, S_IRUGO|S_IWUSR); -MODULE_PARM_DESC(acbsize, "Request a specific adapter control block (FIB) size. Valid values are 512, 2048, 4096 and 8192. Default is to use suggestion from Firmware."); +MODULE_PARM_DESC(acbsize, "Request a specific adapter control block (FIB)" + " size. Valid values are 512, 2048, 4096 and 8192. Default is to use" + " suggestion from Firmware."); int update_interval = 30 * 60; module_param(update_interval, int, S_IRUGO|S_IWUSR); -MODULE_PARM_DESC(update_interval, "Interval in seconds between time sync updates issued to adapter."); +MODULE_PARM_DESC(update_interval, "Interval in seconds between time sync" + " updates issued to adapter."); int check_interval = 24 * 60 * 60; module_param(check_interval, int, S_IRUGO|S_IWUSR); -MODULE_PARM_DESC(check_interval, "Interval in seconds between adapter health checks."); +MODULE_PARM_DESC(check_interval, "Interval in seconds between adapter health" + " checks."); int aac_check_reset = 1; module_param_named(check_reset, aac_check_reset, int, S_IRUGO|S_IWUSR); -MODULE_PARM_DESC(aac_check_reset, "If adapter fails health check, reset the adapter. a value of -1 forces the reset to adapters programmed to ignore it."); +MODULE_PARM_DESC(aac_check_reset, "If adapter fails health check, reset the" + " adapter. a value of -1 forces the reset to adapters programmed to" + " ignore it."); int expose_physicals = -1; module_param(expose_physicals, int, S_IRUGO|S_IWUSR); -MODULE_PARM_DESC(expose_physicals, "Expose physical components of the arrays. -1=protect 0=off, 1=on"); +MODULE_PARM_DESC(expose_physicals, "Expose physical components of the arrays." + " -1=protect 0=off, 1=on"); -int aac_reset_devices = 0; +int aac_reset_devices; module_param_named(reset_devices, aac_reset_devices, int, S_IRUGO|S_IWUSR); MODULE_PARM_DESC(reset_devices, "Force an adapter reset at initialization."); @@ -1315,7 +1341,7 @@ int aac_get_adapter_info(struct aac_dev* dev) (int)sizeof(dev->supplement_adapter_info.VpdInfo.Tsid), dev->supplement_adapter_info.VpdInfo.Tsid); } - if (!aac_check_reset || ((aac_check_reset != 1) && + if (!aac_check_reset || ((aac_check_reset == 1) && (dev->supplement_adapter_info.SupportedOptions2 & AAC_OPTION_IGNORE_RESET))) { printk(KERN_INFO "%s%d: Reset Adapter Ignored\n", @@ -1353,13 +1379,14 @@ int aac_get_adapter_info(struct aac_dev* dev) if (nondasd != -1) dev->nondasd_support = (nondasd!=0); - if(dev->nondasd_support != 0) { + if (dev->nondasd_support && !dev->in_reset) printk(KERN_INFO "%s%d: Non-DASD support enabled.\n",dev->name, dev->id); - } dev->dac_support = 0; if( (sizeof(dma_addr_t) > 4) && (dev->adapter_info.options & AAC_OPT_SGMAP_HOST64)){ - printk(KERN_INFO "%s%d: 64bit support enabled.\n", dev->name, dev->id); + if (!dev->in_reset) + printk(KERN_INFO "%s%d: 64bit support enabled.\n", + dev->name, dev->id); dev->dac_support = 1; } @@ -1369,8 +1396,9 @@ int aac_get_adapter_info(struct aac_dev* dev) if(dev->dac_support != 0) { if (!pci_set_dma_mask(dev->pdev, DMA_64BIT_MASK) && !pci_set_consistent_dma_mask(dev->pdev, DMA_64BIT_MASK)) { - printk(KERN_INFO"%s%d: 64 Bit DAC enabled\n", - dev->name, dev->id); + if (!dev->in_reset) + printk(KERN_INFO"%s%d: 64 Bit DAC enabled\n", + dev->name, dev->id); } else if (!pci_set_dma_mask(dev->pdev, DMA_32BIT_MASK) && !pci_set_consistent_dma_mask(dev->pdev, DMA_32BIT_MASK)) { printk(KERN_INFO"%s%d: DMA mask set failed, 64 Bit DAC disabled\n", diff --git a/drivers/scsi/aacraid/aacraid.h b/drivers/scsi/aacraid/aacraid.h index 3195d29f217..ace0b751c13 100644 --- a/drivers/scsi/aacraid/aacraid.h +++ b/drivers/scsi/aacraid/aacraid.h @@ -1026,6 +1026,7 @@ struct aac_dev u8 raw_io_64; u8 printf_enabled; u8 in_reset; + u8 msi; }; #define aac_adapter_interrupt(dev) \ @@ -1881,6 +1882,7 @@ extern int startup_timeout; extern int aif_timeout; extern int expose_physicals; extern int aac_reset_devices; +extern int aac_msi; extern int aac_commit; extern int update_interval; extern int check_interval; diff --git a/drivers/scsi/aacraid/commsup.c b/drivers/scsi/aacraid/commsup.c index 81b36923e0e..47434499e82 100644 --- a/drivers/scsi/aacraid/commsup.c +++ b/drivers/scsi/aacraid/commsup.c @@ -1458,7 +1458,7 @@ int aac_check_health(struct aac_dev * aac) printk(KERN_ERR "%s: Host adapter BLINK LED 0x%x\n", aac->name, BlinkLED); - if (!aac_check_reset || ((aac_check_reset != 1) && + if (!aac_check_reset || ((aac_check_reset == 1) && (aac->supplement_adapter_info.SupportedOptions2 & AAC_OPTION_IGNORE_RESET))) goto out; diff --git a/drivers/scsi/aacraid/linit.c b/drivers/scsi/aacraid/linit.c index e80d2a0c46a..ae5f74fb62d 100644 --- a/drivers/scsi/aacraid/linit.c +++ b/drivers/scsi/aacraid/linit.c @@ -275,9 +275,9 @@ static const char *aac_info(struct Scsi_Host *shost) /** * aac_get_driver_ident - * @devtype: index into lookup table + * @devtype: index into lookup table * - * Returns a pointer to the entry in the driver lookup table. + * Returns a pointer to the entry in the driver lookup table. */ struct aac_driver_ident* aac_get_driver_ident(int devtype) @@ -494,13 +494,14 @@ static int aac_change_queue_depth(struct scsi_device *sdev, int depth) static ssize_t aac_show_raid_level(struct device *dev, struct device_attribute *attr, char *buf) { - struct scsi_device * sdev = to_scsi_device(dev); + struct scsi_device *sdev = to_scsi_device(dev); + struct aac_dev *aac = (struct aac_dev *)(sdev->host->hostdata); if (sdev_channel(sdev) != CONTAINER_CHANNEL) return snprintf(buf, PAGE_SIZE, sdev->no_uld_attach - ? "Hidden\n" : "JBOD"); + ? "Hidden\n" : + ((aac->jbod && (sdev->type == TYPE_DISK)) ? "JBOD\n" : "")); return snprintf(buf, PAGE_SIZE, "%s\n", - get_container_type(((struct aac_dev *)(sdev->host->hostdata)) - ->fsa_dev[sdev_id(sdev)].type)); + get_container_type(aac->fsa_dev[sdev_id(sdev)].type)); } static struct device_attribute aac_raid_level_attr = { @@ -641,7 +642,7 @@ static int aac_eh_reset(struct scsi_cmnd* cmd) AAC_OPTION_MU_RESET) && aac_check_reset && ((aac_check_reset != 1) || - (aac->supplement_adapter_info.SupportedOptions2 & + !(aac->supplement_adapter_info.SupportedOptions2 & AAC_OPTION_IGNORE_RESET))) aac_reset_adapter(aac, 2); /* Bypass wait for command quiesce */ return SUCCESS; /* Cause an immediate retry of the command with a ten second delay after successful tur */ @@ -860,8 +861,8 @@ ssize_t aac_show_serial_number(struct class_device *class_dev, char *buf) le32_to_cpu(dev->adapter_info.serial[0])); if (len && !memcmp(&dev->supplement_adapter_info.MfgPcbaSerialNo[ - sizeof(dev->supplement_adapter_info.MfgPcbaSerialNo)+2-len], - buf, len)) + sizeof(dev->supplement_adapter_info.MfgPcbaSerialNo)-len], + buf, len-1)) len = snprintf(buf, PAGE_SIZE, "%.*s\n", (int)sizeof(dev->supplement_adapter_info.MfgPcbaSerialNo), dev->supplement_adapter_info.MfgPcbaSerialNo); @@ -1004,32 +1005,32 @@ static const struct file_operations aac_cfg_fops = { static struct scsi_host_template aac_driver_template = { .module = THIS_MODULE, - .name = "AAC", + .name = "AAC", .proc_name = AAC_DRIVERNAME, - .info = aac_info, - .ioctl = aac_ioctl, + .info = aac_info, + .ioctl = aac_ioctl, #ifdef CONFIG_COMPAT .compat_ioctl = aac_compat_ioctl, #endif - .queuecommand = aac_queuecommand, - .bios_param = aac_biosparm, + .queuecommand = aac_queuecommand, + .bios_param = aac_biosparm, .shost_attrs = aac_attrs, .slave_configure = aac_slave_configure, .change_queue_depth = aac_change_queue_depth, .sdev_attrs = aac_dev_attrs, .eh_abort_handler = aac_eh_abort, .eh_host_reset_handler = aac_eh_reset, - .can_queue = AAC_NUM_IO_FIB, - .this_id = MAXIMUM_NUM_CONTAINERS, - .sg_tablesize = 16, - .max_sectors = 128, + .can_queue = AAC_NUM_IO_FIB, + .this_id = MAXIMUM_NUM_CONTAINERS, + .sg_tablesize = 16, + .max_sectors = 128, #if (AAC_NUM_IO_FIB > 256) .cmd_per_lun = 256, #else - .cmd_per_lun = AAC_NUM_IO_FIB, + .cmd_per_lun = AAC_NUM_IO_FIB, #endif .use_clustering = ENABLE_CLUSTERING, - .emulated = 1, + .emulated = 1, }; static void __aac_shutdown(struct aac_dev * aac) @@ -1039,6 +1040,8 @@ static void __aac_shutdown(struct aac_dev * aac) aac_send_shutdown(aac); aac_adapter_disable_int(aac); free_irq(aac->pdev->irq, aac); + if (aac->msi) + pci_disable_msi(aac->pdev); } static int __devinit aac_probe_one(struct pci_dev *pdev, @@ -1254,7 +1257,7 @@ static struct pci_driver aac_pci_driver = { .id_table = aac_pci_tbl, .probe = aac_probe_one, .remove = __devexit_p(aac_remove_one), - .shutdown = aac_shutdown, + .shutdown = aac_shutdown, }; static int __init aac_init(void) @@ -1271,7 +1274,7 @@ static int __init aac_init(void) aac_cfg_major = register_chrdev( 0, "aac", &aac_cfg_fops); if (aac_cfg_major < 0) { printk(KERN_WARNING - "aacraid: unable to register \"aac\" device.\n"); + "aacraid: unable to register \"aac\" device.\n"); } return 0; diff --git a/drivers/scsi/aacraid/rx.c b/drivers/scsi/aacraid/rx.c index a08bbf1fd76..1f18b83e1e0 100644 --- a/drivers/scsi/aacraid/rx.c +++ b/drivers/scsi/aacraid/rx.c @@ -625,8 +625,11 @@ int _aac_rx_init(struct aac_dev *dev) if (aac_init_adapter(dev) == NULL) goto error_iounmap; aac_adapter_comm(dev, dev->comm_interface); - if (request_irq(dev->scsi_host_ptr->irq, dev->a_ops.adapter_intr, + dev->msi = aac_msi && !pci_enable_msi(dev->pdev); + if (request_irq(dev->pdev->irq, dev->a_ops.adapter_intr, IRQF_SHARED|IRQF_DISABLED, "aacraid", dev) < 0) { + if (dev->msi) + pci_disable_msi(dev->pdev); printk(KERN_ERR "%s%d: Interrupt unavailable.\n", name, instance); goto error_iounmap; diff --git a/drivers/scsi/aacraid/sa.c b/drivers/scsi/aacraid/sa.c index 85b91bc578c..cfc3410ec07 100644 --- a/drivers/scsi/aacraid/sa.c +++ b/drivers/scsi/aacraid/sa.c @@ -31,6 +31,7 @@ #include <linux/kernel.h> #include <linux/init.h> #include <linux/types.h> +#include <linux/pci.h> #include <linux/spinlock.h> #include <linux/slab.h> #include <linux/blkdev.h> @@ -385,7 +386,7 @@ int aac_sa_init(struct aac_dev *dev) if(aac_init_adapter(dev) == NULL) goto error_irq; - if (request_irq(dev->scsi_host_ptr->irq, dev->a_ops.adapter_intr, + if (request_irq(dev->pdev->irq, dev->a_ops.adapter_intr, IRQF_SHARED|IRQF_DISABLED, "aacraid", (void *)dev ) < 0) { printk(KERN_WARNING "%s%d: Interrupt unavailable.\n", @@ -403,7 +404,7 @@ int aac_sa_init(struct aac_dev *dev) error_irq: aac_sa_disable_interrupt(dev); - free_irq(dev->scsi_host_ptr->irq, (void *)dev); + free_irq(dev->pdev->irq, (void *)dev); error_iounmap: diff --git a/drivers/scsi/advansys.c b/drivers/scsi/advansys.c index ccef891d642..3c2d6888bb8 100644 --- a/drivers/scsi/advansys.c +++ b/drivers/scsi/advansys.c @@ -566,7 +566,7 @@ typedef struct asc_dvc_var { ASC_SCSI_BIT_ID_TYPE unit_not_ready; ASC_SCSI_BIT_ID_TYPE queue_full_or_busy; ASC_SCSI_BIT_ID_TYPE start_motor; - uchar overrun_buf[ASC_OVERRUN_BSIZE] __aligned(8); + uchar *overrun_buf; dma_addr_t overrun_dma; uchar scsi_reset_wait; uchar chip_no; @@ -13833,6 +13833,12 @@ static int __devinit advansys_board_found(struct Scsi_Host *shost, */ if (ASC_NARROW_BOARD(boardp)) { ASC_DBG(2, "AscInitAsc1000Driver()\n"); + + asc_dvc_varp->overrun_buf = kzalloc(ASC_OVERRUN_BSIZE, GFP_KERNEL); + if (!asc_dvc_varp->overrun_buf) { + ret = -ENOMEM; + goto err_free_wide_mem; + } warn_code = AscInitAsc1000Driver(asc_dvc_varp); if (warn_code || asc_dvc_varp->err_code) { @@ -13840,8 +13846,10 @@ static int __devinit advansys_board_found(struct Scsi_Host *shost, "warn 0x%x, error 0x%x\n", asc_dvc_varp->init_state, warn_code, asc_dvc_varp->err_code); - if (asc_dvc_varp->err_code) + if (asc_dvc_varp->err_code) { ret = -ENODEV; + kfree(asc_dvc_varp->overrun_buf); + } } } else { if (advansys_wide_init_chip(shost)) @@ -13894,6 +13902,7 @@ static int advansys_release(struct Scsi_Host *shost) dma_unmap_single(board->dev, board->dvc_var.asc_dvc_var.overrun_dma, ASC_OVERRUN_BSIZE, DMA_FROM_DEVICE); + kfree(board->dvc_var.asc_dvc_var.overrun_buf); } else { iounmap(board->ioremap_addr); advansys_wide_free_mem(board); diff --git a/drivers/scsi/aic94xx/aic94xx_sas.h b/drivers/scsi/aic94xx/aic94xx_sas.h index fa7c5290257..912e6b755f7 100644 --- a/drivers/scsi/aic94xx/aic94xx_sas.h +++ b/drivers/scsi/aic94xx/aic94xx_sas.h @@ -292,7 +292,7 @@ struct scb_header { #define INITIATE_SSP_TASK 0x00 #define INITIATE_LONG_SSP_TASK 0x01 #define INITIATE_BIDIR_SSP_TASK 0x02 -#define ABORT_TASK 0x03 +#define SCB_ABORT_TASK 0x03 #define INITIATE_SSP_TMF 0x04 #define SSP_TARG_GET_DATA 0x05 #define SSP_TARG_GET_DATA_GOOD 0x06 diff --git a/drivers/scsi/aic94xx/aic94xx_tmf.c b/drivers/scsi/aic94xx/aic94xx_tmf.c index 87b2f6e6adf..b52124f3d3a 100644 --- a/drivers/scsi/aic94xx/aic94xx_tmf.c +++ b/drivers/scsi/aic94xx/aic94xx_tmf.c @@ -369,7 +369,7 @@ int asd_abort_task(struct sas_task *task) return -ENOMEM; scb = ascb->scb; - scb->header.opcode = ABORT_TASK; + scb->header.opcode = SCB_ABORT_TASK; switch (task->task_proto) { case SAS_PROTOCOL_SATA: diff --git a/drivers/scsi/arm/fas216.c b/drivers/scsi/arm/fas216.c index fb5f2028438..a715632e19d 100644 --- a/drivers/scsi/arm/fas216.c +++ b/drivers/scsi/arm/fas216.c @@ -2018,6 +2018,7 @@ static void fas216_rq_sns_done(FAS216_Info *info, struct scsi_cmnd *SCpnt, * the upper layers to process. This would have been set * correctly by fas216_std_done. */ + scsi_eh_restore_cmnd(SCpnt, &info->ses); SCpnt->scsi_done(SCpnt); } @@ -2103,23 +2104,12 @@ request_sense: if (SCpnt->cmnd[0] == REQUEST_SENSE) goto done; + scsi_eh_prep_cmnd(SCpnt, &info->ses, NULL, 0, ~0); fas216_log_target(info, LOG_CONNECT, SCpnt->device->id, "requesting sense"); - memset(SCpnt->cmnd, 0, sizeof (SCpnt->cmnd)); - SCpnt->cmnd[0] = REQUEST_SENSE; - SCpnt->cmnd[1] = SCpnt->device->lun << 5; - SCpnt->cmnd[4] = sizeof(SCpnt->sense_buffer); - SCpnt->cmd_len = COMMAND_SIZE(SCpnt->cmnd[0]); - SCpnt->SCp.buffer = NULL; - SCpnt->SCp.buffers_residual = 0; - SCpnt->SCp.ptr = (char *)SCpnt->sense_buffer; - SCpnt->SCp.this_residual = sizeof(SCpnt->sense_buffer); - SCpnt->SCp.phase = sizeof(SCpnt->sense_buffer); + init_SCp(SCpnt); SCpnt->SCp.Message = 0; SCpnt->SCp.Status = 0; - SCpnt->request_bufflen = sizeof(SCpnt->sense_buffer); - SCpnt->sc_data_direction = DMA_FROM_DEVICE; - SCpnt->use_sg = 0; SCpnt->tag = 0; SCpnt->host_scribble = (void *)fas216_rq_sns_done; diff --git a/drivers/scsi/arm/fas216.h b/drivers/scsi/arm/fas216.h index 00e5f055afd..3e73e264972 100644 --- a/drivers/scsi/arm/fas216.h +++ b/drivers/scsi/arm/fas216.h @@ -16,6 +16,8 @@ #define NO_IRQ 255 #endif +#include <scsi/scsi_eh.h> + #include "queue.h" #include "msgqueue.h" @@ -311,6 +313,7 @@ typedef struct { /* miscellaneous */ int internal_done; /* flag to indicate request done */ + struct scsi_eh_save *ses; /* holds request sense restore info */ unsigned long magic_end; } FAS216_Info; diff --git a/drivers/scsi/gdth.c b/drivers/scsi/gdth.c index c82523908c2..6d67f5c0eb8 100644 --- a/drivers/scsi/gdth.c +++ b/drivers/scsi/gdth.c @@ -642,12 +642,15 @@ static void __init gdth_search_dev(gdth_pci_str *pcistr, ushort *cnt, *cnt, vendor, device)); pdev = NULL; - while ((pdev = pci_find_device(vendor, device, pdev)) + while ((pdev = pci_get_device(vendor, device, pdev)) != NULL) { if (pci_enable_device(pdev)) continue; - if (*cnt >= MAXHA) + if (*cnt >= MAXHA) { + pci_dev_put(pdev); return; + } + /* GDT PCI controller found, resources are already in pdev */ pcistr[*cnt].pdev = pdev; pcistr[*cnt].irq = pdev->irq; @@ -4836,6 +4839,9 @@ static int __init gdth_isa_probe_one(ulong32 isa_bios) if (error) goto out_free_coal_stat; list_add_tail(&ha->list, &gdth_instances); + + scsi_scan_host(shp); + return 0; out_free_coal_stat: @@ -4963,6 +4969,9 @@ static int __init gdth_eisa_probe_one(ushort eisa_slot) if (error) goto out_free_coal_stat; list_add_tail(&ha->list, &gdth_instances); + + scsi_scan_host(shp); + return 0; out_free_ccb_phys: @@ -5100,6 +5109,9 @@ static int __init gdth_pci_probe_one(gdth_pci_str *pcistr, int ctr) if (error) goto out_free_coal_stat; list_add_tail(&ha->list, &gdth_instances); + + scsi_scan_host(shp); + return 0; out_free_coal_stat: diff --git a/drivers/scsi/lpfc/lpfc.h b/drivers/scsi/lpfc/lpfc.h index 83567b9755b..2ab2d24dcc1 100644 --- a/drivers/scsi/lpfc/lpfc.h +++ b/drivers/scsi/lpfc/lpfc.h @@ -1,7 +1,7 @@ /******************************************************************* * This file is part of the Emulex Linux Device Driver for * * Fibre Channel Host Bus Adapters. * - * Copyright (C) 2004-2007 Emulex. All rights reserved. * + * Copyright (C) 2004-2008 Emulex. All rights reserved. * * EMULEX and SLI are trademarks of Emulex. * * www.emulex.com * * Portions Copyright (C) 2004-2005 Christoph Hellwig * @@ -307,6 +307,7 @@ struct lpfc_vport { uint32_t fc_nlp_cnt; /* outstanding NODELIST requests */ uint32_t fc_rscn_id_cnt; /* count of RSCNs payloads in list */ + uint32_t fc_rscn_flush; /* flag use of fc_rscn_id_list */ struct lpfc_dmabuf *fc_rscn_id_list[FC_MAX_HOLD_RSCN]; struct lpfc_name fc_nodename; /* fc nodename */ struct lpfc_name fc_portname; /* fc portname */ @@ -392,6 +393,13 @@ enum hba_temp_state { HBA_OVER_TEMP }; +enum intr_type_t { + NONE = 0, + INTx, + MSI, + MSIX, +}; + struct lpfc_hba { struct lpfc_sli sli; uint32_t sli_rev; /* SLI2 or SLI3 */ @@ -409,7 +417,7 @@ struct lpfc_hba { /* This flag is set while issuing */ /* INIT_LINK mailbox command */ #define LS_NPIV_FAB_SUPPORTED 0x2 /* Fabric supports NPIV */ -#define LS_IGNORE_ERATT 0x3 /* intr handler should ignore ERATT */ +#define LS_IGNORE_ERATT 0x4 /* intr handler should ignore ERATT */ struct lpfc_sli2_slim *slim2p; struct lpfc_dmabuf hbqslimp; @@ -487,6 +495,8 @@ struct lpfc_hba { wait_queue_head_t *work_wait; struct task_struct *worker_thread; + uint32_t hbq_in_use; /* HBQs in use flag */ + struct list_head hbqbuf_in_list; /* in-fly hbq buffer list */ uint32_t hbq_count; /* Count of configured HBQs */ struct hbq_s hbqs[LPFC_MAX_HBQS]; /* local copy of hbq indicies */ @@ -555,7 +565,8 @@ struct lpfc_hba { mempool_t *nlp_mem_pool; struct fc_host_statistics link_stats; - uint8_t using_msi; + enum intr_type_t intr_type; + struct msix_entry msix_entries[1]; struct list_head port_list; struct lpfc_vport *pport; /* physical lpfc_vport pointer */ @@ -595,6 +606,8 @@ struct lpfc_hba { unsigned long last_completion_time; struct timer_list hb_tmofunc; uint8_t hb_outstanding; + /* ndlp reference management */ + spinlock_t ndlp_lock; /* * Following bit will be set for all buffer tags which are not * associated with any HBQ. diff --git a/drivers/scsi/lpfc/lpfc_attr.c b/drivers/scsi/lpfc/lpfc_attr.c index 4bae4a2ed2f..b12a841703c 100644 --- a/drivers/scsi/lpfc/lpfc_attr.c +++ b/drivers/scsi/lpfc/lpfc_attr.c @@ -1191,7 +1191,7 @@ lpfc_update_rport_devloss_tmo(struct lpfc_vport *vport) shost = lpfc_shost_from_vport(vport); spin_lock_irq(shost->host_lock); list_for_each_entry(ndlp, &vport->fc_nodes, nlp_listp) - if (ndlp->rport) + if (NLP_CHK_NODE_ACT(ndlp) && ndlp->rport) ndlp->rport->dev_loss_tmo = vport->cfg_devloss_tmo; spin_unlock_irq(shost->host_lock); } @@ -1592,9 +1592,11 @@ LPFC_ATTR_RW(poll_tmo, 10, 1, 255, # support this feature # 0 = MSI disabled (default) # 1 = MSI enabled -# Value range is [0,1]. Default value is 0. +# 2 = MSI-X enabled +# Value range is [0,2]. Default value is 0. */ -LPFC_ATTR_R(use_msi, 0, 0, 1, "Use Message Signaled Interrupts, if possible"); +LPFC_ATTR_R(use_msi, 0, 0, 2, "Use Message Signaled Interrupts (1) or " + "MSI-X (2), if possible"); /* # lpfc_enable_hba_reset: Allow or prevent HBA resets to the hardware. @@ -1946,11 +1948,13 @@ sysfs_mbox_read(struct kobject *kobj, struct bin_attribute *bin_attr, } /* If HBA encountered an error attention, allow only DUMP - * mailbox command until the HBA is restarted. + * or RESTART mailbox commands until the HBA is restarted. */ if ((phba->pport->stopped) && - (phba->sysfs_mbox.mbox->mb.mbxCommand - != MBX_DUMP_MEMORY)) { + (phba->sysfs_mbox.mbox->mb.mbxCommand != + MBX_DUMP_MEMORY && + phba->sysfs_mbox.mbox->mb.mbxCommand != + MBX_RESTART)) { sysfs_mbox_idle(phba); spin_unlock_irq(&phba->hbalock); return -EPERM; @@ -2384,7 +2388,8 @@ lpfc_get_node_by_target(struct scsi_target *starget) spin_lock_irq(shost->host_lock); /* Search for this, mapped, target ID */ list_for_each_entry(ndlp, &vport->fc_nodes, nlp_listp) { - if (ndlp->nlp_state == NLP_STE_MAPPED_NODE && + if (NLP_CHK_NODE_ACT(ndlp) && + ndlp->nlp_state == NLP_STE_MAPPED_NODE && starget->id == ndlp->nlp_sid) { spin_unlock_irq(shost->host_lock); return ndlp; diff --git a/drivers/scsi/lpfc/lpfc_crtn.h b/drivers/scsi/lpfc/lpfc_crtn.h index 50fcb7c930b..848d97744b4 100644 --- a/drivers/scsi/lpfc/lpfc_crtn.h +++ b/drivers/scsi/lpfc/lpfc_crtn.h @@ -1,7 +1,7 @@ /******************************************************************* * This file is part of the Emulex Linux Device Driver for * * Fibre Channel Host Bus Adapters. * - * Copyright (C) 2004-2007 Emulex. All rights reserved. * + * Copyright (C) 2004-2008 Emulex. All rights reserved. * * EMULEX and SLI are trademarks of Emulex. * * www.emulex.com * * * @@ -53,7 +53,11 @@ void lpfc_mbx_cmpl_dflt_rpi(struct lpfc_hba *, LPFC_MBOXQ_t *); void lpfc_mbx_cmpl_fabric_reg_login(struct lpfc_hba *, LPFC_MBOXQ_t *); void lpfc_mbx_cmpl_ns_reg_login(struct lpfc_hba *, LPFC_MBOXQ_t *); void lpfc_mbx_cmpl_fdmi_reg_login(struct lpfc_hba *, LPFC_MBOXQ_t *); +void lpfc_enqueue_node(struct lpfc_vport *, struct lpfc_nodelist *); void lpfc_dequeue_node(struct lpfc_vport *, struct lpfc_nodelist *); +void lpfc_disable_node(struct lpfc_vport *, struct lpfc_nodelist *); +struct lpfc_nodelist *lpfc_enable_node(struct lpfc_vport *, + struct lpfc_nodelist *, int); void lpfc_nlp_set_state(struct lpfc_vport *, struct lpfc_nodelist *, int); void lpfc_drop_node(struct lpfc_vport *, struct lpfc_nodelist *); void lpfc_set_disctmo(struct lpfc_vport *); diff --git a/drivers/scsi/lpfc/lpfc_ct.c b/drivers/scsi/lpfc/lpfc_ct.c index 92441ce610e..3d0ccd9b341 100644 --- a/drivers/scsi/lpfc/lpfc_ct.c +++ b/drivers/scsi/lpfc/lpfc_ct.c @@ -1,7 +1,7 @@ /******************************************************************* * This file is part of the Emulex Linux Device Driver for * * Fibre Channel Host Bus Adapters. * - * Copyright (C) 2004-2007 Emulex. All rights reserved. * + * Copyright (C) 2004-2008 Emulex. All rights reserved. * * EMULEX and SLI are trademarks of Emulex. * * www.emulex.com * * * @@ -294,7 +294,7 @@ lpfc_gen_req(struct lpfc_vport *vport, struct lpfc_dmabuf *bmp, /* Save for completion so we can release these resources */ geniocb->context1 = (uint8_t *) inp; geniocb->context2 = (uint8_t *) outp; - geniocb->context_un.ndlp = ndlp; + geniocb->context_un.ndlp = lpfc_nlp_get(ndlp); /* Fill in payload, bp points to frame payload */ icmd->ulpCommand = CMD_GEN_REQUEST64_CR; @@ -489,8 +489,10 @@ lpfc_ns_rsp(struct lpfc_vport *vport, struct lpfc_dmabuf *mp, uint32_t Size) */ ndlp = lpfc_findnode_did(vport, Did); - if (ndlp && (ndlp->nlp_type & - NLP_FCP_TARGET)) + if (ndlp && + NLP_CHK_NODE_ACT(ndlp) + && (ndlp->nlp_type & + NLP_FCP_TARGET)) lpfc_setup_disc_node (vport, Did); else if (lpfc_ns_cmd(vport, @@ -773,7 +775,7 @@ lpfc_cmpl_ct_cmd_gff_id(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, "0267 NameServer GFF Rsp " "x%x Error (%d %d) Data: x%x x%x\n", did, irsp->ulpStatus, irsp->un.ulpWord[4], - vport->fc_flag, vport->fc_rscn_id_cnt) + vport->fc_flag, vport->fc_rscn_id_cnt); } /* This is a target port, unregistered port, or the GFF_ID failed */ @@ -1064,7 +1066,8 @@ lpfc_ns_cmd(struct lpfc_vport *vport, int cmdcode, int rc = 0; ndlp = lpfc_findnode_did(vport, NameServer_DID); - if (ndlp == NULL || ndlp->nlp_state != NLP_STE_UNMAPPED_NODE) { + if (!ndlp || !NLP_CHK_NODE_ACT(ndlp) + || ndlp->nlp_state != NLP_STE_UNMAPPED_NODE) { rc=1; goto ns_cmd_exit; } @@ -1213,8 +1216,9 @@ lpfc_ns_cmd(struct lpfc_vport *vport, int cmdcode, cmpl = lpfc_cmpl_ct_cmd_rff_id; break; } - lpfc_nlp_get(ndlp); - + /* The lpfc_ct_cmd/lpfc_get_req shall increment ndlp reference count + * to hold ndlp reference for the corresponding callback function. + */ if (!lpfc_ct_cmd(vport, mp, bmp, ndlp, cmpl, rsp_size, retry)) { /* On success, The cmpl function will free the buffers */ lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_CT, @@ -1222,9 +1226,13 @@ lpfc_ns_cmd(struct lpfc_vport *vport, int cmdcode, cmdcode, ndlp->nlp_DID, 0); return 0; } - rc=6; + + /* Decrement ndlp reference count to release ndlp reference held + * for the failed command's callback function. + */ lpfc_nlp_put(ndlp); + lpfc_mbuf_free(phba, bmp->virt, bmp->phys); ns_cmd_free_bmp: kfree(bmp); @@ -1271,6 +1279,9 @@ lpfc_cmpl_ct_cmd_fdmi(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, } ndlp = lpfc_findnode_did(vport, FDMI_DID); + if (!ndlp || !NLP_CHK_NODE_ACT(ndlp)) + goto fail_out; + if (fdmi_rsp == be16_to_cpu(SLI_CT_RESPONSE_FS_RJT)) { /* FDMI rsp failed */ lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY, @@ -1294,6 +1305,8 @@ lpfc_cmpl_ct_cmd_fdmi(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, lpfc_fdmi_cmd(vport, ndlp, SLI_MGMT_RHBA); break; } + +fail_out: lpfc_ct_free_iocb(phba, cmdiocb); return; } @@ -1650,12 +1663,18 @@ lpfc_fdmi_cmd(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, int cmdcode) bpl->tus.w = le32_to_cpu(bpl->tus.w); cmpl = lpfc_cmpl_ct_cmd_fdmi; - lpfc_nlp_get(ndlp); + /* The lpfc_ct_cmd/lpfc_get_req shall increment ndlp reference count + * to hold ndlp reference for the corresponding callback function. + */ if (!lpfc_ct_cmd(vport, mp, bmp, ndlp, cmpl, FC_MAX_NS_RSP, 0)) return 0; + /* Decrement ndlp reference count to release ndlp reference held + * for the failed command's callback function. + */ lpfc_nlp_put(ndlp); + lpfc_mbuf_free(phba, bmp->virt, bmp->phys); fdmi_cmd_free_bmp: kfree(bmp); @@ -1698,7 +1717,7 @@ lpfc_fdmi_timeout_handler(struct lpfc_vport *vport) struct lpfc_nodelist *ndlp; ndlp = lpfc_findnode_did(vport, FDMI_DID); - if (ndlp) { + if (ndlp && NLP_CHK_NODE_ACT(ndlp)) { if (init_utsname()->nodename[0] != '\0') lpfc_fdmi_cmd(vport, ndlp, SLI_MGMT_DHBA); else diff --git a/drivers/scsi/lpfc/lpfc_disc.h b/drivers/scsi/lpfc/lpfc_disc.h index cfe81c50529..2db0b74b6fa 100644 --- a/drivers/scsi/lpfc/lpfc_disc.h +++ b/drivers/scsi/lpfc/lpfc_disc.h @@ -1,7 +1,7 @@ /******************************************************************* * This file is part of the Emulex Linux Device Driver for * * Fibre Channel Host Bus Adapters. * - * Copyright (C) 2004-2007 Emulex. All rights reserved. * + * Copyright (C) 2004-2008 Emulex. All rights reserved. * * EMULEX and SLI are trademarks of Emulex. * * www.emulex.com * * * @@ -73,6 +73,12 @@ struct lpfc_nodelist { uint8_t nlp_fcp_info; /* class info, bits 0-3 */ #define NLP_FCP_2_DEVICE 0x10 /* FCP-2 device */ + uint16_t nlp_usg_map; /* ndlp management usage bitmap */ +#define NLP_USG_NODE_ACT_BIT 0x1 /* Indicate ndlp is actively used */ +#define NLP_USG_IACT_REQ_BIT 0x2 /* Request to inactivate ndlp */ +#define NLP_USG_FREE_REQ_BIT 0x4 /* Request to invoke ndlp memory free */ +#define NLP_USG_FREE_ACK_BIT 0x8 /* Indicate ndlp memory free invoked */ + struct timer_list nlp_delayfunc; /* Used for delayed ELS cmds */ struct fc_rport *rport; /* Corresponding FC transport port structure */ @@ -85,25 +91,51 @@ struct lpfc_nodelist { }; /* Defines for nlp_flag (uint32) */ -#define NLP_PLOGI_SND 0x20 /* sent PLOGI request for this entry */ -#define NLP_PRLI_SND 0x40 /* sent PRLI request for this entry */ -#define NLP_ADISC_SND 0x80 /* sent ADISC request for this entry */ -#define NLP_LOGO_SND 0x100 /* sent LOGO request for this entry */ -#define NLP_RNID_SND 0x400 /* sent RNID request for this entry */ -#define NLP_ELS_SND_MASK 0x7e0 /* sent ELS request for this entry */ -#define NLP_DEFER_RM 0x10000 /* Remove this ndlp if no longer used */ -#define NLP_DELAY_TMO 0x20000 /* delay timeout is running for node */ -#define NLP_NPR_2B_DISC 0x40000 /* node is included in num_disc_nodes */ -#define NLP_RCV_PLOGI 0x80000 /* Rcv'ed PLOGI from remote system */ -#define NLP_LOGO_ACC 0x100000 /* Process LOGO after ACC completes */ -#define NLP_TGT_NO_SCSIID 0x200000 /* good PRLI but no binding for scsid */ -#define NLP_ACC_REGLOGIN 0x1000000 /* Issue Reg Login after successful +#define NLP_PLOGI_SND 0x00000020 /* sent PLOGI request for this entry */ +#define NLP_PRLI_SND 0x00000040 /* sent PRLI request for this entry */ +#define NLP_ADISC_SND 0x00000080 /* sent ADISC request for this entry */ +#define NLP_LOGO_SND 0x00000100 /* sent LOGO request for this entry */ +#define NLP_RNID_SND 0x00000400 /* sent RNID request for this entry */ +#define NLP_ELS_SND_MASK 0x000007e0 /* sent ELS request for this entry */ +#define NLP_DEFER_RM 0x00010000 /* Remove this ndlp if no longer used */ +#define NLP_DELAY_TMO 0x00020000 /* delay timeout is running for node */ +#define NLP_NPR_2B_DISC 0x00040000 /* node is included in num_disc_nodes */ +#define NLP_RCV_PLOGI 0x00080000 /* Rcv'ed PLOGI from remote system */ +#define NLP_LOGO_ACC 0x00100000 /* Process LOGO after ACC completes */ +#define NLP_TGT_NO_SCSIID 0x00200000 /* good PRLI but no binding for scsid */ +#define NLP_ACC_REGLOGIN 0x01000000 /* Issue Reg Login after successful ACC */ -#define NLP_NPR_ADISC 0x2000000 /* Issue ADISC when dq'ed from +#define NLP_NPR_ADISC 0x02000000 /* Issue ADISC when dq'ed from NPR list */ -#define NLP_RM_DFLT_RPI 0x4000000 /* need to remove leftover dflt RPI */ -#define NLP_NODEV_REMOVE 0x8000000 /* Defer removal till discovery ends */ +#define NLP_RM_DFLT_RPI 0x04000000 /* need to remove leftover dflt RPI */ +#define NLP_NODEV_REMOVE 0x08000000 /* Defer removal till discovery ends */ #define NLP_TARGET_REMOVE 0x10000000 /* Target remove in process */ +#define NLP_SC_REQ 0x20000000 /* Target requires authentication */ + +/* ndlp usage management macros */ +#define NLP_CHK_NODE_ACT(ndlp) (((ndlp)->nlp_usg_map \ + & NLP_USG_NODE_ACT_BIT) \ + && \ + !((ndlp)->nlp_usg_map \ + & NLP_USG_FREE_ACK_BIT)) +#define NLP_SET_NODE_ACT(ndlp) ((ndlp)->nlp_usg_map \ + |= NLP_USG_NODE_ACT_BIT) +#define NLP_INT_NODE_ACT(ndlp) ((ndlp)->nlp_usg_map \ + = NLP_USG_NODE_ACT_BIT) +#define NLP_CLR_NODE_ACT(ndlp) ((ndlp)->nlp_usg_map \ + &= ~NLP_USG_NODE_ACT_BIT) +#define NLP_CHK_IACT_REQ(ndlp) ((ndlp)->nlp_usg_map \ + & NLP_USG_IACT_REQ_BIT) +#define NLP_SET_IACT_REQ(ndlp) ((ndlp)->nlp_usg_map \ + |= NLP_USG_IACT_REQ_BIT) +#define NLP_CHK_FREE_REQ(ndlp) ((ndlp)->nlp_usg_map \ + & NLP_USG_FREE_REQ_BIT) +#define NLP_SET_FREE_REQ(ndlp) ((ndlp)->nlp_usg_map \ + |= NLP_USG_FREE_REQ_BIT) +#define NLP_CHK_FREE_ACK(ndlp) ((ndlp)->nlp_usg_map \ + & NLP_USG_FREE_ACK_BIT) +#define NLP_SET_FREE_ACK(ndlp) ((ndlp)->nlp_usg_map \ + |= NLP_USG_FREE_ACK_BIT) /* There are 4 different double linked lists nodelist entries can reside on. * The Port Login (PLOGI) list and Address Discovery (ADISC) list are used diff --git a/drivers/scsi/lpfc/lpfc_els.c b/drivers/scsi/lpfc/lpfc_els.c index c6b739dc6bc..cbb68a94225 100644 --- a/drivers/scsi/lpfc/lpfc_els.c +++ b/drivers/scsi/lpfc/lpfc_els.c @@ -1,7 +1,7 @@ /******************************************************************* * This file is part of the Emulex Linux Device Driver for * * Fibre Channel Host Bus Adapters. * - * Copyright (C) 2004-2007 Emulex. All rights reserved. * + * Copyright (C) 2004-2008 Emulex. All rights reserved. * * EMULEX and SLI are trademarks of Emulex. * * www.emulex.com * * Portions Copyright (C) 2004-2005 Christoph Hellwig * @@ -113,6 +113,7 @@ lpfc_prep_els_iocb(struct lpfc_vport *vport, uint8_t expectRsp, if (elsiocb == NULL) return NULL; + icmd = &elsiocb->iocb; /* fill in BDEs for command */ @@ -134,9 +135,8 @@ lpfc_prep_els_iocb(struct lpfc_vport *vport, uint8_t expectRsp, if (!prsp || !prsp->virt) goto els_iocb_free_prsp_exit; INIT_LIST_HEAD(&prsp->list); - } else { + } else prsp = NULL; - } /* Allocate buffer for Buffer ptr list */ pbuflist = kmalloc(sizeof(struct lpfc_dmabuf), GFP_KERNEL); @@ -246,7 +246,7 @@ lpfc_issue_fabric_reglogin(struct lpfc_vport *vport) sp = &phba->fc_fabparam; ndlp = lpfc_findnode_did(vport, Fabric_DID); - if (!ndlp) { + if (!ndlp || !NLP_CHK_NODE_ACT(ndlp)) { err = 1; goto fail; } @@ -282,6 +282,9 @@ lpfc_issue_fabric_reglogin(struct lpfc_vport *vport) mbox->mbox_cmpl = lpfc_mbx_cmpl_fabric_reg_login; mbox->vport = vport; + /* increment the reference count on ndlp to hold reference + * for the callback routine. + */ mbox->context2 = lpfc_nlp_get(ndlp); rc = lpfc_sli_issue_mbox(phba, mbox, MBX_NOWAIT); @@ -293,6 +296,9 @@ lpfc_issue_fabric_reglogin(struct lpfc_vport *vport) return 0; fail_issue_reg_login: + /* decrement the reference count on ndlp just incremented + * for the failed mbox command. + */ lpfc_nlp_put(ndlp); mp = (struct lpfc_dmabuf *) mbox->context1; lpfc_mbuf_free(phba, mp->virt, mp->phys); @@ -381,6 +387,8 @@ lpfc_cmpl_els_flogi_fabric(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, */ list_for_each_entry_safe(np, next_np, &vport->fc_nodes, nlp_listp) { + if (!NLP_CHK_NODE_ACT(ndlp)) + continue; if ((np->nlp_state != NLP_STE_NPR_NODE) || !(np->nlp_flag & NLP_NPR_ADISC)) continue; @@ -456,6 +464,9 @@ lpfc_cmpl_els_flogi_nport(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, mempool_free(mbox, phba->mbox_mem_pool); goto fail; } + /* Decrement ndlp reference count indicating that ndlp can be + * safely released when other references to it are done. + */ lpfc_nlp_put(ndlp); ndlp = lpfc_findnode_did(vport, PT2PT_RemoteID); @@ -467,22 +478,29 @@ lpfc_cmpl_els_flogi_nport(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, ndlp = mempool_alloc(phba->nlp_mem_pool, GFP_KERNEL); if (!ndlp) goto fail; - lpfc_nlp_init(vport, ndlp, PT2PT_RemoteID); + } else if (!NLP_CHK_NODE_ACT(ndlp)) { + ndlp = lpfc_enable_node(vport, ndlp, + NLP_STE_UNUSED_NODE); + if(!ndlp) + goto fail; } memcpy(&ndlp->nlp_portname, &sp->portName, sizeof(struct lpfc_name)); memcpy(&ndlp->nlp_nodename, &sp->nodeName, sizeof(struct lpfc_name)); + /* Set state will put ndlp onto node list if not already done */ lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE); spin_lock_irq(shost->host_lock); ndlp->nlp_flag |= NLP_NPR_2B_DISC; spin_unlock_irq(shost->host_lock); - } else { - /* This side will wait for the PLOGI */ + } else + /* This side will wait for the PLOGI, decrement ndlp reference + * count indicating that ndlp can be released when other + * references to it are done. + */ lpfc_nlp_put(ndlp); - } /* If we are pt2pt with another NPort, force NPIV off! */ phba->sli3_options &= ~LPFC_SLI3_NPIV_ENABLED; @@ -728,16 +746,21 @@ lpfc_initial_flogi(struct lpfc_vport *vport) if (!ndlp) return 0; lpfc_nlp_init(vport, ndlp, Fabric_DID); - } else { - lpfc_dequeue_node(vport, ndlp); + /* Put ndlp onto node list */ + lpfc_enqueue_node(vport, ndlp); + } else if (!NLP_CHK_NODE_ACT(ndlp)) { + /* re-setup ndlp without removing from node list */ + ndlp = lpfc_enable_node(vport, ndlp, NLP_STE_UNUSED_NODE); + if (!ndlp) + return 0; } - if (lpfc_issue_els_flogi(vport, ndlp, 0)) { + if (lpfc_issue_els_flogi(vport, ndlp, 0)) /* This decrement of reference count to node shall kick off * the release of the node. */ lpfc_nlp_put(ndlp); - } + return 1; } @@ -755,9 +778,15 @@ lpfc_initial_fdisc(struct lpfc_vport *vport) if (!ndlp) return 0; lpfc_nlp_init(vport, ndlp, Fabric_DID); - } else { - lpfc_dequeue_node(vport, ndlp); + /* Put ndlp onto node list */ + lpfc_enqueue_node(vport, ndlp); + } else if (!NLP_CHK_NODE_ACT(ndlp)) { + /* re-setup ndlp without removing from node list */ + ndlp = lpfc_enable_node(vport, ndlp, NLP_STE_UNUSED_NODE); + if (!ndlp) + return 0; } + if (lpfc_issue_els_fdisc(vport, ndlp, 0)) { /* decrement node reference count to trigger the release of * the node. @@ -816,7 +845,7 @@ lpfc_plogi_confirm_nport(struct lpfc_hba *phba, uint32_t *prsp, */ new_ndlp = lpfc_findnode_wwpn(vport, &sp->portName); - if (new_ndlp == ndlp) + if (new_ndlp == ndlp && NLP_CHK_NODE_ACT(new_ndlp)) return ndlp; if (!new_ndlp) { @@ -827,8 +856,12 @@ lpfc_plogi_confirm_nport(struct lpfc_hba *phba, uint32_t *prsp, new_ndlp = mempool_alloc(phba->nlp_mem_pool, GFP_ATOMIC); if (!new_ndlp) return ndlp; - lpfc_nlp_init(vport, new_ndlp, ndlp->nlp_DID); + } else if (!NLP_CHK_NODE_ACT(new_ndlp)) { + new_ndlp = lpfc_enable_node(vport, new_ndlp, + NLP_STE_UNUSED_NODE); + if (!new_ndlp) + return ndlp; } lpfc_unreg_rpi(vport, new_ndlp); @@ -839,6 +872,7 @@ lpfc_plogi_confirm_nport(struct lpfc_hba *phba, uint32_t *prsp, new_ndlp->nlp_flag |= NLP_NPR_2B_DISC; ndlp->nlp_flag &= ~NLP_NPR_2B_DISC; + /* Set state will put new_ndlp on to node list if not already done */ lpfc_nlp_set_state(vport, new_ndlp, ndlp->nlp_state); /* Move this back to NPR state */ @@ -912,7 +946,7 @@ lpfc_cmpl_els_plogi(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, irsp->un.elsreq64.remoteID); ndlp = lpfc_findnode_did(vport, irsp->un.elsreq64.remoteID); - if (!ndlp) { + if (!ndlp || !NLP_CHK_NODE_ACT(ndlp)) { lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS, "0136 PLOGI completes to NPort x%x " "with no ndlp. Data: x%x x%x x%x\n", @@ -962,12 +996,11 @@ lpfc_cmpl_els_plogi(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, } /* PLOGI failed */ /* Do not call DSM for lpfc_els_abort'ed ELS cmds */ - if (lpfc_error_lost_link(irsp)) { + if (lpfc_error_lost_link(irsp)) rc = NLP_STE_FREED_NODE; - } else { + else rc = lpfc_disc_state_machine(vport, ndlp, cmdiocb, NLP_EVT_CMPL_PLOGI); - } } else { /* Good status, call state machine */ prsp = list_entry(((struct lpfc_dmabuf *) @@ -1015,8 +1048,10 @@ lpfc_issue_els_plogi(struct lpfc_vport *vport, uint32_t did, uint8_t retry) pring = &psli->ring[LPFC_ELS_RING]; /* ELS ring */ ndlp = lpfc_findnode_did(vport, did); - /* If ndlp if not NULL, we will bump the reference count on it */ + if (ndlp && !NLP_CHK_NODE_ACT(ndlp)) + ndlp = NULL; + /* If ndlp is not NULL, we will bump the reference count on it */ cmdsize = (sizeof(uint32_t) + sizeof(struct serv_parm)); elsiocb = lpfc_prep_els_iocb(vport, 1, cmdsize, retry, ndlp, did, ELS_CMD_PLOGI); @@ -1097,18 +1132,15 @@ lpfc_cmpl_els_prli(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, } /* PRLI failed */ /* Do not call DSM for lpfc_els_abort'ed ELS cmds */ - if (lpfc_error_lost_link(irsp)) { + if (lpfc_error_lost_link(irsp)) goto out; - } else { + else lpfc_disc_state_machine(vport, ndlp, cmdiocb, NLP_EVT_CMPL_PRLI); - } - } else { + } else /* Good status, call state machine */ lpfc_disc_state_machine(vport, ndlp, cmdiocb, NLP_EVT_CMPL_PRLI); - } - out: lpfc_els_free_iocb(phba, cmdiocb); return; @@ -1275,15 +1307,13 @@ lpfc_cmpl_els_adisc(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, } /* ADISC failed */ /* Do not call DSM for lpfc_els_abort'ed ELS cmds */ - if (!lpfc_error_lost_link(irsp)) { + if (!lpfc_error_lost_link(irsp)) lpfc_disc_state_machine(vport, ndlp, cmdiocb, NLP_EVT_CMPL_ADISC); - } - } else { + } else /* Good status, call state machine */ lpfc_disc_state_machine(vport, ndlp, cmdiocb, NLP_EVT_CMPL_ADISC); - } if (disc && vport->num_disc_nodes) { /* Check to see if there are more ADISCs to be sent */ @@ -1443,14 +1473,12 @@ lpfc_cmpl_els_logo(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, else lpfc_disc_state_machine(vport, ndlp, cmdiocb, NLP_EVT_CMPL_LOGO); - } else { + } else /* Good status, call state machine. * This will unregister the rpi if needed. */ lpfc_disc_state_machine(vport, ndlp, cmdiocb, NLP_EVT_CMPL_LOGO); - } - out: lpfc_els_free_iocb(phba, cmdiocb); return; @@ -1556,11 +1584,19 @@ lpfc_issue_els_scr(struct lpfc_vport *vport, uint32_t nportid, uint8_t retry) psli = &phba->sli; pring = &psli->ring[LPFC_ELS_RING]; /* ELS ring */ cmdsize = (sizeof(uint32_t) + sizeof(SCR)); - ndlp = mempool_alloc(phba->nlp_mem_pool, GFP_KERNEL); - if (!ndlp) - return 1; - lpfc_nlp_init(vport, ndlp, nportid); + ndlp = lpfc_findnode_did(vport, nportid); + if (!ndlp) { + ndlp = mempool_alloc(phba->nlp_mem_pool, GFP_KERNEL); + if (!ndlp) + return 1; + lpfc_nlp_init(vport, ndlp, nportid); + lpfc_enqueue_node(vport, ndlp); + } else if (!NLP_CHK_NODE_ACT(ndlp)) { + ndlp = lpfc_enable_node(vport, ndlp, NLP_STE_UNUSED_NODE); + if (!ndlp) + return 1; + } elsiocb = lpfc_prep_els_iocb(vport, 1, cmdsize, retry, ndlp, ndlp->nlp_DID, ELS_CMD_SCR); @@ -1623,11 +1659,19 @@ lpfc_issue_els_farpr(struct lpfc_vport *vport, uint32_t nportid, uint8_t retry) psli = &phba->sli; pring = &psli->ring[LPFC_ELS_RING]; /* ELS ring */ cmdsize = (sizeof(uint32_t) + sizeof(FARP)); - ndlp = mempool_alloc(phba->nlp_mem_pool, GFP_KERNEL); - if (!ndlp) - return 1; - lpfc_nlp_init(vport, ndlp, nportid); + ndlp = lpfc_findnode_did(vport, nportid); + if (!ndlp) { + ndlp = mempool_alloc(phba->nlp_mem_pool, GFP_KERNEL); + if (!ndlp) + return 1; + lpfc_nlp_init(vport, ndlp, nportid); + lpfc_enqueue_node(vport, ndlp); + } else if (!NLP_CHK_NODE_ACT(ndlp)) { + ndlp = lpfc_enable_node(vport, ndlp, NLP_STE_UNUSED_NODE); + if (!ndlp) + return 1; + } elsiocb = lpfc_prep_els_iocb(vport, 1, cmdsize, retry, ndlp, ndlp->nlp_DID, ELS_CMD_RNID); @@ -1657,7 +1701,7 @@ lpfc_issue_els_farpr(struct lpfc_vport *vport, uint32_t nportid, uint8_t retry) memcpy(&fp->RportName, &vport->fc_portname, sizeof(struct lpfc_name)); memcpy(&fp->RnodeName, &vport->fc_nodename, sizeof(struct lpfc_name)); ondlp = lpfc_findnode_did(vport, nportid); - if (ondlp) { + if (ondlp && NLP_CHK_NODE_ACT(ondlp)) { memcpy(&fp->OportName, &ondlp->nlp_portname, sizeof(struct lpfc_name)); memcpy(&fp->OnodeName, &ondlp->nlp_nodename, @@ -1690,6 +1734,7 @@ void lpfc_cancel_retry_delay_tmo(struct lpfc_vport *vport, struct lpfc_nodelist *nlp) { struct Scsi_Host *shost = lpfc_shost_from_vport(vport); + struct lpfc_work_evt *evtp; spin_lock_irq(shost->host_lock); nlp->nlp_flag &= ~NLP_DELAY_TMO; @@ -1697,8 +1742,12 @@ lpfc_cancel_retry_delay_tmo(struct lpfc_vport *vport, struct lpfc_nodelist *nlp) del_timer_sync(&nlp->nlp_delayfunc); nlp->nlp_last_elscmd = 0; - if (!list_empty(&nlp->els_retry_evt.evt_listp)) + if (!list_empty(&nlp->els_retry_evt.evt_listp)) { list_del_init(&nlp->els_retry_evt.evt_listp); + /* Decrement nlp reference count held for the delayed retry */ + evtp = &nlp->els_retry_evt; + lpfc_nlp_put((struct lpfc_nodelist *)evtp->evt_arg1); + } if (nlp->nlp_flag & NLP_NPR_2B_DISC) { spin_lock_irq(shost->host_lock); @@ -1842,13 +1891,14 @@ lpfc_els_retry(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, cmd = *elscmd++; } - if (ndlp) + if (ndlp && NLP_CHK_NODE_ACT(ndlp)) did = ndlp->nlp_DID; else { /* We should only hit this case for retrying PLOGI */ did = irsp->un.elsreq64.remoteID; ndlp = lpfc_findnode_did(vport, did); - if (!ndlp && (cmd != ELS_CMD_PLOGI)) + if ((!ndlp || !NLP_CHK_NODE_ACT(ndlp)) + && (cmd != ELS_CMD_PLOGI)) return 1; } @@ -1870,18 +1920,15 @@ lpfc_els_retry(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, break; case IOERR_ILLEGAL_COMMAND: - if ((phba->sli3_options & LPFC_SLI3_VPORT_TEARDOWN) && - (cmd == ELS_CMD_FDISC)) { - lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS, - "0124 FDISC failed (3/6) " - "retrying...\n"); - lpfc_mbx_unreg_vpi(vport); - retry = 1; - /* FDISC retry policy */ - maxretry = 48; - if (cmdiocb->retry >= 32) - delay = 1000; - } + lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS, + "0124 Retry illegal cmd x%x " + "retry:x%x delay:x%x\n", + cmd, cmdiocb->retry, delay); + retry = 1; + /* All command's retry policy */ + maxretry = 8; + if (cmdiocb->retry > 2) + delay = 1000; break; case IOERR_NO_RESOURCES: @@ -1967,6 +2014,17 @@ lpfc_els_retry(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, break; case LSRJT_LOGICAL_ERR: + /* There are some cases where switches return this + * error when they are not ready and should be returning + * Logical Busy. We should delay every time. + */ + if (cmd == ELS_CMD_FDISC && + stat.un.b.lsRjtRsnCodeExp == LSEXP_PORT_LOGIN_REQ) { + maxretry = 3; + delay = 1000; + retry = 1; + break; + } case LSRJT_PROTOCOL_ERR: if ((phba->sli3_options & LPFC_SLI3_NPIV_ENABLED) && (cmd == ELS_CMD_FDISC) && @@ -1996,7 +2054,8 @@ lpfc_els_retry(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, retry = 1; if ((cmd == ELS_CMD_FLOGI) && - (phba->fc_topology != TOPOLOGY_LOOP)) { + (phba->fc_topology != TOPOLOGY_LOOP) && + !lpfc_error_lost_link(irsp)) { /* FLOGI retry policy */ retry = 1; maxretry = 48; @@ -2322,6 +2381,9 @@ lpfc_cmpl_els_rsp(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, if ((rspiocb->iocb.ulpStatus == 0) && (ndlp->nlp_flag & NLP_ACC_REGLOGIN)) { lpfc_unreg_rpi(vport, ndlp); + /* Increment reference count to ndlp to hold the + * reference to ndlp for the callback function. + */ mbox->context2 = lpfc_nlp_get(ndlp); mbox->vport = vport; if (ndlp->nlp_flag & NLP_RM_DFLT_RPI) { @@ -2335,9 +2397,13 @@ lpfc_cmpl_els_rsp(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, NLP_STE_REG_LOGIN_ISSUE); } if (lpfc_sli_issue_mbox(phba, mbox, MBX_NOWAIT) - != MBX_NOT_FINISHED) { + != MBX_NOT_FINISHED) goto out; - } + else + /* Decrement the ndlp reference count we + * set for this failed mailbox command. + */ + lpfc_nlp_put(ndlp); /* ELS rsp: Cannot issue reg_login for <NPortid> */ lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS, @@ -2796,6 +2862,8 @@ lpfc_els_disc_adisc(struct lpfc_vport *vport) /* go thru NPR nodes and issue any remaining ELS ADISCs */ list_for_each_entry_safe(ndlp, next_ndlp, &vport->fc_nodes, nlp_listp) { + if (!NLP_CHK_NODE_ACT(ndlp)) + continue; if (ndlp->nlp_state == NLP_STE_NPR_NODE && (ndlp->nlp_flag & NLP_NPR_2B_DISC) != 0 && (ndlp->nlp_flag & NLP_NPR_ADISC) != 0) { @@ -2833,6 +2901,8 @@ lpfc_els_disc_plogi(struct lpfc_vport *vport) /* go thru NPR nodes and issue any remaining ELS PLOGIs */ list_for_each_entry_safe(ndlp, next_ndlp, &vport->fc_nodes, nlp_listp) { + if (!NLP_CHK_NODE_ACT(ndlp)) + continue; if (ndlp->nlp_state == NLP_STE_NPR_NODE && (ndlp->nlp_flag & NLP_NPR_2B_DISC) != 0 && (ndlp->nlp_flag & NLP_DELAY_TMO) == 0 && @@ -2869,6 +2939,16 @@ lpfc_els_flush_rscn(struct lpfc_vport *vport) struct lpfc_hba *phba = vport->phba; int i; + spin_lock_irq(shost->host_lock); + if (vport->fc_rscn_flush) { + /* Another thread is walking fc_rscn_id_list on this vport */ + spin_unlock_irq(shost->host_lock); + return; + } + /* Indicate we are walking lpfc_els_flush_rscn on this vport */ + vport->fc_rscn_flush = 1; + spin_unlock_irq(shost->host_lock); + for (i = 0; i < vport->fc_rscn_id_cnt; i++) { lpfc_in_buf_free(phba, vport->fc_rscn_id_list[i]); vport->fc_rscn_id_list[i] = NULL; @@ -2878,6 +2958,8 @@ lpfc_els_flush_rscn(struct lpfc_vport *vport) vport->fc_flag &= ~(FC_RSCN_MODE | FC_RSCN_DISCOVERY); spin_unlock_irq(shost->host_lock); lpfc_can_disctmo(vport); + /* Indicate we are done walking this fc_rscn_id_list */ + vport->fc_rscn_flush = 0; } int @@ -2887,6 +2969,7 @@ lpfc_rscn_payload_check(struct lpfc_vport *vport, uint32_t did) D_ID rscn_did; uint32_t *lp; uint32_t payload_len, i; + struct Scsi_Host *shost = lpfc_shost_from_vport(vport); ns_did.un.word = did; @@ -2898,6 +2981,15 @@ lpfc_rscn_payload_check(struct lpfc_vport *vport, uint32_t did) if (vport->fc_flag & FC_RSCN_DISCOVERY) return did; + spin_lock_irq(shost->host_lock); + if (vport->fc_rscn_flush) { + /* Another thread is walking fc_rscn_id_list on this vport */ + spin_unlock_irq(shost->host_lock); + return 0; + } + /* Indicate we are walking fc_rscn_id_list on this vport */ + vport->fc_rscn_flush = 1; + spin_unlock_irq(shost->host_lock); for (i = 0; i < vport->fc_rscn_id_cnt; i++) { lp = vport->fc_rscn_id_list[i]->virt; payload_len = be32_to_cpu(*lp++ & ~ELS_CMD_MASK); @@ -2908,16 +3000,16 @@ lpfc_rscn_payload_check(struct lpfc_vport *vport, uint32_t did) switch (rscn_did.un.b.resv) { case 0: /* Single N_Port ID effected */ if (ns_did.un.word == rscn_did.un.word) - return did; + goto return_did_out; break; case 1: /* Whole N_Port Area effected */ if ((ns_did.un.b.domain == rscn_did.un.b.domain) && (ns_did.un.b.area == rscn_did.un.b.area)) - return did; + goto return_did_out; break; case 2: /* Whole N_Port Domain effected */ if (ns_did.un.b.domain == rscn_did.un.b.domain) - return did; + goto return_did_out; break; default: /* Unknown Identifier in RSCN node */ @@ -2926,11 +3018,17 @@ lpfc_rscn_payload_check(struct lpfc_vport *vport, uint32_t did) "RSCN payload Data: x%x\n", rscn_did.un.word); case 3: /* Whole Fabric effected */ - return did; + goto return_did_out; } } } + /* Indicate we are done with walking fc_rscn_id_list on this vport */ + vport->fc_rscn_flush = 0; return 0; +return_did_out: + /* Indicate we are done with walking fc_rscn_id_list on this vport */ + vport->fc_rscn_flush = 0; + return did; } static int @@ -2943,7 +3041,8 @@ lpfc_rscn_recovery_check(struct lpfc_vport *vport) */ list_for_each_entry(ndlp, &vport->fc_nodes, nlp_listp) { - if (ndlp->nlp_state == NLP_STE_UNUSED_NODE || + if (!NLP_CHK_NODE_ACT(ndlp) || + ndlp->nlp_state == NLP_STE_UNUSED_NODE || lpfc_rscn_payload_check(vport, ndlp->nlp_DID) == 0) continue; @@ -2971,7 +3070,7 @@ lpfc_els_rcv_rscn(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb, uint32_t *lp, *datap; IOCB_t *icmd; uint32_t payload_len, length, nportid, *cmd; - int rscn_cnt = vport->fc_rscn_id_cnt; + int rscn_cnt; int rscn_id = 0, hba_id = 0; int i; @@ -2984,7 +3083,8 @@ lpfc_els_rcv_rscn(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb, /* RSCN received */ lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY, "0214 RSCN received Data: x%x x%x x%x x%x\n", - vport->fc_flag, payload_len, *lp, rscn_cnt); + vport->fc_flag, payload_len, *lp, + vport->fc_rscn_id_cnt); for (i = 0; i < payload_len/sizeof(uint32_t); i++) fc_host_post_event(shost, fc_get_event_number(), FCH_EVT_RSCN, lp[i]); @@ -3022,7 +3122,7 @@ lpfc_els_rcv_rscn(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb, "0214 Ignore RSCN " "Data: x%x x%x x%x x%x\n", vport->fc_flag, payload_len, - *lp, rscn_cnt); + *lp, vport->fc_rscn_id_cnt); lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_UNSOL, "RCV RSCN vport: did:x%x/ste:x%x flg:x%x", ndlp->nlp_DID, vport->port_state, @@ -3034,6 +3134,18 @@ lpfc_els_rcv_rscn(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb, } } + spin_lock_irq(shost->host_lock); + if (vport->fc_rscn_flush) { + /* Another thread is walking fc_rscn_id_list on this vport */ + spin_unlock_irq(shost->host_lock); + vport->fc_flag |= FC_RSCN_DISCOVERY; + return 0; + } + /* Indicate we are walking fc_rscn_id_list on this vport */ + vport->fc_rscn_flush = 1; + spin_unlock_irq(shost->host_lock); + /* Get the array count after sucessfully have the token */ + rscn_cnt = vport->fc_rscn_id_cnt; /* If we are already processing an RSCN, save the received * RSCN payload buffer, cmdiocb->context2 to process later. */ @@ -3055,7 +3167,7 @@ lpfc_els_rcv_rscn(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb, if ((rscn_cnt) && (payload_len + length <= LPFC_BPL_SIZE)) { *cmd &= ELS_CMD_MASK; - *cmd |= be32_to_cpu(payload_len + length); + *cmd |= cpu_to_be32(payload_len + length); memcpy(((uint8_t *)cmd) + length, lp, payload_len); } else { @@ -3066,7 +3178,6 @@ lpfc_els_rcv_rscn(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb, */ cmdiocb->context2 = NULL; } - /* Deferred RSCN */ lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY, "0235 Deferred RSCN " @@ -3083,9 +3194,10 @@ lpfc_els_rcv_rscn(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb, vport->fc_rscn_id_cnt, vport->fc_flag, vport->port_state); } + /* Indicate we are done walking fc_rscn_id_list on this vport */ + vport->fc_rscn_flush = 0; /* Send back ACC */ lpfc_els_rsp_acc(vport, ELS_CMD_ACC, cmdiocb, ndlp, NULL); - /* send RECOVERY event for ALL nodes that match RSCN payload */ lpfc_rscn_recovery_check(vport); spin_lock_irq(shost->host_lock); @@ -3093,7 +3205,6 @@ lpfc_els_rcv_rscn(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb, spin_unlock_irq(shost->host_lock); return 0; } - lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_UNSOL, "RCV RSCN: did:x%x/ste:x%x flg:x%x", ndlp->nlp_DID, vport->port_state, ndlp->nlp_flag); @@ -3102,20 +3213,18 @@ lpfc_els_rcv_rscn(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb, vport->fc_flag |= FC_RSCN_MODE; spin_unlock_irq(shost->host_lock); vport->fc_rscn_id_list[vport->fc_rscn_id_cnt++] = pcmd; + /* Indicate we are done walking fc_rscn_id_list on this vport */ + vport->fc_rscn_flush = 0; /* * If we zero, cmdiocb->context2, the calling routine will * not try to free it. */ cmdiocb->context2 = NULL; - lpfc_set_disctmo(vport); - /* Send back ACC */ lpfc_els_rsp_acc(vport, ELS_CMD_ACC, cmdiocb, ndlp, NULL); - /* send RECOVERY event for ALL nodes that match RSCN payload */ lpfc_rscn_recovery_check(vport); - return lpfc_els_handle_rscn(vport); } @@ -3145,7 +3254,8 @@ lpfc_els_handle_rscn(struct lpfc_vport *vport) vport->num_disc_nodes = 0; ndlp = lpfc_findnode_did(vport, NameServer_DID); - if (ndlp && ndlp->nlp_state == NLP_STE_UNMAPPED_NODE) { + if (ndlp && NLP_CHK_NODE_ACT(ndlp) + && ndlp->nlp_state == NLP_STE_UNMAPPED_NODE) { /* Good ndlp, issue CT Request to NameServer */ if (lpfc_ns_cmd(vport, SLI_CTNS_GID_FT, 0, 0) == 0) /* Wait for NameServer query cmpl before we can @@ -3155,25 +3265,35 @@ lpfc_els_handle_rscn(struct lpfc_vport *vport) /* If login to NameServer does not exist, issue one */ /* Good status, issue PLOGI to NameServer */ ndlp = lpfc_findnode_did(vport, NameServer_DID); - if (ndlp) + if (ndlp && NLP_CHK_NODE_ACT(ndlp)) /* Wait for NameServer login cmpl before we can continue */ return 1; - ndlp = mempool_alloc(phba->nlp_mem_pool, GFP_KERNEL); - if (!ndlp) { - lpfc_els_flush_rscn(vport); - return 0; + if (ndlp) { + ndlp = lpfc_enable_node(vport, ndlp, + NLP_STE_PLOGI_ISSUE); + if (!ndlp) { + lpfc_els_flush_rscn(vport); + return 0; + } + ndlp->nlp_prev_state = NLP_STE_UNUSED_NODE; } else { + ndlp = mempool_alloc(phba->nlp_mem_pool, GFP_KERNEL); + if (!ndlp) { + lpfc_els_flush_rscn(vport); + return 0; + } lpfc_nlp_init(vport, ndlp, NameServer_DID); - ndlp->nlp_type |= NLP_FABRIC; ndlp->nlp_prev_state = ndlp->nlp_state; lpfc_nlp_set_state(vport, ndlp, NLP_STE_PLOGI_ISSUE); - lpfc_issue_els_plogi(vport, NameServer_DID, 0); - /* Wait for NameServer login cmpl before we can - continue */ - return 1; } + ndlp->nlp_type |= NLP_FABRIC; + lpfc_issue_els_plogi(vport, NameServer_DID, 0); + /* Wait for NameServer login cmpl before we can + * continue + */ + return 1; } lpfc_els_flush_rscn(vport); @@ -3672,6 +3792,8 @@ lpfc_els_rcv_fan(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb, list_for_each_entry_safe(ndlp, next_ndlp, &vport->fc_nodes, nlp_listp) { + if (!NLP_CHK_NODE_ACT(ndlp)) + continue; if (ndlp->nlp_state != NLP_STE_NPR_NODE) continue; if (ndlp->nlp_type & NLP_FABRIC) { @@ -3697,6 +3819,8 @@ lpfc_els_rcv_fan(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb, */ list_for_each_entry_safe(ndlp, next_ndlp, &vport->fc_nodes, nlp_listp) { + if (!NLP_CHK_NODE_ACT(ndlp)) + continue; if (ndlp->nlp_state != NLP_STE_NPR_NODE) continue; @@ -3936,7 +4060,7 @@ lpfc_els_unsol_buffer(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, uint32_t cmd, did, newnode, rjt_err = 0; IOCB_t *icmd = &elsiocb->iocb; - if (vport == NULL || elsiocb->context2 == NULL) + if (!vport || !(elsiocb->context2)) goto dropit; newnode = 0; @@ -3971,14 +4095,20 @@ lpfc_els_unsol_buffer(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, lpfc_nlp_init(vport, ndlp, did); lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE); newnode = 1; - if ((did & Fabric_DID_MASK) == Fabric_DID_MASK) { + if ((did & Fabric_DID_MASK) == Fabric_DID_MASK) ndlp->nlp_type |= NLP_FABRIC; + } else { + if (!NLP_CHK_NODE_ACT(ndlp)) { + ndlp = lpfc_enable_node(vport, ndlp, + NLP_STE_UNUSED_NODE); + if (!ndlp) + goto dropit; } - } - else { if (ndlp->nlp_state == NLP_STE_UNUSED_NODE) { /* This is simular to the new node path */ - lpfc_nlp_get(ndlp); + ndlp = lpfc_nlp_get(ndlp); + if (!ndlp) + goto dropit; lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE); newnode = 1; } @@ -3987,6 +4117,7 @@ lpfc_els_unsol_buffer(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, phba->fc_stat.elsRcvFrame++; if (elsiocb->context1) lpfc_nlp_put(elsiocb->context1); + elsiocb->context1 = lpfc_nlp_get(ndlp); elsiocb->vport = vport; @@ -4007,8 +4138,15 @@ lpfc_els_unsol_buffer(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, ndlp = lpfc_plogi_confirm_nport(phba, payload, ndlp); if (vport->port_state < LPFC_DISC_AUTH) { - rjt_err = LSRJT_UNABLE_TPC; - break; + if (!(phba->pport->fc_flag & FC_PT2PT) || + (phba->pport->fc_flag & FC_PT2PT_PLOGI)) { + rjt_err = LSRJT_UNABLE_TPC; + break; + } + /* We get here, and drop thru, if we are PT2PT with + * another NPort and the other side has initiated + * the PLOGI before responding to our FLOGI. + */ } shost = lpfc_shost_from_vport(vport); @@ -4251,15 +4389,15 @@ lpfc_els_unsol_event(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, vport = lpfc_find_vport_by_vpid(phba, vpi); } } - /* If there are no BDEs associated - * with this IOCB, there is nothing to do. - */ + /* If there are no BDEs associated + * with this IOCB, there is nothing to do. + */ if (icmd->ulpBdeCount == 0) return; - /* type of ELS cmd is first 32bit word - * in packet - */ + /* type of ELS cmd is first 32bit word + * in packet + */ if (phba->sli3_options & LPFC_SLI3_HBQ_ENABLED) { elsiocb->context2 = bdeBuf1; } else { @@ -4314,6 +4452,18 @@ lpfc_do_scr_ns_plogi(struct lpfc_hba *phba, struct lpfc_vport *vport) } lpfc_nlp_init(vport, ndlp, NameServer_DID); ndlp->nlp_type |= NLP_FABRIC; + } else if (!NLP_CHK_NODE_ACT(ndlp)) { + ndlp = lpfc_enable_node(vport, ndlp, NLP_STE_UNUSED_NODE); + if (!ndlp) { + if (phba->fc_topology == TOPOLOGY_LOOP) { + lpfc_disc_start(vport); + return; + } + lpfc_vport_set_state(vport, FC_VPORT_FAILED); + lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS, + "0348 NameServer login: node freed\n"); + return; + } } lpfc_nlp_set_state(vport, ndlp, NLP_STE_PLOGI_ISSUE); @@ -4360,6 +4510,7 @@ lpfc_cmpl_reg_new_vport(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) switch (mb->mbxStatus) { case 0x11: /* unsupported feature */ case 0x9603: /* max_vpi exceeded */ + case 0x9602: /* Link event since CLEAR_LA */ /* giving up on vport registration */ lpfc_vport_set_state(vport, FC_VPORT_FAILED); spin_lock_irq(shost->host_lock); @@ -4373,7 +4524,10 @@ lpfc_cmpl_reg_new_vport(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) spin_lock_irq(shost->host_lock); vport->fc_flag |= FC_VPORT_NEEDS_REG_VPI; spin_unlock_irq(shost->host_lock); - lpfc_initial_fdisc(vport); + if (vport->port_type == LPFC_PHYSICAL_PORT) + lpfc_initial_flogi(vport); + else + lpfc_initial_fdisc(vport); break; } @@ -4471,7 +4625,6 @@ lpfc_cmpl_els_fdisc(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, irsp->ulpStatus, irsp->un.ulpWord[4]); if (vport->fc_vport->vport_state == FC_VPORT_INITIALIZING) lpfc_vport_set_state(vport, FC_VPORT_FAILED); - lpfc_nlp_put(ndlp); /* giving up on FDISC. Cancel discovery timer */ lpfc_can_disctmo(vport); @@ -4492,8 +4645,9 @@ lpfc_cmpl_els_fdisc(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, */ list_for_each_entry_safe(np, next_np, &vport->fc_nodes, nlp_listp) { - if (np->nlp_state != NLP_STE_NPR_NODE - || !(np->nlp_flag & NLP_NPR_ADISC)) + if (!NLP_CHK_NODE_ACT(ndlp) || + (np->nlp_state != NLP_STE_NPR_NODE) || + !(np->nlp_flag & NLP_NPR_ADISC)) continue; spin_lock_irq(shost->host_lock); np->nlp_flag &= ~NLP_NPR_ADISC; @@ -4599,6 +4753,8 @@ lpfc_cmpl_els_npiv_logo(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, { struct lpfc_vport *vport = cmdiocb->vport; IOCB_t *irsp; + struct lpfc_nodelist *ndlp; + ndlp = (struct lpfc_nodelist *)cmdiocb->context1; irsp = &rspiocb->iocb; lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_CMD, @@ -4607,6 +4763,9 @@ lpfc_cmpl_els_npiv_logo(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, lpfc_els_free_iocb(phba, cmdiocb); vport->unreg_vpi_cmpl = VPORT_ERROR; + + /* Trigger the release of the ndlp after logo */ + lpfc_nlp_put(ndlp); } int @@ -4686,11 +4845,12 @@ lpfc_resume_fabric_iocbs(struct lpfc_hba *phba) repeat: iocb = NULL; spin_lock_irqsave(&phba->hbalock, iflags); - /* Post any pending iocb to the SLI layer */ + /* Post any pending iocb to the SLI layer */ if (atomic_read(&phba->fabric_iocb_count) == 0) { list_remove_head(&phba->fabric_iocb_list, iocb, typeof(*iocb), list); if (iocb) + /* Increment fabric iocb count to hold the position */ atomic_inc(&phba->fabric_iocb_count); } spin_unlock_irqrestore(&phba->hbalock, iflags); @@ -4737,9 +4897,7 @@ lpfc_block_fabric_iocbs(struct lpfc_hba *phba) int blocked; blocked = test_and_set_bit(FABRIC_COMANDS_BLOCKED, &phba->bit_flags); - /* Start a timer to unblock fabric - * iocbs after 100ms - */ + /* Start a timer to unblock fabric iocbs after 100ms */ if (!blocked) mod_timer(&phba->fabric_block_timer, jiffies + HZ/10 ); @@ -4787,8 +4945,8 @@ lpfc_cmpl_fabric_iocb(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, atomic_dec(&phba->fabric_iocb_count); if (!test_bit(FABRIC_COMANDS_BLOCKED, &phba->bit_flags)) { - /* Post any pending iocbs to HBA */ - lpfc_resume_fabric_iocbs(phba); + /* Post any pending iocbs to HBA */ + lpfc_resume_fabric_iocbs(phba); } } @@ -4807,6 +4965,9 @@ lpfc_issue_fabric_iocb(struct lpfc_hba *phba, struct lpfc_iocbq *iocb) ready = atomic_read(&phba->fabric_iocb_count) == 0 && !test_bit(FABRIC_COMANDS_BLOCKED, &phba->bit_flags); + if (ready) + /* Increment fabric iocb count to hold the position */ + atomic_inc(&phba->fabric_iocb_count); spin_unlock_irqrestore(&phba->hbalock, iflags); if (ready) { iocb->fabric_iocb_cmpl = iocb->iocb_cmpl; @@ -4817,7 +4978,6 @@ lpfc_issue_fabric_iocb(struct lpfc_hba *phba, struct lpfc_iocbq *iocb) "Fabric sched2: ste:x%x", iocb->vport->port_state, 0, 0); - atomic_inc(&phba->fabric_iocb_count); ret = lpfc_sli_issue_iocb(phba, pring, iocb, 0); if (ret == IOCB_ERROR) { diff --git a/drivers/scsi/lpfc/lpfc_hbadisc.c b/drivers/scsi/lpfc/lpfc_hbadisc.c index dc042bd97ba..bd572d6b60a 100644 --- a/drivers/scsi/lpfc/lpfc_hbadisc.c +++ b/drivers/scsi/lpfc/lpfc_hbadisc.c @@ -1,7 +1,7 @@ /******************************************************************* * This file is part of the Emulex Linux Device Driver for * * Fibre Channel Host Bus Adapters. * - * Copyright (C) 2004-2007 Emulex. All rights reserved. * + * Copyright (C) 2004-2008 Emulex. All rights reserved. * * EMULEX and SLI are trademarks of Emulex. * * www.emulex.com * * Portions Copyright (C) 2004-2005 Christoph Hellwig * @@ -272,9 +272,8 @@ lpfc_dev_loss_tmo_handler(struct lpfc_nodelist *ndlp) if (!(vport->load_flag & FC_UNLOADING) && !(ndlp->nlp_flag & NLP_DELAY_TMO) && !(ndlp->nlp_flag & NLP_NPR_2B_DISC) && - (ndlp->nlp_state != NLP_STE_UNMAPPED_NODE)) { + (ndlp->nlp_state != NLP_STE_UNMAPPED_NODE)) lpfc_disc_state_machine(vport, ndlp, NULL, NLP_EVT_DEVICE_RM); - } } @@ -566,9 +565,10 @@ lpfc_cleanup_rpis(struct lpfc_vport *vport, int remove) int rc; list_for_each_entry_safe(ndlp, next_ndlp, &vport->fc_nodes, nlp_listp) { + if (!NLP_CHK_NODE_ACT(ndlp)) + continue; if (ndlp->nlp_state == NLP_STE_UNUSED_NODE) continue; - if ((phba->sli3_options & LPFC_SLI3_VPORT_TEARDOWN) || ((vport->port_type == LPFC_NPIV_PORT) && (ndlp->nlp_DID == NameServer_DID))) @@ -629,9 +629,8 @@ lpfc_linkdown(struct lpfc_hba *phba) LPFC_MBOXQ_t *mb; int i; - if (phba->link_state == LPFC_LINK_DOWN) { + if (phba->link_state == LPFC_LINK_DOWN) return 0; - } spin_lock_irq(&phba->hbalock); if (phba->link_state > LPFC_LINK_DOWN) { phba->link_state = LPFC_LINK_DOWN; @@ -684,20 +683,21 @@ lpfc_linkup_cleanup_nodes(struct lpfc_vport *vport) struct lpfc_nodelist *ndlp; list_for_each_entry(ndlp, &vport->fc_nodes, nlp_listp) { + if (!NLP_CHK_NODE_ACT(ndlp)) + continue; if (ndlp->nlp_state == NLP_STE_UNUSED_NODE) continue; - if (ndlp->nlp_type & NLP_FABRIC) { - /* On Linkup its safe to clean up the ndlp - * from Fabric connections. - */ + /* On Linkup its safe to clean up the ndlp + * from Fabric connections. + */ if (ndlp->nlp_DID != Fabric_DID) lpfc_unreg_rpi(vport, ndlp); lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE); } else if (!(ndlp->nlp_flag & NLP_NPR_ADISC)) { - /* Fail outstanding IO now since device is - * marked for PLOGI. - */ + /* Fail outstanding IO now since device is + * marked for PLOGI. + */ lpfc_unreg_rpi(vport, ndlp); } } @@ -799,21 +799,9 @@ lpfc_mbx_cmpl_clear_la(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) writel(control, phba->HCregaddr); readl(phba->HCregaddr); /* flush */ spin_unlock_irq(&phba->hbalock); + mempool_free(pmb, phba->mbox_mem_pool); return; - vport->num_disc_nodes = 0; - /* go thru NPR nodes and issue ELS PLOGIs */ - if (vport->fc_npr_cnt) - lpfc_els_disc_plogi(vport); - - if (!vport->num_disc_nodes) { - spin_lock_irq(shost->host_lock); - vport->fc_flag &= ~FC_NDISC_ACTIVE; - spin_unlock_irq(shost->host_lock); - } - - vport->port_state = LPFC_VPORT_READY; - out: /* Device Discovery completes */ lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY, @@ -1133,7 +1121,7 @@ lpfc_mbx_cmpl_read_la(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) if (la->attType == AT_LINK_UP) { phba->fc_stat.LinkUp++; if (phba->link_flag & LS_LOOPBACK_MODE) { - lpfc_printf_log(phba, KERN_INFO, LOG_LINK_EVENT, + lpfc_printf_log(phba, KERN_ERR, LOG_LINK_EVENT, "1306 Link Up Event in loop back mode " "x%x received Data: x%x x%x x%x x%x\n", la->eventTag, phba->fc_eventTag, @@ -1150,11 +1138,21 @@ lpfc_mbx_cmpl_read_la(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) lpfc_mbx_process_link_up(phba, la); } else { phba->fc_stat.LinkDown++; - lpfc_printf_log(phba, KERN_ERR, LOG_LINK_EVENT, + if (phba->link_flag & LS_LOOPBACK_MODE) { + lpfc_printf_log(phba, KERN_ERR, LOG_LINK_EVENT, + "1308 Link Down Event in loop back mode " + "x%x received " + "Data: x%x x%x x%x\n", + la->eventTag, phba->fc_eventTag, + phba->pport->port_state, vport->fc_flag); + } + else { + lpfc_printf_log(phba, KERN_ERR, LOG_LINK_EVENT, "1305 Link Down Event x%x received " "Data: x%x x%x x%x\n", la->eventTag, phba->fc_eventTag, phba->pport->port_state, vport->fc_flag); + } lpfc_mbx_issue_link_down(phba); } @@ -1305,7 +1303,6 @@ lpfc_mbx_cmpl_fabric_reg_login(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) lpfc_mbuf_free(phba, mp->virt, mp->phys); kfree(mp); mempool_free(pmb, phba->mbox_mem_pool); - lpfc_nlp_put(ndlp); if (phba->fc_topology == TOPOLOGY_LOOP) { /* FLOGI failed, use loop map to make discovery list */ @@ -1313,6 +1310,10 @@ lpfc_mbx_cmpl_fabric_reg_login(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) /* Start discovery */ lpfc_disc_start(vport); + /* Decrement the reference count to ndlp after the + * reference to the ndlp are done. + */ + lpfc_nlp_put(ndlp); return; } @@ -1320,6 +1321,10 @@ lpfc_mbx_cmpl_fabric_reg_login(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) lpfc_printf_vlog(vport, KERN_ERR, LOG_MBOX, "0258 Register Fabric login error: 0x%x\n", mb->mbxStatus); + /* Decrement the reference count to ndlp after the reference + * to the ndlp are done. + */ + lpfc_nlp_put(ndlp); return; } @@ -1327,8 +1332,6 @@ lpfc_mbx_cmpl_fabric_reg_login(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) ndlp->nlp_type |= NLP_FABRIC; lpfc_nlp_set_state(vport, ndlp, NLP_STE_UNMAPPED_NODE); - lpfc_nlp_put(ndlp); /* Drop the reference from the mbox */ - if (vport->port_state == LPFC_FABRIC_CFG_LINK) { vports = lpfc_create_vport_work_array(phba); if (vports != NULL) @@ -1356,6 +1359,11 @@ lpfc_mbx_cmpl_fabric_reg_login(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) lpfc_mbuf_free(phba, mp->virt, mp->phys); kfree(mp); mempool_free(pmb, phba->mbox_mem_pool); + + /* Drop the reference count from the mbox at the end after + * all the current reference to the ndlp have been done. + */ + lpfc_nlp_put(ndlp); return; } @@ -1463,9 +1471,8 @@ lpfc_register_remote_port(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) * registered the port. */ if (ndlp->rport && ndlp->rport->dd_data && - ((struct lpfc_rport_data *) ndlp->rport->dd_data)->pnode == ndlp) { + ((struct lpfc_rport_data *) ndlp->rport->dd_data)->pnode == ndlp) lpfc_nlp_put(ndlp); - } lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_RPORT, "rport add: did:x%x flg:x%x type x%x", @@ -1660,6 +1667,18 @@ lpfc_nlp_set_state(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, } void +lpfc_enqueue_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) +{ + struct Scsi_Host *shost = lpfc_shost_from_vport(vport); + + if (list_empty(&ndlp->nlp_listp)) { + spin_lock_irq(shost->host_lock); + list_add_tail(&ndlp->nlp_listp, &vport->fc_nodes); + spin_unlock_irq(shost->host_lock); + } +} + +void lpfc_dequeue_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) { struct Scsi_Host *shost = lpfc_shost_from_vport(vport); @@ -1672,7 +1691,80 @@ lpfc_dequeue_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) list_del_init(&ndlp->nlp_listp); spin_unlock_irq(shost->host_lock); lpfc_nlp_state_cleanup(vport, ndlp, ndlp->nlp_state, - NLP_STE_UNUSED_NODE); + NLP_STE_UNUSED_NODE); +} + +void +lpfc_disable_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) +{ + if ((ndlp->nlp_flag & NLP_DELAY_TMO) != 0) + lpfc_cancel_retry_delay_tmo(vport, ndlp); + if (ndlp->nlp_state && !list_empty(&ndlp->nlp_listp)) + lpfc_nlp_counters(vport, ndlp->nlp_state, -1); + lpfc_nlp_state_cleanup(vport, ndlp, ndlp->nlp_state, + NLP_STE_UNUSED_NODE); +} + +struct lpfc_nodelist * +lpfc_enable_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, + int state) +{ + struct lpfc_hba *phba = vport->phba; + uint32_t did; + unsigned long flags; + + if (!ndlp) + return NULL; + + spin_lock_irqsave(&phba->ndlp_lock, flags); + /* The ndlp should not be in memory free mode */ + if (NLP_CHK_FREE_REQ(ndlp)) { + spin_unlock_irqrestore(&phba->ndlp_lock, flags); + lpfc_printf_vlog(vport, KERN_WARNING, LOG_NODE, + "0277 lpfc_enable_node: ndlp:x%p " + "usgmap:x%x refcnt:%d\n", + (void *)ndlp, ndlp->nlp_usg_map, + atomic_read(&ndlp->kref.refcount)); + return NULL; + } + /* The ndlp should not already be in active mode */ + if (NLP_CHK_NODE_ACT(ndlp)) { + spin_unlock_irqrestore(&phba->ndlp_lock, flags); + lpfc_printf_vlog(vport, KERN_WARNING, LOG_NODE, + "0278 lpfc_enable_node: ndlp:x%p " + "usgmap:x%x refcnt:%d\n", + (void *)ndlp, ndlp->nlp_usg_map, + atomic_read(&ndlp->kref.refcount)); + return NULL; + } + + /* Keep the original DID */ + did = ndlp->nlp_DID; + + /* re-initialize ndlp except of ndlp linked list pointer */ + memset((((char *)ndlp) + sizeof (struct list_head)), 0, + sizeof (struct lpfc_nodelist) - sizeof (struct list_head)); + INIT_LIST_HEAD(&ndlp->els_retry_evt.evt_listp); + INIT_LIST_HEAD(&ndlp->dev_loss_evt.evt_listp); + init_timer(&ndlp->nlp_delayfunc); + ndlp->nlp_delayfunc.function = lpfc_els_retry_delay; + ndlp->nlp_delayfunc.data = (unsigned long)ndlp; + ndlp->nlp_DID = did; + ndlp->vport = vport; + ndlp->nlp_sid = NLP_NO_SID; + /* ndlp management re-initialize */ + kref_init(&ndlp->kref); + NLP_INT_NODE_ACT(ndlp); + + spin_unlock_irqrestore(&phba->ndlp_lock, flags); + + if (state != NLP_STE_UNUSED_NODE) + lpfc_nlp_set_state(vport, ndlp, state); + + lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_NODE, + "node enable: did:x%x", + ndlp->nlp_DID, 0, 0); + return ndlp; } void @@ -1972,7 +2064,21 @@ lpfc_cleanup_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) "Data: x%x x%x x%x\n", ndlp->nlp_DID, ndlp->nlp_flag, ndlp->nlp_state, ndlp->nlp_rpi); - lpfc_dequeue_node(vport, ndlp); + if (NLP_CHK_FREE_REQ(ndlp)) { + lpfc_printf_vlog(vport, KERN_WARNING, LOG_NODE, + "0280 lpfc_cleanup_node: ndlp:x%p " + "usgmap:x%x refcnt:%d\n", + (void *)ndlp, ndlp->nlp_usg_map, + atomic_read(&ndlp->kref.refcount)); + lpfc_dequeue_node(vport, ndlp); + } else { + lpfc_printf_vlog(vport, KERN_WARNING, LOG_NODE, + "0281 lpfc_cleanup_node: ndlp:x%p " + "usgmap:x%x refcnt:%d\n", + (void *)ndlp, ndlp->nlp_usg_map, + atomic_read(&ndlp->kref.refcount)); + lpfc_disable_node(vport, ndlp); + } /* cleanup any ndlp on mbox q waiting for reglogin cmpl */ if ((mb = phba->sli.mbox_active)) { @@ -1994,12 +2100,16 @@ lpfc_cleanup_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) } list_del(&mb->list); mempool_free(mb, phba->mbox_mem_pool); - lpfc_nlp_put(ndlp); + /* We shall not invoke the lpfc_nlp_put to decrement + * the ndlp reference count as we are in the process + * of lpfc_nlp_release. + */ } } spin_unlock_irq(&phba->hbalock); - lpfc_els_abort(phba,ndlp); + lpfc_els_abort(phba, ndlp); + spin_lock_irq(shost->host_lock); ndlp->nlp_flag &= ~NLP_DELAY_TMO; spin_unlock_irq(shost->host_lock); @@ -2057,7 +2167,6 @@ lpfc_nlp_remove(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) } } } - lpfc_cleanup_node(vport, ndlp); /* @@ -2182,7 +2291,16 @@ lpfc_setup_disc_node(struct lpfc_vport *vport, uint32_t did) ndlp->nlp_flag |= NLP_NPR_2B_DISC; spin_unlock_irq(shost->host_lock); return ndlp; + } else if (!NLP_CHK_NODE_ACT(ndlp)) { + ndlp = lpfc_enable_node(vport, ndlp, NLP_STE_NPR_NODE); + if (!ndlp) + return NULL; + spin_lock_irq(shost->host_lock); + ndlp->nlp_flag |= NLP_NPR_2B_DISC; + spin_unlock_irq(shost->host_lock); + return ndlp; } + if (vport->fc_flag & FC_RSCN_MODE) { if (lpfc_rscn_payload_check(vport, did)) { /* If we've already recieved a PLOGI from this NPort @@ -2363,6 +2481,7 @@ lpfc_disc_start(struct lpfc_vport *vport) * continue discovery. */ if ((phba->sli3_options & LPFC_SLI3_NPIV_ENABLED) && + !(vport->fc_flag & FC_PT2PT) && !(vport->fc_flag & FC_RSCN_MODE)) { lpfc_issue_reg_vpi(phba, vport); return; @@ -2485,6 +2604,8 @@ lpfc_disc_flush_list(struct lpfc_vport *vport) if (vport->fc_plogi_cnt || vport->fc_adisc_cnt) { list_for_each_entry_safe(ndlp, next_ndlp, &vport->fc_nodes, nlp_listp) { + if (!NLP_CHK_NODE_ACT(ndlp)) + continue; if (ndlp->nlp_state == NLP_STE_PLOGI_ISSUE || ndlp->nlp_state == NLP_STE_ADISC_ISSUE) { lpfc_free_tx(phba, ndlp); @@ -2572,6 +2693,8 @@ lpfc_disc_timeout_handler(struct lpfc_vport *vport) /* Start discovery by sending FLOGI, clean up old rpis */ list_for_each_entry_safe(ndlp, next_ndlp, &vport->fc_nodes, nlp_listp) { + if (!NLP_CHK_NODE_ACT(ndlp)) + continue; if (ndlp->nlp_state != NLP_STE_NPR_NODE) continue; if (ndlp->nlp_type & NLP_FABRIC) { @@ -2618,7 +2741,7 @@ lpfc_disc_timeout_handler(struct lpfc_vport *vport) "NameServer login\n"); /* Next look for NameServer ndlp */ ndlp = lpfc_findnode_did(vport, NameServer_DID); - if (ndlp) + if (ndlp && NLP_CHK_NODE_ACT(ndlp)) lpfc_els_abort(phba, ndlp); /* ReStart discovery */ @@ -2897,6 +3020,7 @@ lpfc_nlp_init(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, ndlp->nlp_sid = NLP_NO_SID; INIT_LIST_HEAD(&ndlp->nlp_listp); kref_init(&ndlp->kref); + NLP_INT_NODE_ACT(ndlp); lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_NODE, "node init: did:x%x", @@ -2911,6 +3035,8 @@ lpfc_nlp_init(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, static void lpfc_nlp_release(struct kref *kref) { + struct lpfc_hba *phba; + unsigned long flags; struct lpfc_nodelist *ndlp = container_of(kref, struct lpfc_nodelist, kref); @@ -2918,8 +3044,24 @@ lpfc_nlp_release(struct kref *kref) "node release: did:x%x flg:x%x type:x%x", ndlp->nlp_DID, ndlp->nlp_flag, ndlp->nlp_type); + lpfc_printf_vlog(ndlp->vport, KERN_INFO, LOG_NODE, + "0279 lpfc_nlp_release: ndlp:x%p " + "usgmap:x%x refcnt:%d\n", + (void *)ndlp, ndlp->nlp_usg_map, + atomic_read(&ndlp->kref.refcount)); + + /* remove ndlp from action. */ lpfc_nlp_remove(ndlp->vport, ndlp); - mempool_free(ndlp, ndlp->vport->phba->nlp_mem_pool); + + /* clear the ndlp active flag for all release cases */ + phba = ndlp->vport->phba; + spin_lock_irqsave(&phba->ndlp_lock, flags); + NLP_CLR_NODE_ACT(ndlp); + spin_unlock_irqrestore(&phba->ndlp_lock, flags); + + /* free ndlp memory for final ndlp release */ + if (NLP_CHK_FREE_REQ(ndlp)) + mempool_free(ndlp, ndlp->vport->phba->nlp_mem_pool); } /* This routine bumps the reference count for a ndlp structure to ensure @@ -2929,37 +3071,108 @@ lpfc_nlp_release(struct kref *kref) struct lpfc_nodelist * lpfc_nlp_get(struct lpfc_nodelist *ndlp) { + struct lpfc_hba *phba; + unsigned long flags; + if (ndlp) { lpfc_debugfs_disc_trc(ndlp->vport, LPFC_DISC_TRC_NODE, "node get: did:x%x flg:x%x refcnt:x%x", ndlp->nlp_DID, ndlp->nlp_flag, atomic_read(&ndlp->kref.refcount)); - kref_get(&ndlp->kref); + /* The check of ndlp usage to prevent incrementing the + * ndlp reference count that is in the process of being + * released. + */ + phba = ndlp->vport->phba; + spin_lock_irqsave(&phba->ndlp_lock, flags); + if (!NLP_CHK_NODE_ACT(ndlp) || NLP_CHK_FREE_ACK(ndlp)) { + spin_unlock_irqrestore(&phba->ndlp_lock, flags); + lpfc_printf_vlog(ndlp->vport, KERN_WARNING, LOG_NODE, + "0276 lpfc_nlp_get: ndlp:x%p " + "usgmap:x%x refcnt:%d\n", + (void *)ndlp, ndlp->nlp_usg_map, + atomic_read(&ndlp->kref.refcount)); + return NULL; + } else + kref_get(&ndlp->kref); + spin_unlock_irqrestore(&phba->ndlp_lock, flags); } return ndlp; } - /* This routine decrements the reference count for a ndlp structure. If the - * count goes to 0, this indicates the the associated nodelist should be freed. + * count goes to 0, this indicates the the associated nodelist should be + * freed. Returning 1 indicates the ndlp resource has been released; on the + * other hand, returning 0 indicates the ndlp resource has not been released + * yet. */ int lpfc_nlp_put(struct lpfc_nodelist *ndlp) { - if (ndlp) { - lpfc_debugfs_disc_trc(ndlp->vport, LPFC_DISC_TRC_NODE, - "node put: did:x%x flg:x%x refcnt:x%x", - ndlp->nlp_DID, ndlp->nlp_flag, - atomic_read(&ndlp->kref.refcount)); + struct lpfc_hba *phba; + unsigned long flags; + + if (!ndlp) + return 1; + + lpfc_debugfs_disc_trc(ndlp->vport, LPFC_DISC_TRC_NODE, + "node put: did:x%x flg:x%x refcnt:x%x", + ndlp->nlp_DID, ndlp->nlp_flag, + atomic_read(&ndlp->kref.refcount)); + phba = ndlp->vport->phba; + spin_lock_irqsave(&phba->ndlp_lock, flags); + /* Check the ndlp memory free acknowledge flag to avoid the + * possible race condition that kref_put got invoked again + * after previous one has done ndlp memory free. + */ + if (NLP_CHK_FREE_ACK(ndlp)) { + spin_unlock_irqrestore(&phba->ndlp_lock, flags); + lpfc_printf_vlog(ndlp->vport, KERN_WARNING, LOG_NODE, + "0274 lpfc_nlp_put: ndlp:x%p " + "usgmap:x%x refcnt:%d\n", + (void *)ndlp, ndlp->nlp_usg_map, + atomic_read(&ndlp->kref.refcount)); + return 1; } - return ndlp ? kref_put(&ndlp->kref, lpfc_nlp_release) : 0; + /* Check the ndlp inactivate log flag to avoid the possible + * race condition that kref_put got invoked again after ndlp + * is already in inactivating state. + */ + if (NLP_CHK_IACT_REQ(ndlp)) { + spin_unlock_irqrestore(&phba->ndlp_lock, flags); + lpfc_printf_vlog(ndlp->vport, KERN_WARNING, LOG_NODE, + "0275 lpfc_nlp_put: ndlp:x%p " + "usgmap:x%x refcnt:%d\n", + (void *)ndlp, ndlp->nlp_usg_map, + atomic_read(&ndlp->kref.refcount)); + return 1; + } + /* For last put, mark the ndlp usage flags to make sure no + * other kref_get and kref_put on the same ndlp shall get + * in between the process when the final kref_put has been + * invoked on this ndlp. + */ + if (atomic_read(&ndlp->kref.refcount) == 1) { + /* Indicate ndlp is put to inactive state. */ + NLP_SET_IACT_REQ(ndlp); + /* Acknowledge ndlp memory free has been seen. */ + if (NLP_CHK_FREE_REQ(ndlp)) + NLP_SET_FREE_ACK(ndlp); + } + spin_unlock_irqrestore(&phba->ndlp_lock, flags); + /* Note, the kref_put returns 1 when decrementing a reference + * count that was 1, it invokes the release callback function, + * but it still left the reference count as 1 (not actually + * performs the last decrementation). Otherwise, it actually + * decrements the reference count and returns 0. + */ + return kref_put(&ndlp->kref, lpfc_nlp_release); } /* This routine free's the specified nodelist if it is not in use - * by any other discovery thread. This routine returns 1 if the ndlp - * is not being used by anyone and has been freed. A return value of - * 0 indicates it is being used by another discovery thread and the - * refcount is left unchanged. + * by any other discovery thread. This routine returns 1 if the + * ndlp has been freed. A return value of 0 indicates the ndlp is + * not yet been released. */ int lpfc_nlp_not_used(struct lpfc_nodelist *ndlp) @@ -2968,11 +3181,8 @@ lpfc_nlp_not_used(struct lpfc_nodelist *ndlp) "node not used: did:x%x flg:x%x refcnt:x%x", ndlp->nlp_DID, ndlp->nlp_flag, atomic_read(&ndlp->kref.refcount)); - - if (atomic_read(&ndlp->kref.refcount) == 1) { - lpfc_nlp_put(ndlp); - return 1; - } + if (atomic_read(&ndlp->kref.refcount) == 1) + if (lpfc_nlp_put(ndlp)) + return 1; return 0; } - diff --git a/drivers/scsi/lpfc/lpfc_hw.h b/drivers/scsi/lpfc/lpfc_hw.h index 041f83e7634..7773b949aa7 100644 --- a/drivers/scsi/lpfc/lpfc_hw.h +++ b/drivers/scsi/lpfc/lpfc_hw.h @@ -1,7 +1,7 @@ /******************************************************************* * This file is part of the Emulex Linux Device Driver for * * Fibre Channel Host Bus Adapters. * - * Copyright (C) 2004-2007 Emulex. All rights reserved. * + * Copyright (C) 2004-2008 Emulex. All rights reserved. * * EMULEX and SLI are trademarks of Emulex. * * www.emulex.com * * * @@ -581,6 +581,7 @@ struct ls_rjt { /* Structure is in Big Endian format */ #define LSEXP_INVALID_O_SID 0x15 #define LSEXP_INVALID_OX_RX 0x17 #define LSEXP_CMD_IN_PROGRESS 0x19 +#define LSEXP_PORT_LOGIN_REQ 0x1E #define LSEXP_INVALID_NPORT_ID 0x1F #define LSEXP_INVALID_SEQ_ID 0x21 #define LSEXP_INVALID_XCHG 0x23 @@ -1376,11 +1377,26 @@ typedef struct { /* FireFly BIU registers */ #define CMD_QUE_XRI64_CX 0xB3 #define CMD_IOCB_RCV_SEQ64_CX 0xB5 #define CMD_IOCB_RCV_ELS64_CX 0xB7 +#define CMD_IOCB_RET_XRI64_CX 0xB9 #define CMD_IOCB_RCV_CONT64_CX 0xBB #define CMD_GEN_REQUEST64_CR 0xC2 #define CMD_GEN_REQUEST64_CX 0xC3 +/* Unhandled SLI-3 Commands */ +#define CMD_IOCB_XMIT_MSEQ64_CR 0xB0 +#define CMD_IOCB_XMIT_MSEQ64_CX 0xB1 +#define CMD_IOCB_RCV_SEQ_LIST64_CX 0xC1 +#define CMD_IOCB_RCV_ELS_LIST64_CX 0xCD +#define CMD_IOCB_CLOSE_EXTENDED_CN 0xB6 +#define CMD_IOCB_ABORT_EXTENDED_CN 0xBA +#define CMD_IOCB_RET_HBQE64_CN 0xCA +#define CMD_IOCB_FCP_IBIDIR64_CR 0xAC +#define CMD_IOCB_FCP_IBIDIR64_CX 0xAD +#define CMD_IOCB_FCP_ITASKMGT64_CX 0xAF +#define CMD_IOCB_LOGENTRY_CN 0x94 +#define CMD_IOCB_LOGENTRY_ASYNC_CN 0x96 + #define CMD_MAX_IOCB_CMD 0xE6 #define CMD_IOCB_MASK 0xff diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c index 6cfeba7454d..22843751c2c 100644 --- a/drivers/scsi/lpfc/lpfc_init.c +++ b/drivers/scsi/lpfc/lpfc_init.c @@ -1,7 +1,7 @@ /******************************************************************* * This file is part of the Emulex Linux Device Driver for * * Fibre Channel Host Bus Adapters. * - * Copyright (C) 2004-2007 Emulex. All rights reserved. * + * Copyright (C) 2004-2008 Emulex. All rights reserved. * * EMULEX and SLI are trademarks of Emulex. * * www.emulex.com * * Portions Copyright (C) 2004-2005 Christoph Hellwig * @@ -461,11 +461,21 @@ lpfc_config_port_post(struct lpfc_hba *phba) int lpfc_hba_down_prep(struct lpfc_hba *phba) { + struct lpfc_vport **vports; + int i; /* Disable interrupts */ writel(0, phba->HCregaddr); readl(phba->HCregaddr); /* flush */ - lpfc_cleanup_discovery_resources(phba->pport); + if (phba->pport->load_flag & FC_UNLOADING) + lpfc_cleanup_discovery_resources(phba->pport); + else { + vports = lpfc_create_vport_work_array(phba); + if (vports != NULL) + for(i = 0; i <= phba->max_vpi && vports[i] != NULL; i++) + lpfc_cleanup_discovery_resources(vports[i]); + lpfc_destroy_vport_work_array(phba, vports); + } return 0; } @@ -1422,9 +1432,32 @@ lpfc_cleanup(struct lpfc_vport *vport) lpfc_port_link_failure(vport); list_for_each_entry_safe(ndlp, next_ndlp, &vport->fc_nodes, nlp_listp) { + if (!NLP_CHK_NODE_ACT(ndlp)) { + ndlp = lpfc_enable_node(vport, ndlp, + NLP_STE_UNUSED_NODE); + if (!ndlp) + continue; + spin_lock_irq(&phba->ndlp_lock); + NLP_SET_FREE_REQ(ndlp); + spin_unlock_irq(&phba->ndlp_lock); + /* Trigger the release of the ndlp memory */ + lpfc_nlp_put(ndlp); + continue; + } + spin_lock_irq(&phba->ndlp_lock); + if (NLP_CHK_FREE_REQ(ndlp)) { + /* The ndlp should not be in memory free mode already */ + spin_unlock_irq(&phba->ndlp_lock); + continue; + } else + /* Indicate request for freeing ndlp memory */ + NLP_SET_FREE_REQ(ndlp); + spin_unlock_irq(&phba->ndlp_lock); + if (ndlp->nlp_type & NLP_FABRIC) lpfc_disc_state_machine(vport, ndlp, NULL, NLP_EVT_DEVICE_RECOVERY); + lpfc_disc_state_machine(vport, ndlp, NULL, NLP_EVT_DEVICE_RM); } @@ -1438,6 +1471,17 @@ lpfc_cleanup(struct lpfc_vport *vport) if (i++ > 3000) { lpfc_printf_vlog(vport, KERN_ERR, LOG_DISCOVERY, "0233 Nodelist not empty\n"); + list_for_each_entry_safe(ndlp, next_ndlp, + &vport->fc_nodes, nlp_listp) { + lpfc_printf_vlog(ndlp->vport, KERN_ERR, + LOG_NODE, + "0282: did:x%x ndlp:x%p " + "usgmap:x%x refcnt:%d\n", + ndlp->nlp_DID, (void *)ndlp, + ndlp->nlp_usg_map, + atomic_read( + &ndlp->kref.refcount)); + } break; } @@ -1586,6 +1630,8 @@ lpfc_offline_prep(struct lpfc_hba * phba) list_for_each_entry_safe(ndlp, next_ndlp, &vports[i]->fc_nodes, nlp_listp) { + if (!NLP_CHK_NODE_ACT(ndlp)) + continue; if (ndlp->nlp_state == NLP_STE_UNUSED_NODE) continue; if (ndlp->nlp_type & NLP_FABRIC) { @@ -1695,9 +1741,9 @@ lpfc_create_port(struct lpfc_hba *phba, int instance, struct device *dev) vport = (struct lpfc_vport *) shost->hostdata; vport->phba = phba; - vport->load_flag |= FC_LOADING; vport->fc_flag |= FC_VPORT_NEEDS_REG_VPI; + vport->fc_rscn_flush = 0; lpfc_get_vport_cfgparam(vport); shost->unique_id = instance; @@ -1879,6 +1925,42 @@ void lpfc_host_attrib_init(struct Scsi_Host *shost) spin_unlock_irq(shost->host_lock); } +static int +lpfc_enable_msix(struct lpfc_hba *phba) +{ + int error; + + phba->msix_entries[0].entry = 0; + phba->msix_entries[0].vector = 0; + + error = pci_enable_msix(phba->pcidev, phba->msix_entries, + ARRAY_SIZE(phba->msix_entries)); + if (error) { + lpfc_printf_log(phba, KERN_INFO, LOG_INIT, + "0420 Enable MSI-X failed (%d), continuing " + "with MSI\n", error); + pci_disable_msix(phba->pcidev); + return error; + } + + error = request_irq(phba->msix_entries[0].vector, lpfc_intr_handler, 0, + LPFC_DRIVER_NAME, phba); + if (error) { + lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + "0421 MSI-X request_irq failed (%d), " + "continuing with MSI\n", error); + pci_disable_msix(phba->pcidev); + } + return error; +} + +static void +lpfc_disable_msix(struct lpfc_hba *phba) +{ + free_irq(phba->msix_entries[0].vector, phba); + pci_disable_msix(phba->pcidev); +} + static int __devinit lpfc_pci_probe_one(struct pci_dev *pdev, const struct pci_device_id *pid) { @@ -1905,6 +1987,9 @@ lpfc_pci_probe_one(struct pci_dev *pdev, const struct pci_device_id *pid) spin_lock_init(&phba->hbalock); + /* Initialize ndlp management spinlock */ + spin_lock_init(&phba->ndlp_lock); + phba->pcidev = pdev; /* Assign an unused board number */ @@ -2002,6 +2087,8 @@ lpfc_pci_probe_one(struct pci_dev *pdev, const struct pci_device_id *pid) memset(phba->hbqslimp.virt, 0, lpfc_sli_hbq_size()); + INIT_LIST_HEAD(&phba->hbqbuf_in_list); + /* Initialize the SLI Layer to run with lpfc HBAs. */ lpfc_sli_setup(phba); lpfc_sli_queue_setup(phba); @@ -2077,24 +2164,36 @@ lpfc_pci_probe_one(struct pci_dev *pdev, const struct pci_device_id *pid) lpfc_debugfs_initialize(vport); pci_set_drvdata(pdev, shost); + phba->intr_type = NONE; - if (phba->cfg_use_msi) { + if (phba->cfg_use_msi == 2) { + error = lpfc_enable_msix(phba); + if (!error) + phba->intr_type = MSIX; + } + + /* Fallback to MSI if MSI-X initialization failed */ + if (phba->cfg_use_msi >= 1 && phba->intr_type == NONE) { retval = pci_enable_msi(phba->pcidev); if (!retval) - phba->using_msi = 1; + phba->intr_type = MSI; else lpfc_printf_log(phba, KERN_INFO, LOG_INIT, "0452 Enable MSI failed, continuing " "with IRQ\n"); } - retval = request_irq(phba->pcidev->irq, lpfc_intr_handler, IRQF_SHARED, - LPFC_DRIVER_NAME, phba); - if (retval) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, - "0451 Enable interrupt handler failed\n"); - error = retval; - goto out_disable_msi; + /* MSI-X is the only case the doesn't need to call request_irq */ + if (phba->intr_type != MSIX) { + retval = request_irq(phba->pcidev->irq, lpfc_intr_handler, + IRQF_SHARED, LPFC_DRIVER_NAME, phba); + if (retval) { + lpfc_printf_log(phba, KERN_ERR, LOG_INIT, "0451 Enable " + "interrupt handler failed\n"); + error = retval; + goto out_disable_msi; + } else if (phba->intr_type != MSI) + phba->intr_type = INTx; } phba->MBslimaddr = phba->slim_memmap_p; @@ -2139,9 +2238,14 @@ out_remove_device: out_free_irq: lpfc_stop_phba_timers(phba); phba->pport->work_port_events = 0; - free_irq(phba->pcidev->irq, phba); + + if (phba->intr_type == MSIX) + lpfc_disable_msix(phba); + else + free_irq(phba->pcidev->irq, phba); + out_disable_msi: - if (phba->using_msi) + if (phba->intr_type == MSI) pci_disable_msi(phba->pcidev); destroy_port(vport); out_kthread_stop: @@ -2214,10 +2318,13 @@ lpfc_pci_remove_one(struct pci_dev *pdev) lpfc_debugfs_terminate(vport); - /* Release the irq reservation */ - free_irq(phba->pcidev->irq, phba); - if (phba->using_msi) - pci_disable_msi(phba->pcidev); + if (phba->intr_type == MSIX) + lpfc_disable_msix(phba); + else { + free_irq(phba->pcidev->irq, phba); + if (phba->intr_type == MSI) + pci_disable_msi(phba->pcidev); + } pci_set_drvdata(pdev, NULL); scsi_host_put(shost); @@ -2276,10 +2383,13 @@ static pci_ers_result_t lpfc_io_error_detected(struct pci_dev *pdev, pring = &psli->ring[psli->fcp_ring]; lpfc_sli_abort_iocb_ring(phba, pring); - /* Release the irq reservation */ - free_irq(phba->pcidev->irq, phba); - if (phba->using_msi) - pci_disable_msi(phba->pcidev); + if (phba->intr_type == MSIX) + lpfc_disable_msix(phba); + else { + free_irq(phba->pcidev->irq, phba); + if (phba->intr_type == MSI) + pci_disable_msi(phba->pcidev); + } /* Request a slot reset. */ return PCI_ERS_RESULT_NEED_RESET; diff --git a/drivers/scsi/lpfc/lpfc_logmsg.h b/drivers/scsi/lpfc/lpfc_logmsg.h index c5841d7565f..39fd2b843be 100644 --- a/drivers/scsi/lpfc/lpfc_logmsg.h +++ b/drivers/scsi/lpfc/lpfc_logmsg.h @@ -1,7 +1,7 @@ /******************************************************************* * This file is part of the Emulex Linux Device Driver for * * Fibre Channel Host Bus Adapters. * - * Copyright (C) 2004-2005 Emulex. All rights reserved. * + * Copyright (C) 2004-2008 Emulex. All rights reserved. * * EMULEX and SLI are trademarks of Emulex. * * www.emulex.com * * * @@ -35,11 +35,15 @@ #define LOG_ALL_MSG 0xffff /* LOG all messages */ #define lpfc_printf_vlog(vport, level, mask, fmt, arg...) \ + do { \ { if (((mask) &(vport)->cfg_log_verbose) || (level[1] <= '3')) \ dev_printk(level, &((vport)->phba->pcidev)->dev, "%d:(%d):" \ - fmt, (vport)->phba->brd_no, vport->vpi, ##arg); } + fmt, (vport)->phba->brd_no, vport->vpi, ##arg); } \ + } while (0) #define lpfc_printf_log(phba, level, mask, fmt, arg...) \ + do { \ { if (((mask) &(phba)->pport->cfg_log_verbose) || (level[1] <= '3')) \ dev_printk(level, &((phba)->pcidev)->dev, "%d:" \ - fmt, phba->brd_no, ##arg); } + fmt, phba->brd_no, ##arg); } \ + } while (0) diff --git a/drivers/scsi/lpfc/lpfc_mem.c b/drivers/scsi/lpfc/lpfc_mem.c index 6dc5ab8d671..3c0cebc7180 100644 --- a/drivers/scsi/lpfc/lpfc_mem.c +++ b/drivers/scsi/lpfc/lpfc_mem.c @@ -264,19 +264,30 @@ void lpfc_in_buf_free(struct lpfc_hba *phba, struct lpfc_dmabuf *mp) { struct hbq_dmabuf *hbq_entry; + unsigned long flags; + + if (!mp) + return; if (phba->sli3_options & LPFC_SLI3_HBQ_ENABLED) { + /* Check whether HBQ is still in use */ + spin_lock_irqsave(&phba->hbalock, flags); + if (!phba->hbq_in_use) { + spin_unlock_irqrestore(&phba->hbalock, flags); + return; + } hbq_entry = container_of(mp, struct hbq_dmabuf, dbuf); + list_del(&hbq_entry->dbuf.list); if (hbq_entry->tag == -1) { (phba->hbqs[LPFC_ELS_HBQ].hbq_free_buffer) (phba, hbq_entry); } else { lpfc_sli_free_hbq(phba, hbq_entry); } + spin_unlock_irqrestore(&phba->hbalock, flags); } else { lpfc_mbuf_free(phba, mp->virt, mp->phys); kfree(mp); } return; } - diff --git a/drivers/scsi/lpfc/lpfc_nportdisc.c b/drivers/scsi/lpfc/lpfc_nportdisc.c index 4a0e3406e37..d513813f669 100644 --- a/drivers/scsi/lpfc/lpfc_nportdisc.c +++ b/drivers/scsi/lpfc/lpfc_nportdisc.c @@ -1,7 +1,7 @@ /******************************************************************* * This file is part of the Emulex Linux Device Driver for * * Fibre Channel Host Bus Adapters. * - * Copyright (C) 2004-2007 Emulex. All rights reserved. * + * Copyright (C) 2004-2008 Emulex. All rights reserved. * * EMULEX and SLI are trademarks of Emulex. * * www.emulex.com * * Portions Copyright (C) 2004-2005 Christoph Hellwig * @@ -249,6 +249,7 @@ lpfc_rcv_plogi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, struct Scsi_Host *shost = lpfc_shost_from_vport(vport); struct lpfc_hba *phba = vport->phba; struct lpfc_dmabuf *pcmd; + struct lpfc_work_evt *evtp; uint32_t *lp; IOCB_t *icmd; struct serv_parm *sp; @@ -435,8 +436,14 @@ lpfc_rcv_plogi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, del_timer_sync(&ndlp->nlp_delayfunc); ndlp->nlp_last_elscmd = 0; - if (!list_empty(&ndlp->els_retry_evt.evt_listp)) + if (!list_empty(&ndlp->els_retry_evt.evt_listp)) { list_del_init(&ndlp->els_retry_evt.evt_listp); + /* Decrement ndlp reference count held for the + * delayed retry + */ + evtp = &ndlp->els_retry_evt; + lpfc_nlp_put((struct lpfc_nodelist *)evtp->evt_arg1); + } if (ndlp->nlp_flag & NLP_NPR_2B_DISC) { spin_lock_irq(shost->host_lock); @@ -638,13 +645,15 @@ lpfc_disc_set_adisc(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) return 0; } - /* Check config parameter use-adisc or FCP-2 */ - if ((vport->cfg_use_adisc && (vport->fc_flag & FC_RSCN_MODE)) || - ndlp->nlp_fcp_info & NLP_FCP_2_DEVICE) { - spin_lock_irq(shost->host_lock); - ndlp->nlp_flag |= NLP_NPR_ADISC; - spin_unlock_irq(shost->host_lock); - return 1; + if (!(vport->fc_flag & FC_PT2PT)) { + /* Check config parameter use-adisc or FCP-2 */ + if ((vport->cfg_use_adisc && (vport->fc_flag & FC_RSCN_MODE)) || + ndlp->nlp_fcp_info & NLP_FCP_2_DEVICE) { + spin_lock_irq(shost->host_lock); + ndlp->nlp_flag |= NLP_NPR_ADISC; + spin_unlock_irq(shost->host_lock); + return 1; + } } ndlp->nlp_flag &= ~NLP_NPR_ADISC; lpfc_unreg_rpi(vport, ndlp); @@ -656,7 +665,7 @@ lpfc_disc_illegal(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, void *arg, uint32_t evt) { lpfc_printf_vlog(vport, KERN_ERR, LOG_DISCOVERY, - "0253 Illegal State Transition: node x%x " + "0271 Illegal State Transition: node x%x " "event x%x, state x%x Data: x%x x%x\n", ndlp->nlp_DID, evt, ndlp->nlp_state, ndlp->nlp_rpi, ndlp->nlp_flag); @@ -674,7 +683,7 @@ lpfc_cmpl_plogi_illegal(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, */ if (!(ndlp->nlp_flag & NLP_RCV_PLOGI)) { lpfc_printf_vlog(vport, KERN_ERR, LOG_DISCOVERY, - "0253 Illegal State Transition: node x%x " + "0272 Illegal State Transition: node x%x " "event x%x, state x%x Data: x%x x%x\n", ndlp->nlp_DID, evt, ndlp->nlp_state, ndlp->nlp_rpi, ndlp->nlp_flag); @@ -2144,8 +2153,11 @@ lpfc_disc_state_machine(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, uint32_t cur_state, rc; uint32_t(*func) (struct lpfc_vport *, struct lpfc_nodelist *, void *, uint32_t); + uint32_t got_ndlp = 0; + + if (lpfc_nlp_get(ndlp)) + got_ndlp = 1; - lpfc_nlp_get(ndlp); cur_state = ndlp->nlp_state; /* DSM in event <evt> on NPort <nlp_DID> in state <cur_state> */ @@ -2162,15 +2174,24 @@ lpfc_disc_state_machine(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, rc = (func) (vport, ndlp, arg, evt); /* DSM out state <rc> on NPort <nlp_DID> */ - lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY, + if (got_ndlp) { + lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY, "0212 DSM out state %d on NPort x%x Data: x%x\n", rc, ndlp->nlp_DID, ndlp->nlp_flag); - lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_DSM, - "DSM out: ste:%d did:x%x flg:x%x", - rc, ndlp->nlp_DID, ndlp->nlp_flag); + lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_DSM, + "DSM out: ste:%d did:x%x flg:x%x", + rc, ndlp->nlp_DID, ndlp->nlp_flag); + /* Decrement the ndlp reference count held for this function */ + lpfc_nlp_put(ndlp); + } else { + lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY, + "0212 DSM out state %d on NPort free\n", rc); - lpfc_nlp_put(ndlp); + lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_DSM, + "DSM out: ste:%d did:x%x flg:x%x", + rc, 0, 0); + } return rc; } diff --git a/drivers/scsi/lpfc/lpfc_scsi.c b/drivers/scsi/lpfc/lpfc_scsi.c index fc5c3a42b05..70255c11d3a 100644 --- a/drivers/scsi/lpfc/lpfc_scsi.c +++ b/drivers/scsi/lpfc/lpfc_scsi.c @@ -1,7 +1,7 @@ /******************************************************************* * This file is part of the Emulex Linux Device Driver for * * Fibre Channel Host Bus Adapters. * - * Copyright (C) 2004-2007 Emulex. All rights reserved. * + * Copyright (C) 2004-2008 Emulex. All rights reserved. * * EMULEX and SLI are trademarks of Emulex. * * www.emulex.com * * Portions Copyright (C) 2004-2005 Christoph Hellwig * @@ -1283,6 +1283,8 @@ lpfc_bus_reset_handler(struct scsi_cmnd *cmnd) match = 0; spin_lock_irq(shost->host_lock); list_for_each_entry(ndlp, &vport->fc_nodes, nlp_listp) { + if (!NLP_CHK_NODE_ACT(ndlp)) + continue; if (ndlp->nlp_state == NLP_STE_MAPPED_NODE && i == ndlp->nlp_sid && ndlp->rport) { diff --git a/drivers/scsi/lpfc/lpfc_sli.c b/drivers/scsi/lpfc/lpfc_sli.c index fdd01e384e3..f53206411cd 100644 --- a/drivers/scsi/lpfc/lpfc_sli.c +++ b/drivers/scsi/lpfc/lpfc_sli.c @@ -1,7 +1,7 @@ /******************************************************************* * This file is part of the Emulex Linux Device Driver for * * Fibre Channel Host Bus Adapters. * - * Copyright (C) 2004-2007 Emulex. All rights reserved. * + * Copyright (C) 2004-2008 Emulex. All rights reserved. * * EMULEX and SLI are trademarks of Emulex. * * www.emulex.com * * Portions Copyright (C) 2004-2005 Christoph Hellwig * @@ -203,8 +203,25 @@ lpfc_sli_iocb_cmd_type(uint8_t iocb_cmnd) case CMD_IOCB_RCV_SEQ64_CX: case CMD_IOCB_RCV_ELS64_CX: case CMD_IOCB_RCV_CONT64_CX: + case CMD_IOCB_RET_XRI64_CX: type = LPFC_UNSOL_IOCB; break; + case CMD_IOCB_XMIT_MSEQ64_CR: + case CMD_IOCB_XMIT_MSEQ64_CX: + case CMD_IOCB_RCV_SEQ_LIST64_CX: + case CMD_IOCB_RCV_ELS_LIST64_CX: + case CMD_IOCB_CLOSE_EXTENDED_CN: + case CMD_IOCB_ABORT_EXTENDED_CN: + case CMD_IOCB_RET_HBQE64_CN: + case CMD_IOCB_FCP_IBIDIR64_CR: + case CMD_IOCB_FCP_IBIDIR64_CX: + case CMD_IOCB_FCP_ITASKMGT64_CX: + case CMD_IOCB_LOGENTRY_CN: + case CMD_IOCB_LOGENTRY_ASYNC_CN: + printk("%s - Unhandled SLI-3 Command x%x\n", + __FUNCTION__, iocb_cmnd); + type = LPFC_UNKNOWN_IOCB; + break; default: type = LPFC_UNKNOWN_IOCB; break; @@ -529,10 +546,13 @@ lpfc_sli_hbqbuf_free_all(struct lpfc_hba *phba) { struct lpfc_dmabuf *dmabuf, *next_dmabuf; struct hbq_dmabuf *hbq_buf; + unsigned long flags; int i, hbq_count; + uint32_t hbqno; hbq_count = lpfc_sli_hbq_count(); /* Return all memory used by all HBQs */ + spin_lock_irqsave(&phba->hbalock, flags); for (i = 0; i < hbq_count; ++i) { list_for_each_entry_safe(dmabuf, next_dmabuf, &phba->hbqs[i].hbq_buffer_list, list) { @@ -542,6 +562,28 @@ lpfc_sli_hbqbuf_free_all(struct lpfc_hba *phba) } phba->hbqs[i].buffer_count = 0; } + /* Return all HBQ buffer that are in-fly */ + list_for_each_entry_safe(dmabuf, next_dmabuf, + &phba->hbqbuf_in_list, list) { + hbq_buf = container_of(dmabuf, struct hbq_dmabuf, dbuf); + list_del(&hbq_buf->dbuf.list); + if (hbq_buf->tag == -1) { + (phba->hbqs[LPFC_ELS_HBQ].hbq_free_buffer) + (phba, hbq_buf); + } else { + hbqno = hbq_buf->tag >> 16; + if (hbqno >= LPFC_MAX_HBQS) + (phba->hbqs[LPFC_ELS_HBQ].hbq_free_buffer) + (phba, hbq_buf); + else + (phba->hbqs[hbqno].hbq_free_buffer)(phba, + hbq_buf); + } + } + + /* Mark the HBQs not in use */ + phba->hbq_in_use = 0; + spin_unlock_irqrestore(&phba->hbalock, flags); } static struct lpfc_hbq_entry * @@ -603,6 +645,7 @@ static int lpfc_sli_hbqbuf_fill_hbqs(struct lpfc_hba *phba, uint32_t hbqno, uint32_t count) { uint32_t i, start, end; + unsigned long flags; struct hbq_dmabuf *hbq_buffer; if (!phba->hbqs[hbqno].hbq_alloc_buffer) { @@ -615,6 +658,13 @@ lpfc_sli_hbqbuf_fill_hbqs(struct lpfc_hba *phba, uint32_t hbqno, uint32_t count) end = lpfc_hbq_defs[hbqno]->entry_count; } + /* Check whether HBQ is still in use */ + spin_lock_irqsave(&phba->hbalock, flags); + if (!phba->hbq_in_use) { + spin_unlock_irqrestore(&phba->hbalock, flags); + return 0; + } + /* Populate HBQ entries */ for (i = start; i < end; i++) { hbq_buffer = (phba->hbqs[hbqno].hbq_alloc_buffer)(phba); @@ -626,6 +676,8 @@ lpfc_sli_hbqbuf_fill_hbqs(struct lpfc_hba *phba, uint32_t hbqno, uint32_t count) else (phba->hbqs[hbqno].hbq_free_buffer)(phba, hbq_buffer); } + + spin_unlock_irqrestore(&phba->hbalock, flags); return 0; } @@ -910,16 +962,29 @@ lpfc_sli_replace_hbqbuff(struct lpfc_hba *phba, uint32_t tag) uint32_t hbqno; void *virt; /* virtual address ptr */ dma_addr_t phys; /* mapped address */ + unsigned long flags; + + /* Check whether HBQ is still in use */ + spin_lock_irqsave(&phba->hbalock, flags); + if (!phba->hbq_in_use) { + spin_unlock_irqrestore(&phba->hbalock, flags); + return NULL; + } hbq_entry = lpfc_sli_hbqbuf_find(phba, tag); - if (hbq_entry == NULL) + if (hbq_entry == NULL) { + spin_unlock_irqrestore(&phba->hbalock, flags); return NULL; + } list_del(&hbq_entry->dbuf.list); hbqno = tag >> 16; new_hbq_entry = (phba->hbqs[hbqno].hbq_alloc_buffer)(phba); - if (new_hbq_entry == NULL) + if (new_hbq_entry == NULL) { + list_add_tail(&hbq_entry->dbuf.list, &phba->hbqbuf_in_list); + spin_unlock_irqrestore(&phba->hbalock, flags); return &hbq_entry->dbuf; + } new_hbq_entry->tag = -1; phys = new_hbq_entry->dbuf.phys; virt = new_hbq_entry->dbuf.virt; @@ -928,6 +993,9 @@ lpfc_sli_replace_hbqbuff(struct lpfc_hba *phba, uint32_t tag) hbq_entry->dbuf.phys = phys; hbq_entry->dbuf.virt = virt; lpfc_sli_free_hbq(phba, hbq_entry); + list_add_tail(&new_hbq_entry->dbuf.list, &phba->hbqbuf_in_list); + spin_unlock_irqrestore(&phba->hbalock, flags); + return &new_hbq_entry->dbuf; } @@ -951,6 +1019,7 @@ lpfc_sli_process_unsol_iocb(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, uint32_t Rctl, Type; uint32_t match, i; struct lpfc_iocbq *iocbq; + struct lpfc_dmabuf *dmzbuf; match = 0; irsp = &(saveq->iocb); @@ -972,6 +1041,29 @@ lpfc_sli_process_unsol_iocb(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, return 1; } + if ((irsp->ulpCommand == CMD_IOCB_RET_XRI64_CX) && + (phba->sli3_options & LPFC_SLI3_HBQ_ENABLED)) { + if (irsp->ulpBdeCount > 0) { + dmzbuf = lpfc_sli_get_buff(phba, pring, + irsp->un.ulpWord[3]); + lpfc_in_buf_free(phba, dmzbuf); + } + + if (irsp->ulpBdeCount > 1) { + dmzbuf = lpfc_sli_get_buff(phba, pring, + irsp->unsli3.sli3Words[3]); + lpfc_in_buf_free(phba, dmzbuf); + } + + if (irsp->ulpBdeCount > 2) { + dmzbuf = lpfc_sli_get_buff(phba, pring, + irsp->unsli3.sli3Words[7]); + lpfc_in_buf_free(phba, dmzbuf); + } + + return 1; + } + if (phba->sli3_options & LPFC_SLI3_HBQ_ENABLED) { if (irsp->ulpBdeCount != 0) { saveq->context2 = lpfc_sli_get_buff(phba, pring, @@ -2293,6 +2385,7 @@ lpfc_sli_hbq_setup(struct lpfc_hba *phba) /* Initialize the struct lpfc_sli_hbq structure for each hbq */ phba->link_state = LPFC_INIT_MBX_CMDS; + phba->hbq_in_use = 1; hbq_entry_index = 0; for (hbqno = 0; hbqno < hbq_count; ++hbqno) { @@ -2404,9 +2497,7 @@ lpfc_do_config_port(struct lpfc_hba *phba, int sli_mode) if ((pmb->mb.un.varCfgPort.sli_mode == 3) && (!pmb->mb.un.varCfgPort.cMA)) { rc = -ENXIO; - goto do_prep_failed; } - return rc; do_prep_failed: mempool_free(pmb, phba->mbox_mem_pool); @@ -2625,14 +2716,14 @@ lpfc_sli_issue_mbox(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmbox, uint32_t flag) spin_unlock_irqrestore(&phba->hbalock, drvr_flag); /* Mbox command <mbxCommand> cannot issue */ - LOG_MBOX_CANNOT_ISSUE_DATA(phba, pmbox, psli, flag) + LOG_MBOX_CANNOT_ISSUE_DATA(phba, pmbox, psli, flag); return MBX_NOT_FINISHED; } if (mb->mbxCommand != MBX_KILL_BOARD && flag & MBX_NOWAIT && !(readl(phba->HCregaddr) & HC_MBINT_ENA)) { spin_unlock_irqrestore(&phba->hbalock, drvr_flag); - LOG_MBOX_CANNOT_ISSUE_DATA(phba, pmbox, psli, flag) + LOG_MBOX_CANNOT_ISSUE_DATA(phba, pmbox, psli, flag); return MBX_NOT_FINISHED; } diff --git a/drivers/scsi/lpfc/lpfc_version.h b/drivers/scsi/lpfc/lpfc_version.h index 4b633d39a82..ca540d1d041 100644 --- a/drivers/scsi/lpfc/lpfc_version.h +++ b/drivers/scsi/lpfc/lpfc_version.h @@ -18,7 +18,7 @@ * included with this package. * *******************************************************************/ -#define LPFC_DRIVER_VERSION "8.2.4" +#define LPFC_DRIVER_VERSION "8.2.5" #define LPFC_DRIVER_NAME "lpfc" diff --git a/drivers/scsi/lpfc/lpfc_vport.c b/drivers/scsi/lpfc/lpfc_vport.c index 9fad7663c11..86d05beb00b 100644 --- a/drivers/scsi/lpfc/lpfc_vport.c +++ b/drivers/scsi/lpfc/lpfc_vport.c @@ -1,7 +1,7 @@ /******************************************************************* * This file is part of the Emulex Linux Device Driver for * * Fibre Channel Host Bus Adapters. * - * Copyright (C) 2004-2006 Emulex. All rights reserved. * + * Copyright (C) 2004-2008 Emulex. All rights reserved. * * EMULEX and SLI are trademarks of Emulex. * * www.emulex.com * * Portions Copyright (C) 2004-2005 Christoph Hellwig * @@ -327,7 +327,8 @@ lpfc_vport_create(struct fc_vport *fc_vport, bool disable) * up and ready to FDISC. */ ndlp = lpfc_findnode_did(phba->pport, Fabric_DID); - if (ndlp && ndlp->nlp_state == NLP_STE_UNMAPPED_NODE) { + if (ndlp && NLP_CHK_NODE_ACT(ndlp) && + ndlp->nlp_state == NLP_STE_UNMAPPED_NODE) { if (phba->link_flag & LS_NPIV_FAB_SUPPORTED) { lpfc_set_disctmo(vport); lpfc_initial_fdisc(vport); @@ -358,7 +359,8 @@ disable_vport(struct fc_vport *fc_vport) long timeout; ndlp = lpfc_findnode_did(vport, Fabric_DID); - if (ndlp && phba->link_state >= LPFC_LINK_UP) { + if (ndlp && NLP_CHK_NODE_ACT(ndlp) + && phba->link_state >= LPFC_LINK_UP) { vport->unreg_vpi_cmpl = VPORT_INVAL; timeout = msecs_to_jiffies(phba->fc_ratov * 2000); if (!lpfc_issue_els_npiv_logo(vport, ndlp)) @@ -372,6 +374,8 @@ disable_vport(struct fc_vport *fc_vport) * calling lpfc_cleanup_rpis(vport, 1) */ list_for_each_entry_safe(ndlp, next_ndlp, &vport->fc_nodes, nlp_listp) { + if (!NLP_CHK_NODE_ACT(ndlp)) + continue; if (ndlp->nlp_state == NLP_STE_UNUSED_NODE) continue; lpfc_disc_state_machine(vport, ndlp, NULL, @@ -414,7 +418,8 @@ enable_vport(struct fc_vport *fc_vport) * up and ready to FDISC. */ ndlp = lpfc_findnode_did(phba->pport, Fabric_DID); - if (ndlp && ndlp->nlp_state == NLP_STE_UNMAPPED_NODE) { + if (ndlp && NLP_CHK_NODE_ACT(ndlp) + && ndlp->nlp_state == NLP_STE_UNMAPPED_NODE) { if (phba->link_flag & LS_NPIV_FAB_SUPPORTED) { lpfc_set_disctmo(vport); lpfc_initial_fdisc(vport); @@ -498,7 +503,41 @@ lpfc_vport_delete(struct fc_vport *fc_vport) scsi_remove_host(lpfc_shost_from_vport(vport)); ndlp = lpfc_findnode_did(phba->pport, Fabric_DID); - if (ndlp && ndlp->nlp_state == NLP_STE_UNMAPPED_NODE && + + /* In case of driver unload, we shall not perform fabric logo as the + * worker thread already stopped at this stage and, in this case, we + * can safely skip the fabric logo. + */ + if (phba->pport->load_flag & FC_UNLOADING) { + if (ndlp && NLP_CHK_NODE_ACT(ndlp) && + ndlp->nlp_state == NLP_STE_UNMAPPED_NODE && + phba->link_state >= LPFC_LINK_UP) { + /* First look for the Fabric ndlp */ + ndlp = lpfc_findnode_did(vport, Fabric_DID); + if (!ndlp) + goto skip_logo; + else if (!NLP_CHK_NODE_ACT(ndlp)) { + ndlp = lpfc_enable_node(vport, ndlp, + NLP_STE_UNUSED_NODE); + if (!ndlp) + goto skip_logo; + } + /* Remove ndlp from vport npld list */ + lpfc_dequeue_node(vport, ndlp); + + /* Indicate free memory when release */ + spin_lock_irq(&phba->ndlp_lock); + NLP_SET_FREE_REQ(ndlp); + spin_unlock_irq(&phba->ndlp_lock); + /* Kick off release ndlp when it can be safely done */ + lpfc_nlp_put(ndlp); + } + goto skip_logo; + } + + /* Otherwise, we will perform fabric logo as needed */ + if (ndlp && NLP_CHK_NODE_ACT(ndlp) && + ndlp->nlp_state == NLP_STE_UNMAPPED_NODE && phba->link_state >= LPFC_LINK_UP) { if (vport->cfg_enable_da_id) { timeout = msecs_to_jiffies(phba->fc_ratov * 2000); @@ -519,8 +558,27 @@ lpfc_vport_delete(struct fc_vport *fc_vport) if (!ndlp) goto skip_logo; lpfc_nlp_init(vport, ndlp, Fabric_DID); + /* Indicate free memory when release */ + NLP_SET_FREE_REQ(ndlp); } else { + if (!NLP_CHK_NODE_ACT(ndlp)) + ndlp = lpfc_enable_node(vport, ndlp, + NLP_STE_UNUSED_NODE); + if (!ndlp) + goto skip_logo; + + /* Remove ndlp from vport npld list */ lpfc_dequeue_node(vport, ndlp); + spin_lock_irq(&phba->ndlp_lock); + if (!NLP_CHK_FREE_REQ(ndlp)) + /* Indicate free memory when release */ + NLP_SET_FREE_REQ(ndlp); + else { + /* Skip this if ndlp is already in free mode */ + spin_unlock_irq(&phba->ndlp_lock); + goto skip_logo; + } + spin_unlock_irq(&phba->ndlp_lock); } vport->unreg_vpi_cmpl = VPORT_INVAL; timeout = msecs_to_jiffies(phba->fc_ratov * 2000); @@ -534,9 +592,9 @@ skip_logo: lpfc_sli_host_down(vport); lpfc_stop_vport_timers(vport); - lpfc_unreg_all_rpis(vport); if (!(phba->pport->load_flag & FC_UNLOADING)) { + lpfc_unreg_all_rpis(vport); lpfc_unreg_default_rpis(vport); /* * Completion of unreg_vpi (lpfc_mbx_cmpl_unreg_vpi) diff --git a/drivers/scsi/megaraid/megaraid_mm.c b/drivers/scsi/megaraid/megaraid_mm.c index b6587a6d848..0ad215e27b8 100644 --- a/drivers/scsi/megaraid/megaraid_mm.c +++ b/drivers/scsi/megaraid/megaraid_mm.c @@ -59,7 +59,6 @@ EXPORT_SYMBOL(mraid_mm_register_adp); EXPORT_SYMBOL(mraid_mm_unregister_adp); EXPORT_SYMBOL(mraid_mm_adapter_app_handle); -static int majorno; static uint32_t drvr_ver = 0x02200207; static int adapters_count_g; @@ -76,6 +75,12 @@ static const struct file_operations lsi_fops = { .owner = THIS_MODULE, }; +static struct miscdevice megaraid_mm_dev = { + .minor = MISC_DYNAMIC_MINOR, + .name = "megadev0", + .fops = &lsi_fops, +}; + /** * mraid_mm_open - open routine for char node interface * @inode : unused @@ -1184,15 +1189,16 @@ mraid_mm_teardown_dma_pools(mraid_mmadp_t *adp) static int __init mraid_mm_init(void) { + int err; + // Announce the driver version con_log(CL_ANN, (KERN_INFO "megaraid cmm: %s %s\n", LSI_COMMON_MOD_VERSION, LSI_COMMON_MOD_EXT_VERSION)); - majorno = register_chrdev(0, "megadev", &lsi_fops); - - if (majorno < 0) { - con_log(CL_ANN, ("megaraid cmm: cannot get major\n")); - return majorno; + err = misc_register(&megaraid_mm_dev); + if (err < 0) { + con_log(CL_ANN, ("megaraid cmm: cannot register misc device\n")); + return err; } init_waitqueue_head(&wait_q); @@ -1230,7 +1236,7 @@ mraid_mm_exit(void) { con_log(CL_DLEVEL1 , ("exiting common mod\n")); - unregister_chrdev(majorno, "megadev"); + misc_deregister(&megaraid_mm_dev); } module_init(mraid_mm_init); diff --git a/drivers/scsi/megaraid/megaraid_mm.h b/drivers/scsi/megaraid/megaraid_mm.h index c8762b2b8ed..55b425c0a65 100644 --- a/drivers/scsi/megaraid/megaraid_mm.h +++ b/drivers/scsi/megaraid/megaraid_mm.h @@ -22,6 +22,7 @@ #include <linux/moduleparam.h> #include <linux/pci.h> #include <linux/list.h> +#include <linux/miscdevice.h> #include "mbox_defs.h" #include "megaraid_ioctl.h" diff --git a/drivers/scsi/ses.c b/drivers/scsi/ses.c index 2a6e4f472ea..a57fed47b39 100644 --- a/drivers/scsi/ses.c +++ b/drivers/scsi/ses.c @@ -416,11 +416,11 @@ static int ses_intf_add(struct class_device *cdev, int i, j, types, len, components = 0; int err = -ENOMEM; struct enclosure_device *edev; - struct ses_component *scomp; + struct ses_component *scomp = NULL; if (!scsi_device_enclosure(sdev)) { /* not an enclosure, but might be in one */ - edev = enclosure_find(&sdev->host->shost_gendev); + edev = enclosure_find(&sdev->host->shost_gendev); if (edev) { ses_match_to_enclosure(edev, sdev); class_device_put(&edev->cdev); @@ -456,9 +456,6 @@ static int ses_intf_add(struct class_device *cdev, if (!buf) goto err_free; - ses_dev->page1 = buf; - ses_dev->page1_len = len; - result = ses_recv_diag(sdev, 1, buf, len); if (result) goto recv_failed; @@ -473,6 +470,9 @@ static int ses_intf_add(struct class_device *cdev, type_ptr[0] == ENCLOSURE_COMPONENT_ARRAY_DEVICE) components += type_ptr[1]; } + ses_dev->page1 = buf; + ses_dev->page1_len = len; + buf = NULL; result = ses_recv_diag(sdev, 2, hdr_buf, INIT_ALLOC_SIZE); if (result) @@ -489,6 +489,7 @@ static int ses_intf_add(struct class_device *cdev, goto recv_failed; ses_dev->page2 = buf; ses_dev->page2_len = len; + buf = NULL; /* The additional information page --- allows us * to match up the devices */ @@ -506,11 +507,12 @@ static int ses_intf_add(struct class_device *cdev, goto recv_failed; ses_dev->page10 = buf; ses_dev->page10_len = len; + buf = NULL; no_page10: - scomp = kmalloc(sizeof(struct ses_component) * components, GFP_KERNEL); + scomp = kzalloc(sizeof(struct ses_component) * components, GFP_KERNEL); if (!scomp) - goto err_free; + goto err_free; edev = enclosure_register(cdev->dev, sdev->sdev_gendev.bus_id, components, &ses_enclosure_callbacks); @@ -521,10 +523,9 @@ static int ses_intf_add(struct class_device *cdev, edev->scratch = ses_dev; for (i = 0; i < components; i++) - edev->component[i].scratch = scomp++; + edev->component[i].scratch = scomp + i; /* Page 7 for the descriptors is optional */ - buf = NULL; result = ses_recv_diag(sdev, 7, hdr_buf, INIT_ALLOC_SIZE); if (result) goto simple_populate; @@ -532,6 +533,8 @@ static int ses_intf_add(struct class_device *cdev, len = (hdr_buf[2] << 8) + hdr_buf[3] + 4; /* add 1 for trailing '\0' we'll use */ buf = kzalloc(len + 1, GFP_KERNEL); + if (!buf) + goto simple_populate; result = ses_recv_diag(sdev, 7, buf, len); if (result) { simple_populate: @@ -598,6 +601,7 @@ static int ses_intf_add(struct class_device *cdev, err = -ENODEV; err_free: kfree(buf); + kfree(scomp); kfree(ses_dev->page10); kfree(ses_dev->page2); kfree(ses_dev->page1); @@ -630,6 +634,7 @@ static void ses_intf_remove(struct class_device *cdev, ses_dev = edev->scratch; edev->scratch = NULL; + kfree(ses_dev->page10); kfree(ses_dev->page1); kfree(ses_dev->page2); kfree(ses_dev); diff --git a/drivers/scsi/sym53c416.c b/drivers/scsi/sym53c416.c index 6325901e509..f7d279542fa 100644 --- a/drivers/scsi/sym53c416.c +++ b/drivers/scsi/sym53c416.c @@ -187,10 +187,10 @@ #define sym53c416_base_2 sym53c416_2 #define sym53c416_base_3 sym53c416_3 -static unsigned int sym53c416_base[2] = {0,0}; -static unsigned int sym53c416_base_1[2] = {0,0}; -static unsigned int sym53c416_base_2[2] = {0,0}; -static unsigned int sym53c416_base_3[2] = {0,0}; +static unsigned int sym53c416_base[2]; +static unsigned int sym53c416_base_1[2]; +static unsigned int sym53c416_base_2[2]; +static unsigned int sym53c416_base_3[2]; #endif @@ -621,25 +621,25 @@ int __init sym53c416_detect(struct scsi_host_template *tpnt) int ints[3]; ints[0] = 2; - if(sym53c416_base) + if(sym53c416_base[0]) { ints[1] = sym53c416_base[0]; ints[2] = sym53c416_base[1]; sym53c416_setup(NULL, ints); } - if(sym53c416_base_1) + if(sym53c416_base_1[0]) { ints[1] = sym53c416_base_1[0]; ints[2] = sym53c416_base_1[1]; sym53c416_setup(NULL, ints); } - if(sym53c416_base_2) + if(sym53c416_base_2[0]) { ints[1] = sym53c416_base_2[0]; ints[2] = sym53c416_base_2[1]; sym53c416_setup(NULL, ints); } - if(sym53c416_base_3) + if(sym53c416_base_3[0]) { ints[1] = sym53c416_base_3[0]; ints[2] = sym53c416_base_3[1]; diff --git a/drivers/serial/sh-sci.c b/drivers/serial/sh-sci.c index ddf63914453..9ce12cb2ceb 100644 --- a/drivers/serial/sh-sci.c +++ b/drivers/serial/sh-sci.c @@ -393,7 +393,7 @@ static void sci_init_pins_scif(struct uart_port *port, unsigned int cflag) if (cflag & CRTSCTS) { fcr_val |= SCFCR_MCE; } else { -#ifdef CONFIG_CPU_SUBTYPE_SH7343 +#if defined(CONFIG_CPU_SUBTYPE_SH7343) || defined(CONFIG_CPU_SUBTYPE_SH7366) /* Nothing */ #elif defined(CONFIG_CPU_SUBTYPE_SH7763) || \ defined(CONFIG_CPU_SUBTYPE_SH7780) || \ diff --git a/drivers/serial/sh-sci.h b/drivers/serial/sh-sci.h index f5764ebcfe0..01a9dd715f5 100644 --- a/drivers/serial/sh-sci.h +++ b/drivers/serial/sh-sci.h @@ -97,13 +97,18 @@ # define SCSCR_INIT(port) 0x0038 /* TIE=0,RIE=0,TE=1,RE=1,REIE=1 */ # define SCIF_ONLY # define PORT_PSCR 0xA405011E +#elif defined(CONFIG_CPU_SUBTYPE_SH7366) +# define SCPDR0 0xA405013E /* 16 bit SCIF0 PSDR */ +# define SCSPTR0 SCPDR0 +# define SCIF_ORER 0x0001 /* overrun error bit */ +# define SCSCR_INIT(port) 0x0038 /* TIE=0,RIE=0,TE=1,RE=1,REIE=1 */ +# define SCIF_ONLY #elif defined(CONFIG_CPU_SUBTYPE_SH4_202) # define SCSPTR2 0xffe80020 /* 16 bit SCIF */ # define SCIF_ORER 0x0001 /* overrun error bit */ # define SCSCR_INIT(port) 0x38 /* TIE=0,RIE=0,TE=1,RE=1,REIE=1 */ # define SCIF_ONLY #elif defined(CONFIG_CPU_SUBTYPE_SH5_101) || defined(CONFIG_CPU_SUBTYPE_SH5_103) -# include <asm/hardware.h> # define SCIF_BASE_ADDR 0x01030000 # define SCIF_ADDR_SH5 PHYS_PERIPHERAL_BLOCK+SCIF_BASE_ADDR # define SCIF_PTR2_OFFS 0x0000020 @@ -577,7 +582,7 @@ static inline int sci_rxd_in(struct uart_port *port) return ctrl_inw(SCSPTR3) & 0x0001 ? 1 : 0; /* SCIF */ return 1; } -#elif defined(CONFIG_CPU_SUBTYPE_SH7722) +#elif defined(CONFIG_CPU_SUBTYPE_SH7722) || defined(CONFIG_CPU_SUBTYPE_SH7366) static inline int sci_rxd_in(struct uart_port *port) { if (port->mapbase == 0xffe00000) diff --git a/drivers/sh/maple/maple.c b/drivers/sh/maple/maple.c index e52a6296ca4..9cfcfd8dad5 100644 --- a/drivers/sh/maple/maple.c +++ b/drivers/sh/maple/maple.c @@ -31,6 +31,7 @@ #include <asm/mach/dma.h> #include <asm/mach/sysasic.h> #include <asm/mach/maple.h> +#include <linux/delay.h> MODULE_AUTHOR("Yaegshi Takeshi, Paul Mundt, M.R. Brown, Adrian McMenamin"); MODULE_DESCRIPTION("Maple bus driver for Dreamcast"); @@ -53,12 +54,12 @@ static struct device maple_bus; static int subdevice_map[MAPLE_PORTS]; static unsigned long *maple_sendbuf, *maple_sendptr, *maple_lastptr; static unsigned long maple_pnp_time; -static int started, scanning, liststatus; +static int started, scanning, liststatus, realscan; static struct kmem_cache *maple_queue_cache; struct maple_device_specify { - int port; - int unit; + int port; + int unit; }; /** @@ -68,22 +69,22 @@ struct maple_device_specify { */ int maple_driver_register(struct device_driver *drv) { - if (!drv) - return -EINVAL; - drv->bus = &maple_bus_type; - return driver_register(drv); + if (!drv) + return -EINVAL; + drv->bus = &maple_bus_type; + return driver_register(drv); } EXPORT_SYMBOL_GPL(maple_driver_register); /* set hardware registers to enable next round of dma */ static void maplebus_dma_reset(void) { - ctrl_outl(MAPLE_MAGIC, MAPLE_RESET); - /* set trig type to 0 for software trigger, 1 for hardware (VBLANK) */ - ctrl_outl(1, MAPLE_TRIGTYPE); - ctrl_outl(MAPLE_2MBPS | MAPLE_TIMEOUT(50000), MAPLE_SPEED); - ctrl_outl(PHYSADDR(maple_sendbuf), MAPLE_DMAADDR); - ctrl_outl(1, MAPLE_ENABLE); + ctrl_outl(MAPLE_MAGIC, MAPLE_RESET); + /* set trig type to 0 for software trigger, 1 for hardware (VBLANK) */ + ctrl_outl(1, MAPLE_TRIGTYPE); + ctrl_outl(MAPLE_2MBPS | MAPLE_TIMEOUT(50000), MAPLE_SPEED); + ctrl_outl(PHYSADDR(maple_sendbuf), MAPLE_DMAADDR); + ctrl_outl(1, MAPLE_ENABLE); } /** @@ -94,27 +95,36 @@ static void maplebus_dma_reset(void) * @function: the function code for the device */ void maple_getcond_callback(struct maple_device *dev, - void (*callback) (struct mapleq * mq), - unsigned long interval, unsigned long function) + void (*callback) (struct mapleq *mq), + unsigned long interval, unsigned long function) { - dev->callback = callback; - dev->interval = interval; - dev->function = cpu_to_be32(function); - dev->when = jiffies; + dev->callback = callback; + dev->interval = interval; + dev->function = cpu_to_be32(function); + dev->when = jiffies; } EXPORT_SYMBOL_GPL(maple_getcond_callback); static int maple_dma_done(void) { - return (ctrl_inl(MAPLE_STATE) & 1) == 0; + return (ctrl_inl(MAPLE_STATE) & 1) == 0; } static void maple_release_device(struct device *dev) { - if (dev->type) { - kfree(dev->type->name); - kfree(dev->type); - } + struct maple_device *mdev; + struct mapleq *mq; + if (!dev) + return; + mdev = to_maple_dev(dev); + mq = mdev->mq; + if (mq) { + if (mq->recvbufdcsp) + kmem_cache_free(maple_queue_cache, mq->recvbufdcsp); + kfree(mq); + mq = NULL; + } + kfree(mdev); } /** @@ -123,60 +133,64 @@ static void maple_release_device(struct device *dev) */ void maple_add_packet(struct mapleq *mq) { - mutex_lock(&maple_list_lock); - list_add(&mq->list, &maple_waitq); - mutex_unlock(&maple_list_lock); + mutex_lock(&maple_list_lock); + list_add(&mq->list, &maple_waitq); + mutex_unlock(&maple_list_lock); } EXPORT_SYMBOL_GPL(maple_add_packet); -static struct mapleq *maple_allocq(struct maple_device *dev) +static struct mapleq *maple_allocq(struct maple_device *mdev) { - struct mapleq *mq; + struct mapleq *mq; - mq = kmalloc(sizeof(*mq), GFP_KERNEL); - if (!mq) - return NULL; + mq = kmalloc(sizeof(*mq), GFP_KERNEL); + if (!mq) + return NULL; - mq->dev = dev; - mq->recvbufdcsp = kmem_cache_zalloc(maple_queue_cache, GFP_KERNEL); - mq->recvbuf = (void *) P2SEGADDR(mq->recvbufdcsp); - if (!mq->recvbuf) { - kfree(mq); - return NULL; - } + mq->dev = mdev; + mq->recvbufdcsp = kmem_cache_zalloc(maple_queue_cache, GFP_KERNEL); + mq->recvbuf = (void *) P2SEGADDR(mq->recvbufdcsp); + if (!mq->recvbuf) { + kfree(mq); + return NULL; + } - return mq; + return mq; } static struct maple_device *maple_alloc_dev(int port, int unit) { - struct maple_device *dev; - - dev = kzalloc(sizeof(*dev), GFP_KERNEL); - if (!dev) - return NULL; - - dev->port = port; - dev->unit = unit; - dev->mq = maple_allocq(dev); - - if (!dev->mq) { - kfree(dev); - return NULL; - } - - return dev; + struct maple_device *mdev; + + mdev = kzalloc(sizeof(*mdev), GFP_KERNEL); + if (!mdev) + return NULL; + + mdev->port = port; + mdev->unit = unit; + mdev->mq = maple_allocq(mdev); + + if (!mdev->mq) { + kfree(mdev); + return NULL; + } + mdev->dev.bus = &maple_bus_type; + mdev->dev.parent = &maple_bus; + mdev->function = 0; + return mdev; } static void maple_free_dev(struct maple_device *mdev) { - if (!mdev) - return; - if (mdev->mq) { - kmem_cache_free(maple_queue_cache, mdev->mq->recvbufdcsp); - kfree(mdev->mq); - } - kfree(mdev); + if (!mdev) + return; + if (mdev->mq) { + if (mdev->mq->recvbufdcsp) + kmem_cache_free(maple_queue_cache, + mdev->mq->recvbufdcsp); + kfree(mdev->mq); + } + kfree(mdev); } /* process the command queue into a maple command block @@ -184,153 +198,162 @@ static void maple_free_dev(struct maple_device *mdev) */ static void maple_build_block(struct mapleq *mq) { - int port, unit, from, to, len; - unsigned long *lsendbuf = mq->sendbuf; + int port, unit, from, to, len; + unsigned long *lsendbuf = mq->sendbuf; - port = mq->dev->port & 3; - unit = mq->dev->unit; - len = mq->length; - from = port << 6; - to = (port << 6) | (unit > 0 ? (1 << (unit - 1)) & 0x1f : 0x20); + port = mq->dev->port & 3; + unit = mq->dev->unit; + len = mq->length; + from = port << 6; + to = (port << 6) | (unit > 0 ? (1 << (unit - 1)) & 0x1f : 0x20); - *maple_lastptr &= 0x7fffffff; - maple_lastptr = maple_sendptr; + *maple_lastptr &= 0x7fffffff; + maple_lastptr = maple_sendptr; - *maple_sendptr++ = (port << 16) | len | 0x80000000; - *maple_sendptr++ = PHYSADDR(mq->recvbuf); - *maple_sendptr++ = - mq->command | (to << 8) | (from << 16) | (len << 24); + *maple_sendptr++ = (port << 16) | len | 0x80000000; + *maple_sendptr++ = PHYSADDR(mq->recvbuf); + *maple_sendptr++ = + mq->command | (to << 8) | (from << 16) | (len << 24); - while (len-- > 0) - *maple_sendptr++ = *lsendbuf++; + while (len-- > 0) + *maple_sendptr++ = *lsendbuf++; } /* build up command queue */ static void maple_send(void) { - int i; - int maple_packets; - struct mapleq *mq, *nmq; - - if (!list_empty(&maple_sentq)) - return; - if (list_empty(&maple_waitq) || !maple_dma_done()) - return; - maple_packets = 0; - maple_sendptr = maple_lastptr = maple_sendbuf; - list_for_each_entry_safe(mq, nmq, &maple_waitq, list) { - maple_build_block(mq); - list_move(&mq->list, &maple_sentq); - if (maple_packets++ > MAPLE_MAXPACKETS) - break; - } - if (maple_packets > 0) { - for (i = 0; i < (1 << MAPLE_DMA_PAGES); i++) - dma_cache_sync(0, maple_sendbuf + i * PAGE_SIZE, - PAGE_SIZE, DMA_BIDIRECTIONAL); - } + int i; + int maple_packets; + struct mapleq *mq, *nmq; + + if (!list_empty(&maple_sentq)) + return; + if (list_empty(&maple_waitq) || !maple_dma_done()) + return; + maple_packets = 0; + maple_sendptr = maple_lastptr = maple_sendbuf; + list_for_each_entry_safe(mq, nmq, &maple_waitq, list) { + maple_build_block(mq); + list_move(&mq->list, &maple_sentq); + if (maple_packets++ > MAPLE_MAXPACKETS) + break; + } + if (maple_packets > 0) { + for (i = 0; i < (1 << MAPLE_DMA_PAGES); i++) + dma_cache_sync(0, maple_sendbuf + i * PAGE_SIZE, + PAGE_SIZE, DMA_BIDIRECTIONAL); + } } static int attach_matching_maple_driver(struct device_driver *driver, - void *devptr) + void *devptr) { - struct maple_driver *maple_drv; - struct maple_device *mdev; - - mdev = devptr; - maple_drv = to_maple_driver(driver); - if (mdev->devinfo.function & be32_to_cpu(maple_drv->function)) { - if (maple_drv->connect(mdev) == 0) { - mdev->driver = maple_drv; - return 1; - } - } - return 0; + struct maple_driver *maple_drv; + struct maple_device *mdev; + + mdev = devptr; + maple_drv = to_maple_driver(driver); + if (mdev->devinfo.function & be32_to_cpu(maple_drv->function)) { + if (maple_drv->connect(mdev) == 0) { + mdev->driver = maple_drv; + return 1; + } + } + return 0; } static void maple_detach_driver(struct maple_device *mdev) { - if (!mdev) - return; - if (mdev->driver) { - if (mdev->driver->disconnect) - mdev->driver->disconnect(mdev); - } - mdev->driver = NULL; - if (mdev->registered) { - maple_release_device(&mdev->dev); - device_unregister(&mdev->dev); - } - mdev->registered = 0; - maple_free_dev(mdev); + if (!mdev) + return; + if (mdev->driver) { + if (mdev->driver->disconnect) + mdev->driver->disconnect(mdev); + } + mdev->driver = NULL; + device_unregister(&mdev->dev); + mdev = NULL; } /* process initial MAPLE_COMMAND_DEVINFO for each device or port */ -static void maple_attach_driver(struct maple_device *dev) +static void maple_attach_driver(struct maple_device *mdev) { - char *p; - - char *recvbuf; - unsigned long function; - int matched, retval; - - recvbuf = dev->mq->recvbuf; - memcpy(&dev->devinfo, recvbuf + 4, sizeof(dev->devinfo)); - memcpy(dev->product_name, dev->devinfo.product_name, 30); - memcpy(dev->product_licence, dev->devinfo.product_licence, 60); - dev->product_name[30] = '\0'; - dev->product_licence[60] = '\0'; - - for (p = dev->product_name + 29; dev->product_name <= p; p--) - if (*p == ' ') - *p = '\0'; - else - break; - - for (p = dev->product_licence + 59; dev->product_licence <= p; p--) - if (*p == ' ') - *p = '\0'; - else - break; - - function = be32_to_cpu(dev->devinfo.function); - - if (function > 0x200) { - /* Do this silently - as not a real device */ - function = 0; - dev->driver = &maple_dummy_driver; - sprintf(dev->dev.bus_id, "%d:0.port", dev->port); - } else { - printk(KERN_INFO - "Maple bus at (%d, %d): Connected function 0x%lX\n", - dev->port, dev->unit, function); - - matched = - bus_for_each_drv(&maple_bus_type, NULL, dev, - attach_matching_maple_driver); - - if (matched == 0) { - /* Driver does not exist yet */ - printk(KERN_INFO - "No maple driver found for this device\n"); - dev->driver = &maple_dummy_driver; - } - - sprintf(dev->dev.bus_id, "%d:0%d.%lX", dev->port, - dev->unit, function); - } - dev->function = function; - dev->dev.bus = &maple_bus_type; - dev->dev.parent = &maple_bus; - dev->dev.release = &maple_release_device; - retval = device_register(&dev->dev); - if (retval) { - printk(KERN_INFO - "Maple bus: Attempt to register device (%x, %x) failed.\n", - dev->port, dev->unit); - maple_free_dev(dev); - } - dev->registered = 1; + char *p, *recvbuf; + unsigned long function; + int matched, retval; + + recvbuf = mdev->mq->recvbuf; + /* copy the data as individual elements in + * case of memory optimisation */ + memcpy(&mdev->devinfo.function, recvbuf + 4, 4); + memcpy(&mdev->devinfo.function_data[0], recvbuf + 8, 12); + memcpy(&mdev->devinfo.area_code, recvbuf + 20, 1); + memcpy(&mdev->devinfo.connector_direction, recvbuf + 21, 1); + memcpy(&mdev->devinfo.product_name[0], recvbuf + 22, 30); + memcpy(&mdev->devinfo.product_licence[0], recvbuf + 52, 60); + memcpy(&mdev->devinfo.standby_power, recvbuf + 112, 2); + memcpy(&mdev->devinfo.max_power, recvbuf + 114, 2); + memcpy(mdev->product_name, mdev->devinfo.product_name, 30); + mdev->product_name[30] = '\0'; + memcpy(mdev->product_licence, mdev->devinfo.product_licence, 60); + mdev->product_licence[60] = '\0'; + + for (p = mdev->product_name + 29; mdev->product_name <= p; p--) + if (*p == ' ') + *p = '\0'; + else + break; + for (p = mdev->product_licence + 59; mdev->product_licence <= p; p--) + if (*p == ' ') + *p = '\0'; + else + break; + + if (realscan) { + printk(KERN_INFO "Maple device detected: %s\n", + mdev->product_name); + printk(KERN_INFO "Maple device: %s\n", mdev->product_licence); + } + + function = be32_to_cpu(mdev->devinfo.function); + + if (function > 0x200) { + /* Do this silently - as not a real device */ + function = 0; + mdev->driver = &maple_dummy_driver; + sprintf(mdev->dev.bus_id, "%d:0.port", mdev->port); + } else { + if (realscan) + printk(KERN_INFO + "Maple bus at (%d, %d): Function 0x%lX\n", + mdev->port, mdev->unit, function); + + matched = + bus_for_each_drv(&maple_bus_type, NULL, mdev, + attach_matching_maple_driver); + + if (matched == 0) { + /* Driver does not exist yet */ + if (realscan) + printk(KERN_INFO + "No maple driver found.\n"); + mdev->driver = &maple_dummy_driver; + } + sprintf(mdev->dev.bus_id, "%d:0%d.%lX", mdev->port, + mdev->unit, function); + } + mdev->function = function; + mdev->dev.release = &maple_release_device; + retval = device_register(&mdev->dev); + if (retval) { + printk(KERN_INFO + "Maple bus: Attempt to register device" + " (%x, %x) failed.\n", + mdev->port, mdev->unit); + maple_free_dev(mdev); + mdev = NULL; + return; + } } /* @@ -340,270 +363,262 @@ static void maple_attach_driver(struct maple_device *dev) */ static int detach_maple_device(struct device *device, void *portptr) { - struct maple_device_specify *ds; - struct maple_device *mdev; - - ds = portptr; - mdev = to_maple_dev(device); - if (mdev->port == ds->port && mdev->unit == ds->unit) - return 1; - return 0; + struct maple_device_specify *ds; + struct maple_device *mdev; + + ds = portptr; + mdev = to_maple_dev(device); + if (mdev->port == ds->port && mdev->unit == ds->unit) + return 1; + return 0; } static int setup_maple_commands(struct device *device, void *ignored) { - struct maple_device *maple_dev = to_maple_dev(device); - - if ((maple_dev->interval > 0) - && time_after(jiffies, maple_dev->when)) { - maple_dev->when = jiffies + maple_dev->interval; - maple_dev->mq->command = MAPLE_COMMAND_GETCOND; - maple_dev->mq->sendbuf = &maple_dev->function; - maple_dev->mq->length = 1; - maple_add_packet(maple_dev->mq); - liststatus++; - } else { - if (time_after(jiffies, maple_pnp_time)) { - maple_dev->mq->command = MAPLE_COMMAND_DEVINFO; - maple_dev->mq->length = 0; - maple_add_packet(maple_dev->mq); - liststatus++; - } - } - - return 0; + struct maple_device *maple_dev = to_maple_dev(device); + + if ((maple_dev->interval > 0) + && time_after(jiffies, maple_dev->when)) { + maple_dev->when = jiffies + maple_dev->interval; + maple_dev->mq->command = MAPLE_COMMAND_GETCOND; + maple_dev->mq->sendbuf = &maple_dev->function; + maple_dev->mq->length = 1; + maple_add_packet(maple_dev->mq); + liststatus++; + } else { + if (time_after(jiffies, maple_pnp_time)) { + maple_dev->mq->command = MAPLE_COMMAND_DEVINFO; + maple_dev->mq->length = 0; + maple_add_packet(maple_dev->mq); + liststatus++; + } + } + + return 0; } /* VBLANK bottom half - implemented via workqueue */ static void maple_vblank_handler(struct work_struct *work) { - if (!maple_dma_done()) - return; - if (!list_empty(&maple_sentq)) - return; - ctrl_outl(0, MAPLE_ENABLE); - liststatus = 0; - bus_for_each_dev(&maple_bus_type, NULL, NULL, - setup_maple_commands); - if (time_after(jiffies, maple_pnp_time)) - maple_pnp_time = jiffies + MAPLE_PNP_INTERVAL; - if (liststatus && list_empty(&maple_sentq)) { - INIT_LIST_HEAD(&maple_sentq); - maple_send(); - } - maplebus_dma_reset(); + if (!maple_dma_done()) + return; + if (!list_empty(&maple_sentq)) + return; + ctrl_outl(0, MAPLE_ENABLE); + liststatus = 0; + bus_for_each_dev(&maple_bus_type, NULL, NULL, + setup_maple_commands); + if (time_after(jiffies, maple_pnp_time)) + maple_pnp_time = jiffies + MAPLE_PNP_INTERVAL; + if (liststatus && list_empty(&maple_sentq)) { + INIT_LIST_HEAD(&maple_sentq); + maple_send(); + } + maplebus_dma_reset(); } /* handle devices added via hotplugs - placing them on queue for DEVINFO*/ static void maple_map_subunits(struct maple_device *mdev, int submask) { - int retval, k, devcheck; - struct maple_device *mdev_add; - struct maple_device_specify ds; - - for (k = 0; k < 5; k++) { - ds.port = mdev->port; - ds.unit = k + 1; - retval = - bus_for_each_dev(&maple_bus_type, NULL, &ds, - detach_maple_device); - if (retval) { - submask = submask >> 1; - continue; - } - devcheck = submask & 0x01; - if (devcheck) { - mdev_add = maple_alloc_dev(mdev->port, k + 1); - if (!mdev_add) - return; - mdev_add->mq->command = MAPLE_COMMAND_DEVINFO; - mdev_add->mq->length = 0; - maple_add_packet(mdev_add->mq); - scanning = 1; - } - submask = submask >> 1; - } + int retval, k, devcheck; + struct maple_device *mdev_add; + struct maple_device_specify ds; + + for (k = 0; k < 5; k++) { + ds.port = mdev->port; + ds.unit = k + 1; + retval = + bus_for_each_dev(&maple_bus_type, NULL, &ds, + detach_maple_device); + if (retval) { + submask = submask >> 1; + continue; + } + devcheck = submask & 0x01; + if (devcheck) { + mdev_add = maple_alloc_dev(mdev->port, k + 1); + if (!mdev_add) + return; + mdev_add->mq->command = MAPLE_COMMAND_DEVINFO; + mdev_add->mq->length = 0; + maple_add_packet(mdev_add->mq); + scanning = 1; + } + submask = submask >> 1; + } } /* mark a device as removed */ static void maple_clean_submap(struct maple_device *mdev) { - int killbit; + int killbit; - killbit = (mdev->unit > 0 ? (1 << (mdev->unit - 1)) & 0x1f : 0x20); - killbit = ~killbit; - killbit &= 0xFF; - subdevice_map[mdev->port] = subdevice_map[mdev->port] & killbit; + killbit = (mdev->unit > 0 ? (1 << (mdev->unit - 1)) & 0x1f : 0x20); + killbit = ~killbit; + killbit &= 0xFF; + subdevice_map[mdev->port] = subdevice_map[mdev->port] & killbit; } /* handle empty port or hotplug removal */ static void maple_response_none(struct maple_device *mdev, - struct mapleq *mq) + struct mapleq *mq) { - if (mdev->unit != 0) { - list_del(&mq->list); - maple_clean_submap(mdev); - printk(KERN_INFO - "Maple bus device detaching at (%d, %d)\n", - mdev->port, mdev->unit); - maple_detach_driver(mdev); - return; - } - if (!started) { - printk(KERN_INFO "No maple devices attached to port %d\n", - mdev->port); - return; - } - maple_clean_submap(mdev); + if (mdev->unit != 0) { + list_del(&mq->list); + maple_clean_submap(mdev); + printk(KERN_INFO + "Maple bus device detaching at (%d, %d)\n", + mdev->port, mdev->unit); + maple_detach_driver(mdev); + return; + } + if (!started) { + printk(KERN_INFO "No maple devices attached to port %d\n", + mdev->port); + return; + } + maple_clean_submap(mdev); } /* preprocess hotplugs or scans */ static void maple_response_devinfo(struct maple_device *mdev, - char *recvbuf) + char *recvbuf) { - char submask; - if ((!started) || (scanning == 2)) { - maple_attach_driver(mdev); - return; - } - if (mdev->unit == 0) { - submask = recvbuf[2] & 0x1F; - if (submask ^ subdevice_map[mdev->port]) { - maple_map_subunits(mdev, submask); - subdevice_map[mdev->port] = submask; - } - } + char submask; + if ((!started) || (scanning == 2)) { + maple_attach_driver(mdev); + return; + } + if (mdev->unit == 0) { + submask = recvbuf[2] & 0x1F; + if (submask ^ subdevice_map[mdev->port]) { + maple_map_subunits(mdev, submask); + subdevice_map[mdev->port] = submask; + } + } } /* maple dma end bottom half - implemented via workqueue */ static void maple_dma_handler(struct work_struct *work) { - struct mapleq *mq, *nmq; - struct maple_device *dev; - char *recvbuf; - enum maple_code code; - - if (!maple_dma_done()) - return; - ctrl_outl(0, MAPLE_ENABLE); - if (!list_empty(&maple_sentq)) { - list_for_each_entry_safe(mq, nmq, &maple_sentq, list) { - recvbuf = mq->recvbuf; - code = recvbuf[0]; - dev = mq->dev; - switch (code) { - case MAPLE_RESPONSE_NONE: - maple_response_none(dev, mq); - break; - - case MAPLE_RESPONSE_DEVINFO: - maple_response_devinfo(dev, recvbuf); - break; - - case MAPLE_RESPONSE_DATATRF: - if (dev->callback) - dev->callback(mq); - break; - - case MAPLE_RESPONSE_FILEERR: - case MAPLE_RESPONSE_AGAIN: - case MAPLE_RESPONSE_BADCMD: - case MAPLE_RESPONSE_BADFUNC: - printk(KERN_DEBUG - "Maple non-fatal error 0x%X\n", - code); - break; - - case MAPLE_RESPONSE_ALLINFO: - printk(KERN_DEBUG - "Maple - extended device information not supported\n"); - break; - - case MAPLE_RESPONSE_OK: - break; - - default: - break; - } - } - INIT_LIST_HEAD(&maple_sentq); - if (scanning == 1) { - maple_send(); - scanning = 2; - } else - scanning = 0; - - if (started == 0) - started = 1; - } - maplebus_dma_reset(); + struct mapleq *mq, *nmq; + struct maple_device *dev; + char *recvbuf; + enum maple_code code; + + if (!maple_dma_done()) + return; + ctrl_outl(0, MAPLE_ENABLE); + if (!list_empty(&maple_sentq)) { + list_for_each_entry_safe(mq, nmq, &maple_sentq, list) { + recvbuf = mq->recvbuf; + code = recvbuf[0]; + dev = mq->dev; + switch (code) { + case MAPLE_RESPONSE_NONE: + maple_response_none(dev, mq); + break; + + case MAPLE_RESPONSE_DEVINFO: + maple_response_devinfo(dev, recvbuf); + break; + + case MAPLE_RESPONSE_DATATRF: + if (dev->callback) + dev->callback(mq); + break; + + case MAPLE_RESPONSE_FILEERR: + case MAPLE_RESPONSE_AGAIN: + case MAPLE_RESPONSE_BADCMD: + case MAPLE_RESPONSE_BADFUNC: + printk(KERN_DEBUG + "Maple non-fatal error 0x%X\n", + code); + break; + + case MAPLE_RESPONSE_ALLINFO: + printk(KERN_DEBUG + "Maple - extended device information" + " not supported\n"); + break; + + case MAPLE_RESPONSE_OK: + break; + + default: + break; + } + } + INIT_LIST_HEAD(&maple_sentq); + if (scanning == 1) { + maple_send(); + scanning = 2; + } else + scanning = 0; + + if (started == 0) + started = 1; + } + maplebus_dma_reset(); } static irqreturn_t maplebus_dma_interrupt(int irq, void *dev_id) { - /* Load everything into the bottom half */ - schedule_work(&maple_dma_process); - return IRQ_HANDLED; + /* Load everything into the bottom half */ + schedule_work(&maple_dma_process); + return IRQ_HANDLED; } static irqreturn_t maplebus_vblank_interrupt(int irq, void *dev_id) { - schedule_work(&maple_vblank_process); - return IRQ_HANDLED; + schedule_work(&maple_vblank_process); + return IRQ_HANDLED; } -static struct irqaction maple_dma_irq = { - .name = "maple bus DMA handler", - .handler = maplebus_dma_interrupt, - .flags = IRQF_SHARED, -}; - -static struct irqaction maple_vblank_irq = { - .name = "maple bus VBLANK handler", - .handler = maplebus_vblank_interrupt, - .flags = IRQF_SHARED, -}; - static int maple_set_dma_interrupt_handler(void) { - return setup_irq(HW_EVENT_MAPLE_DMA, &maple_dma_irq); + return request_irq(HW_EVENT_MAPLE_DMA, maplebus_dma_interrupt, + IRQF_SHARED, "maple bus DMA", &maple_dummy_driver); } static int maple_set_vblank_interrupt_handler(void) { - return setup_irq(HW_EVENT_VSYNC, &maple_vblank_irq); + return request_irq(HW_EVENT_VSYNC, maplebus_vblank_interrupt, + IRQF_SHARED, "maple bus VBLANK", &maple_dummy_driver); } static int maple_get_dma_buffer(void) { - maple_sendbuf = - (void *) __get_free_pages(GFP_KERNEL | __GFP_ZERO, - MAPLE_DMA_PAGES); - if (!maple_sendbuf) - return -ENOMEM; - return 0; + maple_sendbuf = + (void *) __get_free_pages(GFP_KERNEL | __GFP_ZERO, + MAPLE_DMA_PAGES); + if (!maple_sendbuf) + return -ENOMEM; + return 0; } static int match_maple_bus_driver(struct device *devptr, - struct device_driver *drvptr) + struct device_driver *drvptr) { - struct maple_driver *maple_drv; - struct maple_device *maple_dev; - - maple_drv = container_of(drvptr, struct maple_driver, drv); - maple_dev = container_of(devptr, struct maple_device, dev); - /* Trap empty port case */ - if (maple_dev->devinfo.function == 0xFFFFFFFF) - return 0; - else if (maple_dev->devinfo.function & - be32_to_cpu(maple_drv->function)) - return 1; - return 0; + struct maple_driver *maple_drv; + struct maple_device *maple_dev; + + maple_drv = container_of(drvptr, struct maple_driver, drv); + maple_dev = container_of(devptr, struct maple_device, dev); + /* Trap empty port case */ + if (maple_dev->devinfo.function == 0xFFFFFFFF) + return 0; + else if (maple_dev->devinfo.function & + be32_to_cpu(maple_drv->function)) + return 1; + return 0; } -static int maple_bus_uevent(struct device *dev, struct kobj_uevent_env *env) +static int maple_bus_uevent(struct device *dev, + struct kobj_uevent_env *env) { - return 0; + return 0; } static void maple_bus_release(struct device *dev) @@ -611,124 +626,122 @@ static void maple_bus_release(struct device *dev) } static struct maple_driver maple_dummy_driver = { - .drv = { - .name = "maple_dummy_driver", - .bus = &maple_bus_type, - }, + .drv = { + .name = "maple_dummy_driver", + .bus = &maple_bus_type, + }, }; struct bus_type maple_bus_type = { - .name = "maple", - .match = match_maple_bus_driver, - .uevent = maple_bus_uevent, + .name = "maple", + .match = match_maple_bus_driver, + .uevent = maple_bus_uevent, }; EXPORT_SYMBOL_GPL(maple_bus_type); static struct device maple_bus = { - .bus_id = "maple", - .release = maple_bus_release, + .bus_id = "maple", + .release = maple_bus_release, }; static int __init maple_bus_init(void) { - int retval, i; - struct maple_device *mdev[MAPLE_PORTS]; - ctrl_outl(0, MAPLE_STATE); - - retval = device_register(&maple_bus); - if (retval) - goto cleanup; - - retval = bus_register(&maple_bus_type); - if (retval) - goto cleanup_device; - - retval = driver_register(&maple_dummy_driver.drv); - - if (retval) - goto cleanup_bus; - - /* allocate memory for maple bus dma */ - retval = maple_get_dma_buffer(); - if (retval) { - printk(KERN_INFO - "Maple bus: Failed to allocate Maple DMA buffers\n"); - goto cleanup_basic; - } - - /* set up DMA interrupt handler */ - retval = maple_set_dma_interrupt_handler(); - if (retval) { - printk(KERN_INFO - "Maple bus: Failed to grab maple DMA IRQ\n"); - goto cleanup_dma; - } - - /* set up VBLANK interrupt handler */ - retval = maple_set_vblank_interrupt_handler(); - if (retval) { - printk(KERN_INFO "Maple bus: Failed to grab VBLANK IRQ\n"); - goto cleanup_irq; - } - - maple_queue_cache = - kmem_cache_create("maple_queue_cache", 0x400, 0, - SLAB_HWCACHE_ALIGN, NULL); - - if (!maple_queue_cache) - goto cleanup_bothirqs; - - /* setup maple ports */ - for (i = 0; i < MAPLE_PORTS; i++) { - mdev[i] = maple_alloc_dev(i, 0); - if (!mdev[i]) { - while (i-- > 0) - maple_free_dev(mdev[i]); - goto cleanup_cache; - } - mdev[i]->registered = 0; - mdev[i]->mq->command = MAPLE_COMMAND_DEVINFO; - mdev[i]->mq->length = 0; - maple_attach_driver(mdev[i]); - maple_add_packet(mdev[i]->mq); - subdevice_map[i] = 0; - } - - /* setup maplebus hardware */ - maplebus_dma_reset(); - - /* initial detection */ - maple_send(); - - maple_pnp_time = jiffies; - - printk(KERN_INFO "Maple bus core now registered.\n"); - - return 0; + int retval, i; + struct maple_device *mdev[MAPLE_PORTS]; + ctrl_outl(0, MAPLE_STATE); + + retval = device_register(&maple_bus); + if (retval) + goto cleanup; + + retval = bus_register(&maple_bus_type); + if (retval) + goto cleanup_device; + + retval = driver_register(&maple_dummy_driver.drv); + if (retval) + goto cleanup_bus; + + /* allocate memory for maple bus dma */ + retval = maple_get_dma_buffer(); + if (retval) { + printk(KERN_INFO + "Maple bus: Failed to allocate Maple DMA buffers\n"); + goto cleanup_basic; + } + + /* set up DMA interrupt handler */ + retval = maple_set_dma_interrupt_handler(); + if (retval) { + printk(KERN_INFO + "Maple bus: Failed to grab maple DMA IRQ\n"); + goto cleanup_dma; + } + + /* set up VBLANK interrupt handler */ + retval = maple_set_vblank_interrupt_handler(); + if (retval) { + printk(KERN_INFO "Maple bus: Failed to grab VBLANK IRQ\n"); + goto cleanup_irq; + } + + maple_queue_cache = + kmem_cache_create("maple_queue_cache", 0x400, 0, + SLAB_POISON|SLAB_HWCACHE_ALIGN, NULL); + + if (!maple_queue_cache) + goto cleanup_bothirqs; + + /* setup maple ports */ + for (i = 0; i < MAPLE_PORTS; i++) { + mdev[i] = maple_alloc_dev(i, 0); + if (!mdev[i]) { + while (i-- > 0) + maple_free_dev(mdev[i]); + goto cleanup_cache; + } + mdev[i]->mq->command = MAPLE_COMMAND_DEVINFO; + mdev[i]->mq->length = 0; + maple_add_packet(mdev[i]->mq); + /* delay aids hardware detection */ + mdelay(5); + subdevice_map[i] = 0; + } + + realscan = 1; + /* setup maplebus hardware */ + maplebus_dma_reset(); + /* initial detection */ + maple_send(); + maple_pnp_time = jiffies; + printk(KERN_INFO "Maple bus core now registered.\n"); + + return 0; cleanup_cache: - kmem_cache_destroy(maple_queue_cache); + kmem_cache_destroy(maple_queue_cache); cleanup_bothirqs: - free_irq(HW_EVENT_VSYNC, 0); + free_irq(HW_EVENT_VSYNC, 0); cleanup_irq: - free_irq(HW_EVENT_MAPLE_DMA, 0); + free_irq(HW_EVENT_MAPLE_DMA, 0); cleanup_dma: - free_pages((unsigned long) maple_sendbuf, MAPLE_DMA_PAGES); + free_pages((unsigned long) maple_sendbuf, MAPLE_DMA_PAGES); cleanup_basic: - driver_unregister(&maple_dummy_driver.drv); + driver_unregister(&maple_dummy_driver.drv); cleanup_bus: - bus_unregister(&maple_bus_type); + bus_unregister(&maple_bus_type); cleanup_device: - device_unregister(&maple_bus); + device_unregister(&maple_bus); cleanup: - printk(KERN_INFO "Maple bus registration failed\n"); - return retval; + printk(KERN_INFO "Maple bus registration failed\n"); + return retval; } -subsys_initcall(maple_bus_init); +/* Push init to later to ensure hardware gets detected */ +fs_initcall(maple_bus_init); diff --git a/drivers/usb/gadget/file_storage.c b/drivers/usb/gadget/file_storage.c index 3301167d4f2..017a196d041 100644 --- a/drivers/usb/gadget/file_storage.c +++ b/drivers/usb/gadget/file_storage.c @@ -3563,8 +3563,7 @@ static ssize_t show_file(struct device *dev, struct device_attribute *attr, down_read(&fsg->filesem); if (backing_file_is_open(curlun)) { // Get the complete pathname - p = d_path(curlun->filp->f_path.dentry, - curlun->filp->f_path.mnt, buf, PAGE_SIZE - 1); + p = d_path(&curlun->filp->f_path, buf, PAGE_SIZE - 1); if (IS_ERR(p)) rc = PTR_ERR(p); else { @@ -3981,9 +3980,8 @@ static int __init fsg_bind(struct usb_gadget *gadget) if (backing_file_is_open(curlun)) { p = NULL; if (pathbuf) { - p = d_path(curlun->filp->f_path.dentry, - curlun->filp->f_path.mnt, - pathbuf, PATH_MAX); + p = d_path(&curlun->filp->f_path, + pathbuf, PATH_MAX); if (IS_ERR(p)) p = NULL; } diff --git a/fs/afs/mntpt.c b/fs/afs/mntpt.c index 5ce43b63c60..a3510b8ba3e 100644 --- a/fs/afs/mntpt.c +++ b/fs/afs/mntpt.c @@ -218,16 +218,16 @@ static void *afs_mntpt_follow_link(struct dentry *dentry, struct nameidata *nd) _enter("%p{%s},{%s:%p{%s},}", dentry, dentry->d_name.name, - nd->mnt->mnt_devname, + nd->path.mnt->mnt_devname, dentry, - nd->dentry->d_name.name); + nd->path.dentry->d_name.name); - dput(nd->dentry); - nd->dentry = dget(dentry); + dput(nd->path.dentry); + nd->path.dentry = dget(dentry); - newmnt = afs_mntpt_do_automount(nd->dentry); + newmnt = afs_mntpt_do_automount(nd->path.dentry); if (IS_ERR(newmnt)) { - path_release(nd); + path_put(&nd->path); return (void *)newmnt; } @@ -235,17 +235,16 @@ static void *afs_mntpt_follow_link(struct dentry *dentry, struct nameidata *nd) err = do_add_mount(newmnt, nd, MNT_SHRINKABLE, &afs_vfsmounts); switch (err) { case 0: - dput(nd->dentry); - mntput(nd->mnt); - nd->mnt = newmnt; - nd->dentry = dget(newmnt->mnt_root); + path_put(&nd->path); + nd->path.mnt = newmnt; + nd->path.dentry = dget(newmnt->mnt_root); schedule_delayed_work(&afs_mntpt_expiry_timer, afs_mntpt_expiry_timeout * HZ); break; case -EBUSY: /* someone else made a mount here whilst we were busy */ - while (d_mountpoint(nd->dentry) && - follow_down(&nd->mnt, &nd->dentry)) + while (d_mountpoint(nd->path.dentry) && + follow_down(&nd->path.mnt, &nd->path.dentry)) ; err = 0; default: diff --git a/fs/autofs4/root.c b/fs/autofs4/root.c index 2bbcc8151dc..a54a946a50a 100644 --- a/fs/autofs4/root.c +++ b/fs/autofs4/root.c @@ -368,7 +368,8 @@ static void *autofs4_follow_link(struct dentry *dentry, struct nameidata *nd) * so we don't need to follow the mount. */ if (d_mountpoint(dentry)) { - if (!autofs4_follow_mount(&nd->mnt, &nd->dentry)) { + if (!autofs4_follow_mount(&nd->path.mnt, + &nd->path.dentry)) { status = -ENOENT; goto out_error; } @@ -382,7 +383,7 @@ done: return NULL; out_error: - path_release(nd); + path_put(&nd->path); return ERR_PTR(status); } diff --git a/fs/binfmt_flat.c b/fs/binfmt_flat.c index d8a02f1e08c..0498b181dd5 100644 --- a/fs/binfmt_flat.c +++ b/fs/binfmt_flat.c @@ -443,12 +443,12 @@ static int load_flat_file(struct linux_binprm * bprm, if (strncmp(hdr->magic, "bFLT", 4)) { /* + * Previously, here was a printk to tell people + * "BINFMT_FLAT: bad header magic". + * But for the kernel which also use ELF FD-PIC format, this + * error message is confusing. * because a lot of people do not manage to produce good - * flat binaries, we leave this printk to help them realise - * the problem. We only print the error if its not a script file */ - if (strncmp(hdr->magic, "#!", 2)) - printk("BINFMT_FLAT: bad header magic\n"); ret = -ENOEXEC; goto err; } diff --git a/fs/block_dev.c b/fs/block_dev.c index e63067d25cd..67fe72ce6ac 100644 --- a/fs/block_dev.c +++ b/fs/block_dev.c @@ -1397,19 +1397,19 @@ struct block_device *lookup_bdev(const char *path) if (error) return ERR_PTR(error); - inode = nd.dentry->d_inode; + inode = nd.path.dentry->d_inode; error = -ENOTBLK; if (!S_ISBLK(inode->i_mode)) goto fail; error = -EACCES; - if (nd.mnt->mnt_flags & MNT_NODEV) + if (nd.path.mnt->mnt_flags & MNT_NODEV) goto fail; error = -ENOMEM; bdev = bd_acquire(inode); if (!bdev) goto fail; out: - path_release(&nd); + path_put(&nd.path); return bdev; fail: bdev = ERR_PTR(error); diff --git a/fs/cifs/cifs_dfs_ref.c b/fs/cifs/cifs_dfs_ref.c index 413ee2349d1..6ad44752996 100644 --- a/fs/cifs/cifs_dfs_ref.c +++ b/fs/cifs/cifs_dfs_ref.c @@ -259,18 +259,18 @@ static int add_mount_helper(struct vfsmount *newmnt, struct nameidata *nd, int err; mntget(newmnt); - err = do_add_mount(newmnt, nd, nd->mnt->mnt_flags, mntlist); + err = do_add_mount(newmnt, nd, nd->path.mnt->mnt_flags, mntlist); switch (err) { case 0: - dput(nd->dentry); - mntput(nd->mnt); - nd->mnt = newmnt; - nd->dentry = dget(newmnt->mnt_root); + dput(nd->path.dentry); + mntput(nd->path.mnt); + nd->path.mnt = newmnt; + nd->path.dentry = dget(newmnt->mnt_root); break; case -EBUSY: /* someone else made a mount here whilst we were busy */ - while (d_mountpoint(nd->dentry) && - follow_down(&nd->mnt, &nd->dentry)) + while (d_mountpoint(nd->path.dentry) && + follow_down(&nd->path.mnt, &nd->path.dentry)) ; err = 0; default: @@ -307,8 +307,8 @@ cifs_dfs_follow_mountpoint(struct dentry *dentry, struct nameidata *nd) xid = GetXid(); - dput(nd->dentry); - nd->dentry = dget(dentry); + dput(nd->path.dentry); + nd->path.dentry = dget(dentry); cifs_sb = CIFS_SB(dentry->d_inode->i_sb); ses = cifs_sb->tcon->ses; @@ -340,7 +340,8 @@ cifs_dfs_follow_mountpoint(struct dentry *dentry, struct nameidata *nd) rc = -EINVAL; goto out_err; } - mnt = cifs_dfs_do_refmount(nd->mnt, nd->dentry, + mnt = cifs_dfs_do_refmount(nd->path.mnt, + nd->path.dentry, referrals[i].node_name); cFYI(1, ("%s: cifs_dfs_do_refmount:%s , mnt:%p", __FUNCTION__, @@ -357,7 +358,7 @@ cifs_dfs_follow_mountpoint(struct dentry *dentry, struct nameidata *nd) if (IS_ERR(mnt)) goto out_err; - nd->mnt->mnt_flags |= MNT_SHRINKABLE; + nd->path.mnt->mnt_flags |= MNT_SHRINKABLE; rc = add_mount_helper(mnt, nd, &cifs_dfs_automount_list); out: @@ -367,7 +368,7 @@ out: cFYI(1, ("leaving %s" , __FUNCTION__)); return ERR_PTR(rc); out_err: - path_release(nd); + path_put(&nd->path); goto out; } diff --git a/fs/coda/pioctl.c b/fs/coda/pioctl.c index 2bf3026adc8..c21a1f552a6 100644 --- a/fs/coda/pioctl.c +++ b/fs/coda/pioctl.c @@ -75,12 +75,12 @@ static int coda_pioctl(struct inode * inode, struct file * filp, if ( error ) { return error; } else { - target_inode = nd.dentry->d_inode; + target_inode = nd.path.dentry->d_inode; } /* return if it is not a Coda inode */ if ( target_inode->i_sb != inode->i_sb ) { - path_release(&nd); + path_put(&nd.path); return -EINVAL; } @@ -89,7 +89,7 @@ static int coda_pioctl(struct inode * inode, struct file * filp, error = venus_pioctl(inode->i_sb, &(cnp->c_fid), cmd, &data); - path_release(&nd); + path_put(&nd.path); return error; } diff --git a/fs/compat.c b/fs/compat.c index ee80ff341d3..2ce4456aad3 100644 --- a/fs/compat.c +++ b/fs/compat.c @@ -241,10 +241,10 @@ asmlinkage long compat_sys_statfs(const char __user *path, struct compat_statfs error = user_path_walk(path, &nd); if (!error) { struct kstatfs tmp; - error = vfs_statfs(nd.dentry, &tmp); + error = vfs_statfs(nd.path.dentry, &tmp); if (!error) error = put_compat_statfs(buf, &tmp); - path_release(&nd); + path_put(&nd.path); } return error; } @@ -309,10 +309,10 @@ asmlinkage long compat_sys_statfs64(const char __user *path, compat_size_t sz, s error = user_path_walk(path, &nd); if (!error) { struct kstatfs tmp; - error = vfs_statfs(nd.dentry, &tmp); + error = vfs_statfs(nd.path.dentry, &tmp); if (!error) error = put_compat_statfs64(buf, &tmp); - path_release(&nd); + path_put(&nd.path); } return error; } @@ -702,9 +702,6 @@ static int do_nfs4_super_data_conv(void *raw_data) real->flags = raw->flags; real->version = raw->version; } - else { - return -EINVAL; - } return 0; } diff --git a/fs/compat_ioctl.c b/fs/compat_ioctl.c index ee32c0eac7c..c6e72aebd16 100644 --- a/fs/compat_ioctl.c +++ b/fs/compat_ioctl.c @@ -2853,7 +2853,7 @@ static void compat_ioctl_error(struct file *filp, unsigned int fd, /* find the name of the device. */ path = (char *)__get_free_page(GFP_KERNEL); if (path) { - fn = d_path(filp->f_path.dentry, filp->f_path.mnt, path, PAGE_SIZE); + fn = d_path(&filp->f_path, path, PAGE_SIZE); if (IS_ERR(fn)) fn = "?"; } diff --git a/fs/configfs/symlink.c b/fs/configfs/symlink.c index 22700d2857d..78929ea84ff 100644 --- a/fs/configfs/symlink.c +++ b/fs/configfs/symlink.c @@ -99,11 +99,11 @@ static int get_target(const char *symname, struct nameidata *nd, ret = path_lookup(symname, LOOKUP_FOLLOW|LOOKUP_DIRECTORY, nd); if (!ret) { - if (nd->dentry->d_sb == configfs_sb) { - *target = configfs_get_config_item(nd->dentry); + if (nd->path.dentry->d_sb == configfs_sb) { + *target = configfs_get_config_item(nd->path.dentry); if (!*target) { ret = -ENOENT; - path_release(nd); + path_put(&nd->path); } } else ret = -EPERM; @@ -141,7 +141,7 @@ int configfs_symlink(struct inode *dir, struct dentry *dentry, const char *symna ret = create_link(parent_item, target_item, dentry); config_item_put(target_item); - path_release(&nd); + path_put(&nd.path); out_put: config_item_put(parent_item); diff --git a/fs/dcache.c b/fs/dcache.c index 44f6cf23b70..43455776711 100644 --- a/fs/dcache.c +++ b/fs/dcache.c @@ -95,6 +95,14 @@ static void d_free(struct dentry *dentry) call_rcu(&dentry->d_u.d_rcu, d_callback); } +static void dentry_lru_remove(struct dentry *dentry) +{ + if (!list_empty(&dentry->d_lru)) { + list_del_init(&dentry->d_lru); + dentry_stat.nr_unused--; + } +} + /* * Release the dentry's inode, using the filesystem * d_iput() operation if defined. @@ -211,13 +219,7 @@ repeat: unhash_it: __d_drop(dentry); kill_it: - /* If dentry was on d_lru list - * delete it from there - */ - if (!list_empty(&dentry->d_lru)) { - list_del(&dentry->d_lru); - dentry_stat.nr_unused--; - } + dentry_lru_remove(dentry); dentry = d_kill(dentry); if (dentry) goto repeat; @@ -285,10 +287,7 @@ int d_invalidate(struct dentry * dentry) static inline struct dentry * __dget_locked(struct dentry *dentry) { atomic_inc(&dentry->d_count); - if (!list_empty(&dentry->d_lru)) { - dentry_stat.nr_unused--; - list_del_init(&dentry->d_lru); - } + dentry_lru_remove(dentry); return dentry; } @@ -404,10 +403,7 @@ static void prune_one_dentry(struct dentry * dentry) if (dentry->d_op && dentry->d_op->d_delete) dentry->d_op->d_delete(dentry); - if (!list_empty(&dentry->d_lru)) { - list_del(&dentry->d_lru); - dentry_stat.nr_unused--; - } + dentry_lru_remove(dentry); __d_drop(dentry); dentry = d_kill(dentry); spin_lock(&dcache_lock); @@ -596,10 +592,7 @@ static void shrink_dcache_for_umount_subtree(struct dentry *dentry) /* detach this root from the system */ spin_lock(&dcache_lock); - if (!list_empty(&dentry->d_lru)) { - dentry_stat.nr_unused--; - list_del_init(&dentry->d_lru); - } + dentry_lru_remove(dentry); __d_drop(dentry); spin_unlock(&dcache_lock); @@ -613,11 +606,7 @@ static void shrink_dcache_for_umount_subtree(struct dentry *dentry) spin_lock(&dcache_lock); list_for_each_entry(loop, &dentry->d_subdirs, d_u.d_child) { - if (!list_empty(&loop->d_lru)) { - dentry_stat.nr_unused--; - list_del_init(&loop->d_lru); - } - + dentry_lru_remove(loop); __d_drop(loop); cond_resched_lock(&dcache_lock); } @@ -799,10 +788,7 @@ resume: struct dentry *dentry = list_entry(tmp, struct dentry, d_u.d_child); next = tmp->next; - if (!list_empty(&dentry->d_lru)) { - dentry_stat.nr_unused--; - list_del_init(&dentry->d_lru); - } + dentry_lru_remove(dentry); /* * move only zero ref count dentries to the end * of the unused list for prune_dcache @@ -1776,9 +1762,8 @@ shouldnt_be_hashed: * * "buflen" should be positive. Caller holds the dcache_lock. */ -static char * __d_path( struct dentry *dentry, struct vfsmount *vfsmnt, - struct dentry *root, struct vfsmount *rootmnt, - char *buffer, int buflen) +static char *__d_path(struct dentry *dentry, struct vfsmount *vfsmnt, + struct path *root, char *buffer, int buflen) { char * end = buffer+buflen; char * retval; @@ -1803,7 +1788,7 @@ static char * __d_path( struct dentry *dentry, struct vfsmount *vfsmnt, for (;;) { struct dentry * parent; - if (dentry == root && vfsmnt == rootmnt) + if (dentry == root->dentry && vfsmnt == root->mnt) break; if (dentry == vfsmnt->mnt_root || IS_ROOT(dentry)) { /* Global root? */ @@ -1844,13 +1829,23 @@ Elong: return ERR_PTR(-ENAMETOOLONG); } -/* write full pathname into buffer and return start of pathname */ -char * d_path(struct dentry *dentry, struct vfsmount *vfsmnt, - char *buf, int buflen) +/** + * d_path - return the path of a dentry + * @path: path to report + * @buf: buffer to return value in + * @buflen: buffer length + * + * Convert a dentry into an ASCII path name. If the entry has been deleted + * the string " (deleted)" is appended. Note that this is ambiguous. + * + * Returns the buffer or an error code if the path was too long. + * + * "buflen" should be positive. Caller holds the dcache_lock. + */ +char *d_path(struct path *path, char *buf, int buflen) { char *res; - struct vfsmount *rootmnt; - struct dentry *root; + struct path root; /* * We have various synthetic filesystems that never get mounted. On @@ -1859,18 +1854,17 @@ char * d_path(struct dentry *dentry, struct vfsmount *vfsmnt, * user wants to identify the object in /proc/pid/fd/. The little hack * below allows us to generate a name for these objects on demand: */ - if (dentry->d_op && dentry->d_op->d_dname) - return dentry->d_op->d_dname(dentry, buf, buflen); + if (path->dentry->d_op && path->dentry->d_op->d_dname) + return path->dentry->d_op->d_dname(path->dentry, buf, buflen); read_lock(¤t->fs->lock); - rootmnt = mntget(current->fs->rootmnt); - root = dget(current->fs->root); + root = current->fs->root; + path_get(¤t->fs->root); read_unlock(¤t->fs->lock); spin_lock(&dcache_lock); - res = __d_path(dentry, vfsmnt, root, rootmnt, buf, buflen); + res = __d_path(path->dentry, path->mnt, &root, buf, buflen); spin_unlock(&dcache_lock); - dput(root); - mntput(rootmnt); + path_put(&root); return res; } @@ -1916,28 +1910,27 @@ char *dynamic_dname(struct dentry *dentry, char *buffer, int buflen, asmlinkage long sys_getcwd(char __user *buf, unsigned long size) { int error; - struct vfsmount *pwdmnt, *rootmnt; - struct dentry *pwd, *root; + struct path pwd, root; char *page = (char *) __get_free_page(GFP_USER); if (!page) return -ENOMEM; read_lock(¤t->fs->lock); - pwdmnt = mntget(current->fs->pwdmnt); - pwd = dget(current->fs->pwd); - rootmnt = mntget(current->fs->rootmnt); - root = dget(current->fs->root); + pwd = current->fs->pwd; + path_get(¤t->fs->pwd); + root = current->fs->root; + path_get(¤t->fs->root); read_unlock(¤t->fs->lock); error = -ENOENT; /* Has the current directory has been unlinked? */ spin_lock(&dcache_lock); - if (pwd->d_parent == pwd || !d_unhashed(pwd)) { + if (pwd.dentry->d_parent == pwd.dentry || !d_unhashed(pwd.dentry)) { unsigned long len; char * cwd; - cwd = __d_path(pwd, pwdmnt, root, rootmnt, page, PAGE_SIZE); + cwd = __d_path(pwd.dentry, pwd.mnt, &root, page, PAGE_SIZE); spin_unlock(&dcache_lock); error = PTR_ERR(cwd); @@ -1955,10 +1948,8 @@ asmlinkage long sys_getcwd(char __user *buf, unsigned long size) spin_unlock(&dcache_lock); out: - dput(pwd); - mntput(pwdmnt); - dput(root); - mntput(rootmnt); + path_put(&pwd); + path_put(&root); free_page((unsigned long) page); return error; } diff --git a/fs/dcookies.c b/fs/dcookies.c index 792cbf55fa9..855d4b1d619 100644 --- a/fs/dcookies.c +++ b/fs/dcookies.c @@ -24,6 +24,7 @@ #include <linux/errno.h> #include <linux/dcookies.h> #include <linux/mutex.h> +#include <linux/path.h> #include <asm/uaccess.h> /* The dcookies are allocated from a kmem_cache and @@ -31,8 +32,7 @@ * code here is particularly performance critical */ struct dcookie_struct { - struct dentry * dentry; - struct vfsmount * vfsmnt; + struct path path; struct list_head hash_list; }; @@ -51,7 +51,7 @@ static inline int is_live(void) /* The dentry is locked, its address will do for the cookie */ static inline unsigned long dcookie_value(struct dcookie_struct * dcs) { - return (unsigned long)dcs->dentry; + return (unsigned long)dcs->path.dentry; } @@ -89,19 +89,17 @@ static void hash_dcookie(struct dcookie_struct * dcs) } -static struct dcookie_struct * alloc_dcookie(struct dentry * dentry, - struct vfsmount * vfsmnt) +static struct dcookie_struct *alloc_dcookie(struct path *path) { - struct dcookie_struct * dcs = kmem_cache_alloc(dcookie_cache, GFP_KERNEL); + struct dcookie_struct *dcs = kmem_cache_alloc(dcookie_cache, + GFP_KERNEL); if (!dcs) return NULL; - dentry->d_cookie = dcs; - - dcs->dentry = dget(dentry); - dcs->vfsmnt = mntget(vfsmnt); + path->dentry->d_cookie = dcs; + dcs->path = *path; + path_get(path); hash_dcookie(dcs); - return dcs; } @@ -109,8 +107,7 @@ static struct dcookie_struct * alloc_dcookie(struct dentry * dentry, /* This is the main kernel-side routine that retrieves the cookie * value for a dentry/vfsmnt pair. */ -int get_dcookie(struct dentry * dentry, struct vfsmount * vfsmnt, - unsigned long * cookie) +int get_dcookie(struct path *path, unsigned long *cookie) { int err = 0; struct dcookie_struct * dcs; @@ -122,10 +119,10 @@ int get_dcookie(struct dentry * dentry, struct vfsmount * vfsmnt, goto out; } - dcs = dentry->d_cookie; + dcs = path->dentry->d_cookie; if (!dcs) - dcs = alloc_dcookie(dentry, vfsmnt); + dcs = alloc_dcookie(path); if (!dcs) { err = -ENOMEM; @@ -174,7 +171,7 @@ asmlinkage long sys_lookup_dcookie(u64 cookie64, char __user * buf, size_t len) goto out; /* FIXME: (deleted) ? */ - path = d_path(dcs->dentry, dcs->vfsmnt, kbuf, PAGE_SIZE); + path = d_path(&dcs->path, kbuf, PAGE_SIZE); if (IS_ERR(path)) { err = PTR_ERR(path); @@ -254,9 +251,8 @@ out_kmem: static void free_dcookie(struct dcookie_struct * dcs) { - dcs->dentry->d_cookie = NULL; - dput(dcs->dentry); - mntput(dcs->vfsmnt); + dcs->path.dentry->d_cookie = NULL; + path_put(&dcs->path); kmem_cache_free(dcookie_cache, dcs); } diff --git a/fs/dquot.c b/fs/dquot.c index def4e969df7..9c7feb62eed 100644 --- a/fs/dquot.c +++ b/fs/dquot.c @@ -1633,16 +1633,17 @@ int vfs_quota_on(struct super_block *sb, int type, int format_id, char *path) error = path_lookup(path, LOOKUP_FOLLOW, &nd); if (error < 0) return error; - error = security_quota_on(nd.dentry); + error = security_quota_on(nd.path.dentry); if (error) goto out_path; /* Quota file not on the same filesystem? */ - if (nd.mnt->mnt_sb != sb) + if (nd.path.mnt->mnt_sb != sb) error = -EXDEV; else - error = vfs_quota_on_inode(nd.dentry->d_inode, type, format_id); + error = vfs_quota_on_inode(nd.path.dentry->d_inode, type, + format_id); out_path: - path_release(&nd); + path_put(&nd.path); return error; } diff --git a/fs/ecryptfs/dentry.c b/fs/ecryptfs/dentry.c index cb20b964419..841a032050a 100644 --- a/fs/ecryptfs/dentry.c +++ b/fs/ecryptfs/dentry.c @@ -51,13 +51,13 @@ static int ecryptfs_d_revalidate(struct dentry *dentry, struct nameidata *nd) if (!lower_dentry->d_op || !lower_dentry->d_op->d_revalidate) goto out; - dentry_save = nd->dentry; - vfsmount_save = nd->mnt; - nd->dentry = lower_dentry; - nd->mnt = lower_mnt; + dentry_save = nd->path.dentry; + vfsmount_save = nd->path.mnt; + nd->path.dentry = lower_dentry; + nd->path.mnt = lower_mnt; rc = lower_dentry->d_op->d_revalidate(lower_dentry, nd); - nd->dentry = dentry_save; - nd->mnt = vfsmount_save; + nd->path.dentry = dentry_save; + nd->path.mnt = vfsmount_save; if (dentry->d_inode) { struct inode *lower_inode = ecryptfs_inode_to_lower(dentry->d_inode); diff --git a/fs/ecryptfs/inode.c b/fs/ecryptfs/inode.c index edd1e44e9d4..e2386115210 100644 --- a/fs/ecryptfs/inode.c +++ b/fs/ecryptfs/inode.c @@ -77,13 +77,13 @@ ecryptfs_create_underlying_file(struct inode *lower_dir_inode, struct vfsmount *vfsmount_save; int rc; - dentry_save = nd->dentry; - vfsmount_save = nd->mnt; - nd->dentry = lower_dentry; - nd->mnt = lower_mnt; + dentry_save = nd->path.dentry; + vfsmount_save = nd->path.mnt; + nd->path.dentry = lower_dentry; + nd->path.mnt = lower_mnt; rc = vfs_create(lower_dir_inode, lower_dentry, mode, nd); - nd->dentry = dentry_save; - nd->mnt = vfsmount_save; + nd->path.dentry = dentry_save; + nd->path.mnt = vfsmount_save; return rc; } @@ -819,14 +819,14 @@ ecryptfs_permission(struct inode *inode, int mask, struct nameidata *nd) int rc; if (nd) { - struct vfsmount *vfsmnt_save = nd->mnt; - struct dentry *dentry_save = nd->dentry; + struct vfsmount *vfsmnt_save = nd->path.mnt; + struct dentry *dentry_save = nd->path.dentry; - nd->mnt = ecryptfs_dentry_to_lower_mnt(nd->dentry); - nd->dentry = ecryptfs_dentry_to_lower(nd->dentry); + nd->path.mnt = ecryptfs_dentry_to_lower_mnt(nd->path.dentry); + nd->path.dentry = ecryptfs_dentry_to_lower(nd->path.dentry); rc = permission(ecryptfs_inode_to_lower(inode), mask, nd); - nd->mnt = vfsmnt_save; - nd->dentry = dentry_save; + nd->path.mnt = vfsmnt_save; + nd->path.dentry = dentry_save; } else rc = permission(ecryptfs_inode_to_lower(inode), mask, NULL); return rc; diff --git a/fs/ecryptfs/main.c b/fs/ecryptfs/main.c index 778c420e4ca..d25ac9500a9 100644 --- a/fs/ecryptfs/main.c +++ b/fs/ecryptfs/main.c @@ -513,8 +513,8 @@ static int ecryptfs_read_super(struct super_block *sb, const char *dev_name) ecryptfs_printk(KERN_WARNING, "path_lookup() failed\n"); goto out; } - lower_root = nd.dentry; - lower_mnt = nd.mnt; + lower_root = nd.path.dentry; + lower_mnt = nd.path.mnt; ecryptfs_set_superblock_lower(sb, lower_root->d_sb); sb->s_maxbytes = lower_root->d_sb->s_maxbytes; sb->s_blocksize = lower_root->d_sb->s_blocksize; @@ -526,7 +526,7 @@ static int ecryptfs_read_super(struct super_block *sb, const char *dev_name) rc = 0; goto out; out_free: - path_release(&nd); + path_put(&nd.path); out: return rc; } diff --git a/fs/exec.c b/fs/exec.c index 9ff6069094d..a44b142fb46 100644 --- a/fs/exec.c +++ b/fs/exec.c @@ -112,7 +112,7 @@ asmlinkage long sys_uselib(const char __user * library) goto out; error = -EINVAL; - if (!S_ISREG(nd.dentry->d_inode->i_mode)) + if (!S_ISREG(nd.path.dentry->d_inode->i_mode)) goto exit; error = vfs_permission(&nd, MAY_READ | MAY_EXEC); @@ -148,7 +148,7 @@ out: return error; exit: release_open_intent(&nd); - path_release(&nd); + path_put(&nd.path); goto out; } @@ -652,7 +652,7 @@ struct file *open_exec(const char *name) file = ERR_PTR(err); if (!err) { - struct inode *inode = nd.dentry->d_inode; + struct inode *inode = nd.path.dentry->d_inode; file = ERR_PTR(-EACCES); if (S_ISREG(inode->i_mode)) { int err = vfs_permission(&nd, MAY_EXEC); @@ -672,7 +672,7 @@ out: } } release_open_intent(&nd); - path_release(&nd); + path_put(&nd.path); } goto out; } diff --git a/fs/ext3/super.c b/fs/ext3/super.c index 8e02cbfb112..18769cc3237 100644 --- a/fs/ext3/super.c +++ b/fs/ext3/super.c @@ -2758,16 +2758,16 @@ static int ext3_quota_on(struct super_block *sb, int type, int format_id, if (err) return err; /* Quotafile not on the same filesystem? */ - if (nd.mnt->mnt_sb != sb) { - path_release(&nd); + if (nd.path.mnt->mnt_sb != sb) { + path_put(&nd.path); return -EXDEV; } /* Quotafile not of fs root? */ - if (nd.dentry->d_parent->d_inode != sb->s_root->d_inode) + if (nd.path.dentry->d_parent->d_inode != sb->s_root->d_inode) printk(KERN_WARNING "EXT3-fs: Quota file not on filesystem root. " "Journalled quota will not work.\n"); - path_release(&nd); + path_put(&nd.path); return vfs_quota_on(sb, type, format_id, path); } diff --git a/fs/ext4/super.c b/fs/ext4/super.c index 0072da75221..13383ba18f1 100644 --- a/fs/ext4/super.c +++ b/fs/ext4/super.c @@ -3158,16 +3158,16 @@ static int ext4_quota_on(struct super_block *sb, int type, int format_id, if (err) return err; /* Quotafile not on the same filesystem? */ - if (nd.mnt->mnt_sb != sb) { - path_release(&nd); + if (nd.path.mnt->mnt_sb != sb) { + path_put(&nd.path); return -EXDEV; } /* Quotafile not of fs root? */ - if (nd.dentry->d_parent->d_inode != sb->s_root->d_inode) + if (nd.path.dentry->d_parent->d_inode != sb->s_root->d_inode) printk(KERN_WARNING "EXT4-fs: Quota file not on filesystem root. " "Journalled quota will not work.\n"); - path_release(&nd); + path_put(&nd.path); return vfs_quota_on(sb, type, format_id, path); } diff --git a/fs/gfs2/ops_fstype.c b/fs/gfs2/ops_fstype.c index 43d511bba52..4bee6aa845e 100644 --- a/fs/gfs2/ops_fstype.c +++ b/fs/gfs2/ops_fstype.c @@ -884,12 +884,13 @@ static struct super_block* get_gfs2_sb(const char *dev_name) dev_name); goto out; } - error = vfs_getattr(nd.mnt, nd.dentry, &stat); + error = vfs_getattr(nd.path.mnt, nd.path.dentry, &stat); fstype = get_fs_type("gfs2"); list_for_each_entry(s, &fstype->fs_supers, s_instances) { if ((S_ISBLK(stat.mode) && s->s_dev == stat.rdev) || - (S_ISDIR(stat.mode) && s == nd.dentry->d_inode->i_sb)) { + (S_ISDIR(stat.mode) && + s == nd.path.dentry->d_inode->i_sb)) { sb = s; goto free_nd; } @@ -899,7 +900,7 @@ static struct super_block* get_gfs2_sb(const char *dev_name) "mount point %s\n", dev_name); free_nd: - path_release(&nd); + path_put(&nd.path); out: return sb; } diff --git a/fs/inotify_user.c b/fs/inotify_user.c index 3ab09a65c45..7b94a1e3c01 100644 --- a/fs/inotify_user.c +++ b/fs/inotify_user.c @@ -41,9 +41,9 @@ static struct kmem_cache *event_cachep __read_mostly; static struct vfsmount *inotify_mnt __read_mostly; /* these are configurable via /proc/sys/fs/inotify/ */ -int inotify_max_user_instances __read_mostly; -int inotify_max_user_watches __read_mostly; -int inotify_max_queued_events __read_mostly; +static int inotify_max_user_instances __read_mostly; +static int inotify_max_user_watches __read_mostly; +static int inotify_max_queued_events __read_mostly; /* * Lock ordering: @@ -367,7 +367,7 @@ static int find_inode(const char __user *dirname, struct nameidata *nd, /* you can only watch an inode if you have read permissions on it */ error = vfs_permission(nd, MAY_READ); if (error) - path_release(nd); + path_put(&nd->path); return error; } @@ -667,7 +667,7 @@ asmlinkage long sys_inotify_add_watch(int fd, const char __user *path, u32 mask) goto fput_and_out; /* inode held in place by reference to nd; dev by fget on fd */ - inode = nd.dentry->d_inode; + inode = nd.path.dentry->d_inode; dev = filp->private_data; mutex_lock(&dev->up_mutex); @@ -676,7 +676,7 @@ asmlinkage long sys_inotify_add_watch(int fd, const char __user *path, u32 mask) ret = create_watch(dev, inode, mask); mutex_unlock(&dev->up_mutex); - path_release(&nd); + path_put(&nd.path); fput_and_out: fput_light(filp, fput_needed); return ret; diff --git a/fs/namei.c b/fs/namei.c index 52703986323..941c8e8228c 100644 --- a/fs/namei.c +++ b/fs/namei.c @@ -231,7 +231,7 @@ int permission(struct inode *inode, int mask, struct nameidata *nd) struct vfsmount *mnt = NULL; if (nd) - mnt = nd->mnt; + mnt = nd->path.mnt; if (mask & MAY_WRITE) { umode_t mode = inode->i_mode; @@ -296,7 +296,7 @@ int permission(struct inode *inode, int mask, struct nameidata *nd) */ int vfs_permission(struct nameidata *nd, int mask) { - return permission(nd->dentry->d_inode, mask, nd); + return permission(nd->path.dentry->d_inode, mask, nd); } /** @@ -362,21 +362,31 @@ int deny_write_access(struct file * file) return 0; } -void path_release(struct nameidata *nd) +/** + * path_get - get a reference to a path + * @path: path to get the reference to + * + * Given a path increment the reference count to the dentry and the vfsmount. + */ +void path_get(struct path *path) { - dput(nd->dentry); - mntput(nd->mnt); + mntget(path->mnt); + dget(path->dentry); } +EXPORT_SYMBOL(path_get); -/* - * umount() mustn't call path_release()/mntput() as that would clear - * mnt_expiry_mark +/** + * path_put - put a reference to a path + * @path: path to put the reference to + * + * Given a path decrement the reference count to the dentry and the vfsmount. */ -void path_release_on_umount(struct nameidata *nd) +void path_put(struct path *path) { - dput(nd->dentry); - mntput_no_expire(nd->mnt); + dput(path->dentry); + mntput(path->mnt); } +EXPORT_SYMBOL(path_put); /** * release_open_intent - free up open intent resources @@ -539,16 +549,16 @@ walk_init_root(const char *name, struct nameidata *nd) struct fs_struct *fs = current->fs; read_lock(&fs->lock); - if (fs->altroot && !(nd->flags & LOOKUP_NOALT)) { - nd->mnt = mntget(fs->altrootmnt); - nd->dentry = dget(fs->altroot); + if (fs->altroot.dentry && !(nd->flags & LOOKUP_NOALT)) { + nd->path = fs->altroot; + path_get(&fs->altroot); read_unlock(&fs->lock); if (__emul_lookup_dentry(name,nd)) return 0; read_lock(&fs->lock); } - nd->mnt = mntget(fs->rootmnt); - nd->dentry = dget(fs->root); + nd->path = fs->root; + path_get(&fs->root); read_unlock(&fs->lock); return 1; } @@ -561,7 +571,7 @@ static __always_inline int __vfs_follow_link(struct nameidata *nd, const char *l goto fail; if (*link == '/') { - path_release(nd); + path_put(&nd->path); if (!walk_init_root(link, nd)) /* weird __emul_prefix() stuff did it */ goto out; @@ -577,31 +587,31 @@ out: */ name = __getname(); if (unlikely(!name)) { - path_release(nd); + path_put(&nd->path); return -ENOMEM; } strcpy(name, nd->last.name); nd->last.name = name; return 0; fail: - path_release(nd); + path_put(&nd->path); return PTR_ERR(link); } -static inline void dput_path(struct path *path, struct nameidata *nd) +static void path_put_conditional(struct path *path, struct nameidata *nd) { dput(path->dentry); - if (path->mnt != nd->mnt) + if (path->mnt != nd->path.mnt) mntput(path->mnt); } static inline void path_to_nameidata(struct path *path, struct nameidata *nd) { - dput(nd->dentry); - if (nd->mnt != path->mnt) - mntput(nd->mnt); - nd->mnt = path->mnt; - nd->dentry = path->dentry; + dput(nd->path.dentry); + if (nd->path.mnt != path->mnt) + mntput(nd->path.mnt); + nd->path.mnt = path->mnt; + nd->path.dentry = path->dentry; } static __always_inline int __do_follow_link(struct path *path, struct nameidata *nd) @@ -613,7 +623,7 @@ static __always_inline int __do_follow_link(struct path *path, struct nameidata touch_atime(path->mnt, dentry); nd_set_link(nd, NULL); - if (path->mnt != nd->mnt) { + if (path->mnt != nd->path.mnt) { path_to_nameidata(path, nd); dget(dentry); } @@ -628,8 +638,7 @@ static __always_inline int __do_follow_link(struct path *path, struct nameidata if (dentry->d_inode->i_op->put_link) dentry->d_inode->i_op->put_link(dentry, nd, cookie); } - dput(dentry); - mntput(path->mnt); + path_put(path); return error; } @@ -661,8 +670,8 @@ static inline int do_follow_link(struct path *path, struct nameidata *nd) nd->depth--; return err; loop: - dput_path(path, nd); - path_release(nd); + path_put_conditional(path, nd); + path_put(&nd->path); return err; } @@ -743,37 +752,37 @@ static __always_inline void follow_dotdot(struct nameidata *nd) while(1) { struct vfsmount *parent; - struct dentry *old = nd->dentry; + struct dentry *old = nd->path.dentry; read_lock(&fs->lock); - if (nd->dentry == fs->root && - nd->mnt == fs->rootmnt) { + if (nd->path.dentry == fs->root.dentry && + nd->path.mnt == fs->root.mnt) { read_unlock(&fs->lock); break; } read_unlock(&fs->lock); spin_lock(&dcache_lock); - if (nd->dentry != nd->mnt->mnt_root) { - nd->dentry = dget(nd->dentry->d_parent); + if (nd->path.dentry != nd->path.mnt->mnt_root) { + nd->path.dentry = dget(nd->path.dentry->d_parent); spin_unlock(&dcache_lock); dput(old); break; } spin_unlock(&dcache_lock); spin_lock(&vfsmount_lock); - parent = nd->mnt->mnt_parent; - if (parent == nd->mnt) { + parent = nd->path.mnt->mnt_parent; + if (parent == nd->path.mnt) { spin_unlock(&vfsmount_lock); break; } mntget(parent); - nd->dentry = dget(nd->mnt->mnt_mountpoint); + nd->path.dentry = dget(nd->path.mnt->mnt_mountpoint); spin_unlock(&vfsmount_lock); dput(old); - mntput(nd->mnt); - nd->mnt = parent; + mntput(nd->path.mnt); + nd->path.mnt = parent; } - follow_mount(&nd->mnt, &nd->dentry); + follow_mount(&nd->path.mnt, &nd->path.dentry); } /* @@ -784,8 +793,8 @@ static __always_inline void follow_dotdot(struct nameidata *nd) static int do_lookup(struct nameidata *nd, struct qstr *name, struct path *path) { - struct vfsmount *mnt = nd->mnt; - struct dentry *dentry = __d_lookup(nd->dentry, name); + struct vfsmount *mnt = nd->path.mnt; + struct dentry *dentry = __d_lookup(nd->path.dentry, name); if (!dentry) goto need_lookup; @@ -798,7 +807,7 @@ done: return 0; need_lookup: - dentry = real_lookup(nd->dentry, name, nd); + dentry = real_lookup(nd->path.dentry, name, nd); if (IS_ERR(dentry)) goto fail; goto done; @@ -835,7 +844,7 @@ static int __link_path_walk(const char *name, struct nameidata *nd) if (!*name) goto return_reval; - inode = nd->dentry->d_inode; + inode = nd->path.dentry->d_inode; if (nd->depth) lookup_flags = LOOKUP_FOLLOW | (nd->flags & LOOKUP_CONTINUE); @@ -883,7 +892,7 @@ static int __link_path_walk(const char *name, struct nameidata *nd) if (this.name[1] != '.') break; follow_dotdot(nd); - inode = nd->dentry->d_inode; + inode = nd->path.dentry->d_inode; /* fallthrough */ case 1: continue; @@ -892,8 +901,9 @@ static int __link_path_walk(const char *name, struct nameidata *nd) * See if the low-level filesystem might want * to use its own hash.. */ - if (nd->dentry->d_op && nd->dentry->d_op->d_hash) { - err = nd->dentry->d_op->d_hash(nd->dentry, &this); + if (nd->path.dentry->d_op && nd->path.dentry->d_op->d_hash) { + err = nd->path.dentry->d_op->d_hash(nd->path.dentry, + &this); if (err < 0) break; } @@ -915,7 +925,7 @@ static int __link_path_walk(const char *name, struct nameidata *nd) if (err) goto return_err; err = -ENOENT; - inode = nd->dentry->d_inode; + inode = nd->path.dentry->d_inode; if (!inode) break; err = -ENOTDIR; @@ -943,13 +953,14 @@ last_component: if (this.name[1] != '.') break; follow_dotdot(nd); - inode = nd->dentry->d_inode; + inode = nd->path.dentry->d_inode; /* fallthrough */ case 1: goto return_reval; } - if (nd->dentry->d_op && nd->dentry->d_op->d_hash) { - err = nd->dentry->d_op->d_hash(nd->dentry, &this); + if (nd->path.dentry->d_op && nd->path.dentry->d_op->d_hash) { + err = nd->path.dentry->d_op->d_hash(nd->path.dentry, + &this); if (err < 0) break; } @@ -962,7 +973,7 @@ last_component: err = do_follow_link(&next, nd); if (err) goto return_err; - inode = nd->dentry->d_inode; + inode = nd->path.dentry->d_inode; } else path_to_nameidata(&next, nd); err = -ENOENT; @@ -990,20 +1001,21 @@ return_reval: * We bypassed the ordinary revalidation routines. * We may need to check the cached dentry for staleness. */ - if (nd->dentry && nd->dentry->d_sb && - (nd->dentry->d_sb->s_type->fs_flags & FS_REVAL_DOT)) { + if (nd->path.dentry && nd->path.dentry->d_sb && + (nd->path.dentry->d_sb->s_type->fs_flags & FS_REVAL_DOT)) { err = -ESTALE; /* Note: we do not d_invalidate() */ - if (!nd->dentry->d_op->d_revalidate(nd->dentry, nd)) + if (!nd->path.dentry->d_op->d_revalidate( + nd->path.dentry, nd)) break; } return_base: return 0; out_dput: - dput_path(&next, nd); + path_put_conditional(&next, nd); break; } - path_release(nd); + path_put(&nd->path); return_err: return err; } @@ -1021,20 +1033,19 @@ static int link_path_walk(const char *name, struct nameidata *nd) int result; /* make sure the stuff we saved doesn't go away */ - dget(save.dentry); - mntget(save.mnt); + dget(save.path.dentry); + mntget(save.path.mnt); result = __link_path_walk(name, nd); if (result == -ESTALE) { *nd = save; - dget(nd->dentry); - mntget(nd->mnt); + dget(nd->path.dentry); + mntget(nd->path.mnt); nd->flags |= LOOKUP_REVAL; result = __link_path_walk(name, nd); } - dput(save.dentry); - mntput(save.mnt); + path_put(&save.path); return result; } @@ -1054,9 +1065,9 @@ static int __emul_lookup_dentry(const char *name, struct nameidata *nd) if (path_walk(name, nd)) return 0; /* something went wrong... */ - if (!nd->dentry->d_inode || S_ISDIR(nd->dentry->d_inode->i_mode)) { - struct dentry *old_dentry = nd->dentry; - struct vfsmount *old_mnt = nd->mnt; + if (!nd->path.dentry->d_inode || + S_ISDIR(nd->path.dentry->d_inode->i_mode)) { + struct path old_path = nd->path; struct qstr last = nd->last; int last_type = nd->last_type; struct fs_struct *fs = current->fs; @@ -1067,19 +1078,17 @@ static int __emul_lookup_dentry(const char *name, struct nameidata *nd) */ nd->last_type = LAST_ROOT; read_lock(&fs->lock); - nd->mnt = mntget(fs->rootmnt); - nd->dentry = dget(fs->root); + nd->path = fs->root; + path_get(&fs->root); read_unlock(&fs->lock); if (path_walk(name, nd) == 0) { - if (nd->dentry->d_inode) { - dput(old_dentry); - mntput(old_mnt); + if (nd->path.dentry->d_inode) { + path_put(&old_path); return 1; } - path_release(nd); + path_put(&nd->path); } - nd->dentry = old_dentry; - nd->mnt = old_mnt; + nd->path = old_path; nd->last = last; nd->last_type = last_type; } @@ -1090,29 +1099,22 @@ void set_fs_altroot(void) { char *emul = __emul_prefix(); struct nameidata nd; - struct vfsmount *mnt = NULL, *oldmnt; - struct dentry *dentry = NULL, *olddentry; + struct path path = {}, old_path; int err; struct fs_struct *fs = current->fs; if (!emul) goto set_it; err = path_lookup(emul, LOOKUP_FOLLOW|LOOKUP_DIRECTORY|LOOKUP_NOALT, &nd); - if (!err) { - mnt = nd.mnt; - dentry = nd.dentry; - } + if (!err) + path = nd.path; set_it: write_lock(&fs->lock); - oldmnt = fs->altrootmnt; - olddentry = fs->altroot; - fs->altrootmnt = mnt; - fs->altroot = dentry; + old_path = fs->altroot; + fs->altroot = path; write_unlock(&fs->lock); - if (olddentry) { - dput(olddentry); - mntput(oldmnt); - } + if (old_path.dentry) + path_put(&old_path); } /* Returns 0 and nd will be valid on success; Retuns error, otherwise. */ @@ -1130,21 +1132,21 @@ static int do_path_lookup(int dfd, const char *name, if (*name=='/') { read_lock(&fs->lock); - if (fs->altroot && !(nd->flags & LOOKUP_NOALT)) { - nd->mnt = mntget(fs->altrootmnt); - nd->dentry = dget(fs->altroot); + if (fs->altroot.dentry && !(nd->flags & LOOKUP_NOALT)) { + nd->path = fs->altroot; + path_get(&fs->altroot); read_unlock(&fs->lock); if (__emul_lookup_dentry(name,nd)) goto out; /* found in altroot */ read_lock(&fs->lock); } - nd->mnt = mntget(fs->rootmnt); - nd->dentry = dget(fs->root); + nd->path = fs->root; + path_get(&fs->root); read_unlock(&fs->lock); } else if (dfd == AT_FDCWD) { read_lock(&fs->lock); - nd->mnt = mntget(fs->pwdmnt); - nd->dentry = dget(fs->pwd); + nd->path = fs->pwd; + path_get(&fs->pwd); read_unlock(&fs->lock); } else { struct dentry *dentry; @@ -1164,17 +1166,17 @@ static int do_path_lookup(int dfd, const char *name, if (retval) goto fput_fail; - nd->mnt = mntget(file->f_path.mnt); - nd->dentry = dget(dentry); + nd->path = file->f_path; + path_get(&file->f_path); fput_light(file, fput_needed); } retval = path_walk(name, nd); out: - if (unlikely(!retval && !audit_dummy_context() && nd->dentry && - nd->dentry->d_inode)) - audit_inode(name, nd->dentry); + if (unlikely(!retval && !audit_dummy_context() && nd->path.dentry && + nd->path.dentry->d_inode)) + audit_inode(name, nd->path.dentry); out_fail: return retval; @@ -1208,13 +1210,13 @@ int vfs_path_lookup(struct dentry *dentry, struct vfsmount *mnt, nd->flags = flags; nd->depth = 0; - nd->mnt = mntget(mnt); - nd->dentry = dget(dentry); + nd->path.mnt = mntget(mnt); + nd->path.dentry = dget(dentry); retval = path_walk(name, nd); - if (unlikely(!retval && !audit_dummy_context() && nd->dentry && - nd->dentry->d_inode)) - audit_inode(name, nd->dentry); + if (unlikely(!retval && !audit_dummy_context() && nd->path.dentry && + nd->path.dentry->d_inode)) + audit_inode(name, nd->path.dentry); return retval; @@ -1236,7 +1238,7 @@ static int __path_lookup_intent_open(int dfd, const char *name, if (IS_ERR(nd->intent.open.file)) { if (err == 0) { err = PTR_ERR(nd->intent.open.file); - path_release(nd); + path_put(&nd->path); } } else if (err != 0) release_open_intent(nd); @@ -1333,10 +1335,10 @@ static struct dentry *lookup_hash(struct nameidata *nd) { int err; - err = permission(nd->dentry->d_inode, MAY_EXEC, nd); + err = permission(nd->path.dentry->d_inode, MAY_EXEC, nd); if (err) return ERR_PTR(err); - return __lookup_hash(&nd->last, nd->dentry, nd); + return __lookup_hash(&nd->last, nd->path.dentry, nd); } static int __lookup_one_len(const char *name, struct qstr *this, @@ -1595,7 +1597,7 @@ int vfs_create(struct inode *dir, struct dentry *dentry, int mode, int may_open(struct nameidata *nd, int acc_mode, int flag) { - struct dentry *dentry = nd->dentry; + struct dentry *dentry = nd->path.dentry; struct inode *inode = dentry->d_inode; int error; @@ -1616,7 +1618,7 @@ int may_open(struct nameidata *nd, int acc_mode, int flag) if (S_ISFIFO(inode->i_mode) || S_ISSOCK(inode->i_mode)) { flag &= ~O_TRUNC; } else if (S_ISBLK(inode->i_mode) || S_ISCHR(inode->i_mode)) { - if (nd->mnt->mnt_flags & MNT_NODEV) + if (nd->path.mnt->mnt_flags & MNT_NODEV) return -EACCES; flag &= ~O_TRUNC; @@ -1678,14 +1680,14 @@ static int open_namei_create(struct nameidata *nd, struct path *path, int flag, int mode) { int error; - struct dentry *dir = nd->dentry; + struct dentry *dir = nd->path.dentry; if (!IS_POSIXACL(dir->d_inode)) mode &= ~current->fs->umask; error = vfs_create(dir->d_inode, path->dentry, mode, nd); mutex_unlock(&dir->d_inode->i_mutex); - dput(nd->dentry); - nd->dentry = path->dentry; + dput(nd->path.dentry); + nd->path.dentry = path->dentry; if (error) return error; /* Don't check for write permission, don't truncate */ @@ -1752,11 +1754,11 @@ int open_namei(int dfd, const char *pathname, int flag, if (nd->last_type != LAST_NORM || nd->last.name[nd->last.len]) goto exit; - dir = nd->dentry; + dir = nd->path.dentry; nd->flags &= ~LOOKUP_PARENT; mutex_lock(&dir->d_inode->i_mutex); path.dentry = lookup_hash(nd); - path.mnt = nd->mnt; + path.mnt = nd->path.mnt; do_last: error = PTR_ERR(path.dentry); @@ -1812,11 +1814,11 @@ ok: return 0; exit_dput: - dput_path(&path, nd); + path_put_conditional(&path, nd); exit: if (!IS_ERR(nd->intent.open.file)) release_open_intent(nd); - path_release(nd); + path_put(&nd->path); return error; do_link: @@ -1861,10 +1863,10 @@ do_link: __putname(nd->last.name); goto exit; } - dir = nd->dentry; + dir = nd->path.dentry; mutex_lock(&dir->d_inode->i_mutex); path.dentry = lookup_hash(nd); - path.mnt = nd->mnt; + path.mnt = nd->path.mnt; __putname(nd->last.name); goto do_last; } @@ -1877,13 +1879,13 @@ do_link: * Simple function to lookup and return a dentry and create it * if it doesn't exist. Is SMP-safe. * - * Returns with nd->dentry->d_inode->i_mutex locked. + * Returns with nd->path.dentry->d_inode->i_mutex locked. */ struct dentry *lookup_create(struct nameidata *nd, int is_dir) { struct dentry *dentry = ERR_PTR(-EEXIST); - mutex_lock_nested(&nd->dentry->d_inode->i_mutex, I_MUTEX_PARENT); + mutex_lock_nested(&nd->path.dentry->d_inode->i_mutex, I_MUTEX_PARENT); /* * Yucky last component or no last component at all? * (foo/., foo/.., /////) @@ -1962,19 +1964,19 @@ asmlinkage long sys_mknodat(int dfd, const char __user *filename, int mode, dentry = lookup_create(&nd, 0); error = PTR_ERR(dentry); - if (!IS_POSIXACL(nd.dentry->d_inode)) + if (!IS_POSIXACL(nd.path.dentry->d_inode)) mode &= ~current->fs->umask; if (!IS_ERR(dentry)) { switch (mode & S_IFMT) { case 0: case S_IFREG: - error = vfs_create(nd.dentry->d_inode,dentry,mode,&nd); + error = vfs_create(nd.path.dentry->d_inode,dentry,mode,&nd); break; case S_IFCHR: case S_IFBLK: - error = vfs_mknod(nd.dentry->d_inode,dentry,mode, + error = vfs_mknod(nd.path.dentry->d_inode,dentry,mode, new_decode_dev(dev)); break; case S_IFIFO: case S_IFSOCK: - error = vfs_mknod(nd.dentry->d_inode,dentry,mode,0); + error = vfs_mknod(nd.path.dentry->d_inode,dentry,mode,0); break; case S_IFDIR: error = -EPERM; @@ -1984,8 +1986,8 @@ asmlinkage long sys_mknodat(int dfd, const char __user *filename, int mode, } dput(dentry); } - mutex_unlock(&nd.dentry->d_inode->i_mutex); - path_release(&nd); + mutex_unlock(&nd.path.dentry->d_inode->i_mutex); + path_put(&nd.path); out: putname(tmp); @@ -2039,13 +2041,13 @@ asmlinkage long sys_mkdirat(int dfd, const char __user *pathname, int mode) if (IS_ERR(dentry)) goto out_unlock; - if (!IS_POSIXACL(nd.dentry->d_inode)) + if (!IS_POSIXACL(nd.path.dentry->d_inode)) mode &= ~current->fs->umask; - error = vfs_mkdir(nd.dentry->d_inode, dentry, mode); + error = vfs_mkdir(nd.path.dentry->d_inode, dentry, mode); dput(dentry); out_unlock: - mutex_unlock(&nd.dentry->d_inode->i_mutex); - path_release(&nd); + mutex_unlock(&nd.path.dentry->d_inode->i_mutex); + path_put(&nd.path); out: putname(tmp); out_err: @@ -2143,17 +2145,17 @@ static long do_rmdir(int dfd, const char __user *pathname) error = -EBUSY; goto exit1; } - mutex_lock_nested(&nd.dentry->d_inode->i_mutex, I_MUTEX_PARENT); + mutex_lock_nested(&nd.path.dentry->d_inode->i_mutex, I_MUTEX_PARENT); dentry = lookup_hash(&nd); error = PTR_ERR(dentry); if (IS_ERR(dentry)) goto exit2; - error = vfs_rmdir(nd.dentry->d_inode, dentry); + error = vfs_rmdir(nd.path.dentry->d_inode, dentry); dput(dentry); exit2: - mutex_unlock(&nd.dentry->d_inode->i_mutex); + mutex_unlock(&nd.path.dentry->d_inode->i_mutex); exit1: - path_release(&nd); + path_put(&nd.path); exit: putname(name); return error; @@ -2219,7 +2221,7 @@ static long do_unlinkat(int dfd, const char __user *pathname) error = -EISDIR; if (nd.last_type != LAST_NORM) goto exit1; - mutex_lock_nested(&nd.dentry->d_inode->i_mutex, I_MUTEX_PARENT); + mutex_lock_nested(&nd.path.dentry->d_inode->i_mutex, I_MUTEX_PARENT); dentry = lookup_hash(&nd); error = PTR_ERR(dentry); if (!IS_ERR(dentry)) { @@ -2229,15 +2231,15 @@ static long do_unlinkat(int dfd, const char __user *pathname) inode = dentry->d_inode; if (inode) atomic_inc(&inode->i_count); - error = vfs_unlink(nd.dentry->d_inode, dentry); + error = vfs_unlink(nd.path.dentry->d_inode, dentry); exit2: dput(dentry); } - mutex_unlock(&nd.dentry->d_inode->i_mutex); + mutex_unlock(&nd.path.dentry->d_inode->i_mutex); if (inode) iput(inode); /* truncate the inode here */ exit1: - path_release(&nd); + path_put(&nd.path); exit: putname(name); return error; @@ -2310,11 +2312,11 @@ asmlinkage long sys_symlinkat(const char __user *oldname, if (IS_ERR(dentry)) goto out_unlock; - error = vfs_symlink(nd.dentry->d_inode, dentry, from, S_IALLUGO); + error = vfs_symlink(nd.path.dentry->d_inode, dentry, from, S_IALLUGO); dput(dentry); out_unlock: - mutex_unlock(&nd.dentry->d_inode->i_mutex); - path_release(&nd); + mutex_unlock(&nd.path.dentry->d_inode->i_mutex); + path_put(&nd.path); out: putname(to); out_putname: @@ -2399,20 +2401,20 @@ asmlinkage long sys_linkat(int olddfd, const char __user *oldname, if (error) goto out; error = -EXDEV; - if (old_nd.mnt != nd.mnt) + if (old_nd.path.mnt != nd.path.mnt) goto out_release; new_dentry = lookup_create(&nd, 0); error = PTR_ERR(new_dentry); if (IS_ERR(new_dentry)) goto out_unlock; - error = vfs_link(old_nd.dentry, nd.dentry->d_inode, new_dentry); + error = vfs_link(old_nd.path.dentry, nd.path.dentry->d_inode, new_dentry); dput(new_dentry); out_unlock: - mutex_unlock(&nd.dentry->d_inode->i_mutex); + mutex_unlock(&nd.path.dentry->d_inode->i_mutex); out_release: - path_release(&nd); + path_put(&nd.path); out: - path_release(&old_nd); + path_put(&old_nd.path); exit: putname(to); @@ -2588,15 +2590,15 @@ static int do_rename(int olddfd, const char *oldname, goto exit1; error = -EXDEV; - if (oldnd.mnt != newnd.mnt) + if (oldnd.path.mnt != newnd.path.mnt) goto exit2; - old_dir = oldnd.dentry; + old_dir = oldnd.path.dentry; error = -EBUSY; if (oldnd.last_type != LAST_NORM) goto exit2; - new_dir = newnd.dentry; + new_dir = newnd.path.dentry; if (newnd.last_type != LAST_NORM) goto exit2; @@ -2640,9 +2642,9 @@ exit4: exit3: unlock_rename(new_dir, old_dir); exit2: - path_release(&newnd); + path_put(&newnd.path); exit1: - path_release(&oldnd); + path_put(&oldnd.path); exit: return error; } @@ -2816,7 +2818,6 @@ EXPORT_SYMBOL(page_symlink); EXPORT_SYMBOL(page_symlink_inode_operations); EXPORT_SYMBOL(path_lookup); EXPORT_SYMBOL(vfs_path_lookup); -EXPORT_SYMBOL(path_release); EXPORT_SYMBOL(permission); EXPORT_SYMBOL(vfs_permission); EXPORT_SYMBOL(file_permission); diff --git a/fs/namespace.c b/fs/namespace.c index 63ced21c12d..7953c96a207 100644 --- a/fs/namespace.c +++ b/fs/namespace.c @@ -157,13 +157,13 @@ static void __touch_mnt_namespace(struct mnt_namespace *ns) static void detach_mnt(struct vfsmount *mnt, struct nameidata *old_nd) { - old_nd->dentry = mnt->mnt_mountpoint; - old_nd->mnt = mnt->mnt_parent; + old_nd->path.dentry = mnt->mnt_mountpoint; + old_nd->path.mnt = mnt->mnt_parent; mnt->mnt_parent = mnt; mnt->mnt_mountpoint = mnt->mnt_root; list_del_init(&mnt->mnt_child); list_del_init(&mnt->mnt_hash); - old_nd->dentry->d_mounted--; + old_nd->path.dentry->d_mounted--; } void mnt_set_mountpoint(struct vfsmount *mnt, struct dentry *dentry, @@ -176,10 +176,10 @@ void mnt_set_mountpoint(struct vfsmount *mnt, struct dentry *dentry, static void attach_mnt(struct vfsmount *mnt, struct nameidata *nd) { - mnt_set_mountpoint(nd->mnt, nd->dentry, mnt); + mnt_set_mountpoint(nd->path.mnt, nd->path.dentry, mnt); list_add_tail(&mnt->mnt_hash, mount_hashtable + - hash(nd->mnt, nd->dentry)); - list_add_tail(&mnt->mnt_child, &nd->mnt->mnt_mounts); + hash(nd->path.mnt, nd->path.dentry)); + list_add_tail(&mnt->mnt_child, &nd->path.mnt->mnt_mounts); } /* @@ -408,10 +408,11 @@ static int show_vfsmnt(struct seq_file *m, void *v) { 0, NULL } }; struct proc_fs_info *fs_infop; + struct path mnt_path = { .dentry = mnt->mnt_root, .mnt = mnt }; mangle(m, mnt->mnt_devname ? mnt->mnt_devname : "none"); seq_putc(m, ' '); - seq_path(m, mnt, mnt->mnt_root, " \t\n\\"); + seq_path(m, &mnt_path, " \t\n\\"); seq_putc(m, ' '); mangle(m, mnt->mnt_sb->s_type->name); if (mnt->mnt_sb->s_subtype && mnt->mnt_sb->s_subtype[0]) { @@ -443,6 +444,7 @@ struct seq_operations mounts_op = { static int show_vfsstat(struct seq_file *m, void *v) { struct vfsmount *mnt = list_entry(v, struct vfsmount, mnt_list); + struct path mnt_path = { .dentry = mnt->mnt_root, .mnt = mnt }; int err = 0; /* device */ @@ -454,7 +456,7 @@ static int show_vfsstat(struct seq_file *m, void *v) /* mount point */ seq_puts(m, " mounted on "); - seq_path(m, mnt, mnt->mnt_root, " \t\n\\"); + seq_path(m, &mnt_path, " \t\n\\"); seq_putc(m, ' '); /* file system type */ @@ -593,7 +595,7 @@ static int do_umount(struct vfsmount *mnt, int flags) * (2) the usage count == 1 [parent vfsmount] + 1 [sys_umount] */ if (flags & MNT_EXPIRE) { - if (mnt == current->fs->rootmnt || + if (mnt == current->fs->root.mnt || flags & (MNT_FORCE | MNT_DETACH)) return -EINVAL; @@ -628,7 +630,7 @@ static int do_umount(struct vfsmount *mnt, int flags) * /reboot - static binary that would close all descriptors and * call reboot(9). Then init(8) could umount root and exec /reboot. */ - if (mnt == current->fs->rootmnt && !(flags & MNT_DETACH)) { + if (mnt == current->fs->root.mnt && !(flags & MNT_DETACH)) { /* * Special case for "unmounting" root ... * we just try to remount it readonly. @@ -679,18 +681,20 @@ asmlinkage long sys_umount(char __user * name, int flags) if (retval) goto out; retval = -EINVAL; - if (nd.dentry != nd.mnt->mnt_root) + if (nd.path.dentry != nd.path.mnt->mnt_root) goto dput_and_out; - if (!check_mnt(nd.mnt)) + if (!check_mnt(nd.path.mnt)) goto dput_and_out; retval = -EPERM; if (!capable(CAP_SYS_ADMIN)) goto dput_and_out; - retval = do_umount(nd.mnt, flags); + retval = do_umount(nd.path.mnt, flags); dput_and_out: - path_release_on_umount(&nd); + /* we mustn't call path_put() as that would clear mnt_expiry_mark */ + dput(nd.path.dentry); + mntput_no_expire(nd.path.mnt); out: return retval; } @@ -713,10 +717,10 @@ static int mount_is_safe(struct nameidata *nd) return 0; return -EPERM; #ifdef notyet - if (S_ISLNK(nd->dentry->d_inode->i_mode)) + if (S_ISLNK(nd->path.dentry->d_inode->i_mode)) return -EPERM; - if (nd->dentry->d_inode->i_mode & S_ISVTX) { - if (current->uid != nd->dentry->d_inode->i_uid) + if (nd->path.dentry->d_inode->i_mode & S_ISVTX) { + if (current->uid != nd->path.dentry->d_inode->i_uid) return -EPERM; } if (vfs_permission(nd, MAY_WRITE)) @@ -765,8 +769,8 @@ struct vfsmount *copy_tree(struct vfsmount *mnt, struct dentry *dentry, q = q->mnt_parent; } p = s; - nd.mnt = q; - nd.dentry = p->mnt_mountpoint; + nd.path.mnt = q; + nd.path.dentry = p->mnt_mountpoint; q = clone_mnt(p, p->mnt_root, flag); if (!q) goto Enomem; @@ -875,8 +879,8 @@ static int attach_recursive_mnt(struct vfsmount *source_mnt, struct nameidata *nd, struct nameidata *parent_nd) { LIST_HEAD(tree_list); - struct vfsmount *dest_mnt = nd->mnt; - struct dentry *dest_dentry = nd->dentry; + struct vfsmount *dest_mnt = nd->path.mnt; + struct dentry *dest_dentry = nd->path.dentry; struct vfsmount *child, *p; if (propagate_mnt(dest_mnt, dest_dentry, source_mnt, &tree_list)) @@ -911,13 +915,13 @@ static int graft_tree(struct vfsmount *mnt, struct nameidata *nd) if (mnt->mnt_sb->s_flags & MS_NOUSER) return -EINVAL; - if (S_ISDIR(nd->dentry->d_inode->i_mode) != + if (S_ISDIR(nd->path.dentry->d_inode->i_mode) != S_ISDIR(mnt->mnt_root->d_inode->i_mode)) return -ENOTDIR; err = -ENOENT; - mutex_lock(&nd->dentry->d_inode->i_mutex); - if (IS_DEADDIR(nd->dentry->d_inode)) + mutex_lock(&nd->path.dentry->d_inode->i_mutex); + if (IS_DEADDIR(nd->path.dentry->d_inode)) goto out_unlock; err = security_sb_check_sb(mnt, nd); @@ -925,10 +929,10 @@ static int graft_tree(struct vfsmount *mnt, struct nameidata *nd) goto out_unlock; err = -ENOENT; - if (IS_ROOT(nd->dentry) || !d_unhashed(nd->dentry)) + if (IS_ROOT(nd->path.dentry) || !d_unhashed(nd->path.dentry)) err = attach_recursive_mnt(mnt, nd, NULL); out_unlock: - mutex_unlock(&nd->dentry->d_inode->i_mutex); + mutex_unlock(&nd->path.dentry->d_inode->i_mutex); if (!err) security_sb_post_addmount(mnt, nd); return err; @@ -940,14 +944,14 @@ out_unlock: */ static noinline int do_change_type(struct nameidata *nd, int flag) { - struct vfsmount *m, *mnt = nd->mnt; + struct vfsmount *m, *mnt = nd->path.mnt; int recurse = flag & MS_REC; int type = flag & ~MS_REC; if (!capable(CAP_SYS_ADMIN)) return -EPERM; - if (nd->dentry != nd->mnt->mnt_root) + if (nd->path.dentry != nd->path.mnt->mnt_root) return -EINVAL; down_write(&namespace_sem); @@ -979,17 +983,17 @@ static noinline int do_loopback(struct nameidata *nd, char *old_name, down_write(&namespace_sem); err = -EINVAL; - if (IS_MNT_UNBINDABLE(old_nd.mnt)) - goto out; + if (IS_MNT_UNBINDABLE(old_nd.path.mnt)) + goto out; - if (!check_mnt(nd->mnt) || !check_mnt(old_nd.mnt)) + if (!check_mnt(nd->path.mnt) || !check_mnt(old_nd.path.mnt)) goto out; err = -ENOMEM; if (recurse) - mnt = copy_tree(old_nd.mnt, old_nd.dentry, 0); + mnt = copy_tree(old_nd.path.mnt, old_nd.path.dentry, 0); else - mnt = clone_mnt(old_nd.mnt, old_nd.dentry, 0); + mnt = clone_mnt(old_nd.path.mnt, old_nd.path.dentry, 0); if (!mnt) goto out; @@ -1005,7 +1009,7 @@ static noinline int do_loopback(struct nameidata *nd, char *old_name, out: up_write(&namespace_sem); - path_release(&old_nd); + path_put(&old_nd.path); return err; } @@ -1019,24 +1023,24 @@ static noinline int do_remount(struct nameidata *nd, int flags, int mnt_flags, void *data) { int err; - struct super_block *sb = nd->mnt->mnt_sb; + struct super_block *sb = nd->path.mnt->mnt_sb; if (!capable(CAP_SYS_ADMIN)) return -EPERM; - if (!check_mnt(nd->mnt)) + if (!check_mnt(nd->path.mnt)) return -EINVAL; - if (nd->dentry != nd->mnt->mnt_root) + if (nd->path.dentry != nd->path.mnt->mnt_root) return -EINVAL; down_write(&sb->s_umount); err = do_remount_sb(sb, flags, data, 0); if (!err) - nd->mnt->mnt_flags = mnt_flags; + nd->path.mnt->mnt_flags = mnt_flags; up_write(&sb->s_umount); if (!err) - security_sb_post_remount(nd->mnt, flags, data); + security_sb_post_remount(nd->path.mnt, flags, data); return err; } @@ -1067,61 +1071,65 @@ static noinline int do_move_mount(struct nameidata *nd, char *old_name) return err; down_write(&namespace_sem); - while (d_mountpoint(nd->dentry) && follow_down(&nd->mnt, &nd->dentry)) + while (d_mountpoint(nd->path.dentry) && + follow_down(&nd->path.mnt, &nd->path.dentry)) ; err = -EINVAL; - if (!check_mnt(nd->mnt) || !check_mnt(old_nd.mnt)) + if (!check_mnt(nd->path.mnt) || !check_mnt(old_nd.path.mnt)) goto out; err = -ENOENT; - mutex_lock(&nd->dentry->d_inode->i_mutex); - if (IS_DEADDIR(nd->dentry->d_inode)) + mutex_lock(&nd->path.dentry->d_inode->i_mutex); + if (IS_DEADDIR(nd->path.dentry->d_inode)) goto out1; - if (!IS_ROOT(nd->dentry) && d_unhashed(nd->dentry)) + if (!IS_ROOT(nd->path.dentry) && d_unhashed(nd->path.dentry)) goto out1; err = -EINVAL; - if (old_nd.dentry != old_nd.mnt->mnt_root) + if (old_nd.path.dentry != old_nd.path.mnt->mnt_root) goto out1; - if (old_nd.mnt == old_nd.mnt->mnt_parent) + if (old_nd.path.mnt == old_nd.path.mnt->mnt_parent) goto out1; - if (S_ISDIR(nd->dentry->d_inode->i_mode) != - S_ISDIR(old_nd.dentry->d_inode->i_mode)) + if (S_ISDIR(nd->path.dentry->d_inode->i_mode) != + S_ISDIR(old_nd.path.dentry->d_inode->i_mode)) goto out1; /* * Don't move a mount residing in a shared parent. */ - if (old_nd.mnt->mnt_parent && IS_MNT_SHARED(old_nd.mnt->mnt_parent)) + if (old_nd.path.mnt->mnt_parent && + IS_MNT_SHARED(old_nd.path.mnt->mnt_parent)) goto out1; /* * Don't move a mount tree containing unbindable mounts to a destination * mount which is shared. */ - if (IS_MNT_SHARED(nd->mnt) && tree_contains_unbindable(old_nd.mnt)) + if (IS_MNT_SHARED(nd->path.mnt) && + tree_contains_unbindable(old_nd.path.mnt)) goto out1; err = -ELOOP; - for (p = nd->mnt; p->mnt_parent != p; p = p->mnt_parent) - if (p == old_nd.mnt) + for (p = nd->path.mnt; p->mnt_parent != p; p = p->mnt_parent) + if (p == old_nd.path.mnt) goto out1; - if ((err = attach_recursive_mnt(old_nd.mnt, nd, &parent_nd))) + err = attach_recursive_mnt(old_nd.path.mnt, nd, &parent_nd); + if (err) goto out1; spin_lock(&vfsmount_lock); /* if the mount is moved, it should no longer be expire * automatically */ - list_del_init(&old_nd.mnt->mnt_expire); + list_del_init(&old_nd.path.mnt->mnt_expire); spin_unlock(&vfsmount_lock); out1: - mutex_unlock(&nd->dentry->d_inode->i_mutex); + mutex_unlock(&nd->path.dentry->d_inode->i_mutex); out: up_write(&namespace_sem); if (!err) - path_release(&parent_nd); - path_release(&old_nd); + path_put(&parent_nd.path); + path_put(&old_nd.path); return err; } @@ -1160,16 +1168,17 @@ int do_add_mount(struct vfsmount *newmnt, struct nameidata *nd, down_write(&namespace_sem); /* Something was mounted here while we slept */ - while (d_mountpoint(nd->dentry) && follow_down(&nd->mnt, &nd->dentry)) + while (d_mountpoint(nd->path.dentry) && + follow_down(&nd->path.mnt, &nd->path.dentry)) ; err = -EINVAL; - if (!check_mnt(nd->mnt)) + if (!check_mnt(nd->path.mnt)) goto unlock; /* Refuse the same filesystem on the same mount point */ err = -EBUSY; - if (nd->mnt->mnt_sb == newmnt->mnt_sb && - nd->mnt->mnt_root == nd->dentry) + if (nd->path.mnt->mnt_sb == newmnt->mnt_sb && + nd->path.mnt->mnt_root == nd->path.dentry) goto unlock; err = -EINVAL; @@ -1505,7 +1514,7 @@ long do_mount(char *dev_name, char *dir_name, char *type_page, retval = do_new_mount(&nd, type_page, flags, mnt_flags, dev_name, data_page); dput_out: - path_release(&nd); + path_put(&nd.path); return retval; } @@ -1552,17 +1561,17 @@ static struct mnt_namespace *dup_mnt_ns(struct mnt_namespace *mnt_ns, while (p) { q->mnt_ns = new_ns; if (fs) { - if (p == fs->rootmnt) { + if (p == fs->root.mnt) { rootmnt = p; - fs->rootmnt = mntget(q); + fs->root.mnt = mntget(q); } - if (p == fs->pwdmnt) { + if (p == fs->pwd.mnt) { pwdmnt = p; - fs->pwdmnt = mntget(q); + fs->pwd.mnt = mntget(q); } - if (p == fs->altrootmnt) { + if (p == fs->altroot.mnt) { altrootmnt = p; - fs->altrootmnt = mntget(q); + fs->altroot.mnt = mntget(q); } } p = next_mnt(p, mnt_ns->root); @@ -1643,44 +1652,35 @@ out1: * Replace the fs->{rootmnt,root} with {mnt,dentry}. Put the old values. * It can block. Requires the big lock held. */ -void set_fs_root(struct fs_struct *fs, struct vfsmount *mnt, - struct dentry *dentry) +void set_fs_root(struct fs_struct *fs, struct path *path) { - struct dentry *old_root; - struct vfsmount *old_rootmnt; + struct path old_root; + write_lock(&fs->lock); old_root = fs->root; - old_rootmnt = fs->rootmnt; - fs->rootmnt = mntget(mnt); - fs->root = dget(dentry); + fs->root = *path; + path_get(path); write_unlock(&fs->lock); - if (old_root) { - dput(old_root); - mntput(old_rootmnt); - } + if (old_root.dentry) + path_put(&old_root); } /* * Replace the fs->{pwdmnt,pwd} with {mnt,dentry}. Put the old values. * It can block. Requires the big lock held. */ -void set_fs_pwd(struct fs_struct *fs, struct vfsmount *mnt, - struct dentry *dentry) +void set_fs_pwd(struct fs_struct *fs, struct path *path) { - struct dentry *old_pwd; - struct vfsmount *old_pwdmnt; + struct path old_pwd; write_lock(&fs->lock); old_pwd = fs->pwd; - old_pwdmnt = fs->pwdmnt; - fs->pwdmnt = mntget(mnt); - fs->pwd = dget(dentry); + fs->pwd = *path; + path_get(path); write_unlock(&fs->lock); - if (old_pwd) { - dput(old_pwd); - mntput(old_pwdmnt); - } + if (old_pwd.dentry) + path_put(&old_pwd); } static void chroot_fs_refs(struct nameidata *old_nd, struct nameidata *new_nd) @@ -1695,12 +1695,12 @@ static void chroot_fs_refs(struct nameidata *old_nd, struct nameidata *new_nd) if (fs) { atomic_inc(&fs->count); task_unlock(p); - if (fs->root == old_nd->dentry - && fs->rootmnt == old_nd->mnt) - set_fs_root(fs, new_nd->mnt, new_nd->dentry); - if (fs->pwd == old_nd->dentry - && fs->pwdmnt == old_nd->mnt) - set_fs_pwd(fs, new_nd->mnt, new_nd->dentry); + if (fs->root.dentry == old_nd->path.dentry + && fs->root.mnt == old_nd->path.mnt) + set_fs_root(fs, &new_nd->path); + if (fs->pwd.dentry == old_nd->path.dentry + && fs->pwd.mnt == old_nd->path.mnt) + set_fs_pwd(fs, &new_nd->path); put_fs_struct(fs); } else task_unlock(p); @@ -1750,7 +1750,7 @@ asmlinkage long sys_pivot_root(const char __user * new_root, if (error) goto out0; error = -EINVAL; - if (!check_mnt(new_nd.mnt)) + if (!check_mnt(new_nd.path.mnt)) goto out1; error = __user_walk(put_old, LOOKUP_FOLLOW | LOOKUP_DIRECTORY, &old_nd); @@ -1759,74 +1759,78 @@ asmlinkage long sys_pivot_root(const char __user * new_root, error = security_sb_pivotroot(&old_nd, &new_nd); if (error) { - path_release(&old_nd); + path_put(&old_nd.path); goto out1; } read_lock(¤t->fs->lock); - user_nd.mnt = mntget(current->fs->rootmnt); - user_nd.dentry = dget(current->fs->root); + user_nd.path = current->fs->root; + path_get(¤t->fs->root); read_unlock(¤t->fs->lock); down_write(&namespace_sem); - mutex_lock(&old_nd.dentry->d_inode->i_mutex); + mutex_lock(&old_nd.path.dentry->d_inode->i_mutex); error = -EINVAL; - if (IS_MNT_SHARED(old_nd.mnt) || - IS_MNT_SHARED(new_nd.mnt->mnt_parent) || - IS_MNT_SHARED(user_nd.mnt->mnt_parent)) + if (IS_MNT_SHARED(old_nd.path.mnt) || + IS_MNT_SHARED(new_nd.path.mnt->mnt_parent) || + IS_MNT_SHARED(user_nd.path.mnt->mnt_parent)) goto out2; - if (!check_mnt(user_nd.mnt)) + if (!check_mnt(user_nd.path.mnt)) goto out2; error = -ENOENT; - if (IS_DEADDIR(new_nd.dentry->d_inode)) + if (IS_DEADDIR(new_nd.path.dentry->d_inode)) goto out2; - if (d_unhashed(new_nd.dentry) && !IS_ROOT(new_nd.dentry)) + if (d_unhashed(new_nd.path.dentry) && !IS_ROOT(new_nd.path.dentry)) goto out2; - if (d_unhashed(old_nd.dentry) && !IS_ROOT(old_nd.dentry)) + if (d_unhashed(old_nd.path.dentry) && !IS_ROOT(old_nd.path.dentry)) goto out2; error = -EBUSY; - if (new_nd.mnt == user_nd.mnt || old_nd.mnt == user_nd.mnt) + if (new_nd.path.mnt == user_nd.path.mnt || + old_nd.path.mnt == user_nd.path.mnt) goto out2; /* loop, on the same file system */ error = -EINVAL; - if (user_nd.mnt->mnt_root != user_nd.dentry) + if (user_nd.path.mnt->mnt_root != user_nd.path.dentry) goto out2; /* not a mountpoint */ - if (user_nd.mnt->mnt_parent == user_nd.mnt) + if (user_nd.path.mnt->mnt_parent == user_nd.path.mnt) goto out2; /* not attached */ - if (new_nd.mnt->mnt_root != new_nd.dentry) + if (new_nd.path.mnt->mnt_root != new_nd.path.dentry) goto out2; /* not a mountpoint */ - if (new_nd.mnt->mnt_parent == new_nd.mnt) + if (new_nd.path.mnt->mnt_parent == new_nd.path.mnt) goto out2; /* not attached */ - tmp = old_nd.mnt; /* make sure we can reach put_old from new_root */ + /* make sure we can reach put_old from new_root */ + tmp = old_nd.path.mnt; spin_lock(&vfsmount_lock); - if (tmp != new_nd.mnt) { + if (tmp != new_nd.path.mnt) { for (;;) { if (tmp->mnt_parent == tmp) goto out3; /* already mounted on put_old */ - if (tmp->mnt_parent == new_nd.mnt) + if (tmp->mnt_parent == new_nd.path.mnt) break; tmp = tmp->mnt_parent; } - if (!is_subdir(tmp->mnt_mountpoint, new_nd.dentry)) + if (!is_subdir(tmp->mnt_mountpoint, new_nd.path.dentry)) goto out3; - } else if (!is_subdir(old_nd.dentry, new_nd.dentry)) + } else if (!is_subdir(old_nd.path.dentry, new_nd.path.dentry)) goto out3; - detach_mnt(new_nd.mnt, &parent_nd); - detach_mnt(user_nd.mnt, &root_parent); - attach_mnt(user_nd.mnt, &old_nd); /* mount old root on put_old */ - attach_mnt(new_nd.mnt, &root_parent); /* mount new_root on / */ + detach_mnt(new_nd.path.mnt, &parent_nd); + detach_mnt(user_nd.path.mnt, &root_parent); + /* mount old root on put_old */ + attach_mnt(user_nd.path.mnt, &old_nd); + /* mount new_root on / */ + attach_mnt(new_nd.path.mnt, &root_parent); touch_mnt_namespace(current->nsproxy->mnt_ns); spin_unlock(&vfsmount_lock); chroot_fs_refs(&user_nd, &new_nd); security_sb_post_pivotroot(&user_nd, &new_nd); error = 0; - path_release(&root_parent); - path_release(&parent_nd); + path_put(&root_parent.path); + path_put(&parent_nd.path); out2: - mutex_unlock(&old_nd.dentry->d_inode->i_mutex); + mutex_unlock(&old_nd.path.dentry->d_inode->i_mutex); up_write(&namespace_sem); - path_release(&user_nd); - path_release(&old_nd); + path_put(&user_nd.path); + path_put(&old_nd.path); out1: - path_release(&new_nd); + path_put(&new_nd.path); out0: unlock_kernel(); return error; @@ -1839,6 +1843,7 @@ static void __init init_mount_tree(void) { struct vfsmount *mnt; struct mnt_namespace *ns; + struct path root; mnt = do_kern_mount("rootfs", 0, "rootfs", NULL); if (IS_ERR(mnt)) @@ -1857,8 +1862,11 @@ static void __init init_mount_tree(void) init_task.nsproxy->mnt_ns = ns; get_mnt_ns(ns); - set_fs_pwd(current->fs, ns->root, ns->root->mnt_root); - set_fs_root(current->fs, ns->root, ns->root->mnt_root); + root.mnt = ns->root; + root.dentry = ns->root->mnt_root; + + set_fs_pwd(current->fs, &root); + set_fs_root(current->fs, &root); } void __init mnt_init(void) diff --git a/fs/nfs/callback.c b/fs/nfs/callback.c index bd185a572a2..ecc06c61949 100644 --- a/fs/nfs/callback.c +++ b/fs/nfs/callback.c @@ -105,7 +105,7 @@ static void nfs_callback_svc(struct svc_rqst *rqstp) */ int nfs_callback_up(void) { - struct svc_serv *serv; + struct svc_serv *serv = NULL; int ret = 0; lock_kernel(); @@ -122,24 +122,30 @@ int nfs_callback_up(void) ret = svc_create_xprt(serv, "tcp", nfs_callback_set_tcpport, SVC_SOCK_ANONYMOUS); if (ret <= 0) - goto out_destroy; + goto out_err; nfs_callback_tcpport = ret; dprintk("Callback port = 0x%x\n", nfs_callback_tcpport); ret = svc_create_thread(nfs_callback_svc, serv); if (ret < 0) - goto out_destroy; + goto out_err; nfs_callback_info.serv = serv; wait_for_completion(&nfs_callback_info.started); out: + /* + * svc_create creates the svc_serv with sv_nrthreads == 1, and then + * svc_create_thread increments that. So we need to call svc_destroy + * on both success and failure so that the refcount is 1 when the + * thread exits. + */ + if (serv) + svc_destroy(serv); mutex_unlock(&nfs_callback_mutex); unlock_kernel(); return ret; -out_destroy: +out_err: dprintk("Couldn't create callback socket or server thread; err = %d\n", ret); - svc_destroy(serv); -out_err: nfs_callback_info.users--; goto out; } diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c index 476cb0f837f..ae04892a5e5 100644 --- a/fs/nfs/dir.c +++ b/fs/nfs/dir.c @@ -154,7 +154,6 @@ typedef struct { struct nfs_entry *entry; decode_dirent_t decode; int plus; - int error; unsigned long timestamp; int timestamp_valid; } nfs_readdir_descriptor_t; @@ -213,7 +212,6 @@ int nfs_readdir_filler(nfs_readdir_descriptor_t *desc, struct page *page) return 0; error: unlock_page(page); - desc->error = error; return -EIO; } @@ -483,13 +481,13 @@ int uncached_readdir(nfs_readdir_descriptor_t *desc, void *dirent, goto out; } timestamp = jiffies; - desc->error = NFS_PROTO(inode)->readdir(file->f_path.dentry, cred, *desc->dir_cookie, - page, + status = NFS_PROTO(inode)->readdir(file->f_path.dentry, cred, + *desc->dir_cookie, page, NFS_SERVER(inode)->dtsize, desc->plus); desc->page = page; desc->ptr = kmap(page); /* matching kunmap in nfs_do_filldir */ - if (desc->error >= 0) { + if (status >= 0) { desc->timestamp = timestamp; desc->timestamp_valid = 1; if ((status = dir_decode(desc)) == 0) diff --git a/fs/nfs/namespace.c b/fs/nfs/namespace.c index be4ce1c3a3d..607f6eb9cdb 100644 --- a/fs/nfs/namespace.c +++ b/fs/nfs/namespace.c @@ -107,38 +107,40 @@ static void * nfs_follow_mountpoint(struct dentry *dentry, struct nameidata *nd) BUG_ON(IS_ROOT(dentry)); dprintk("%s: enter\n", __FUNCTION__); - dput(nd->dentry); - nd->dentry = dget(dentry); + dput(nd->path.dentry); + nd->path.dentry = dget(dentry); /* Look it up again */ - parent = dget_parent(nd->dentry); + parent = dget_parent(nd->path.dentry); err = server->nfs_client->rpc_ops->lookup(parent->d_inode, - &nd->dentry->d_name, + &nd->path.dentry->d_name, &fh, &fattr); dput(parent); if (err != 0) goto out_err; if (fattr.valid & NFS_ATTR_FATTR_V4_REFERRAL) - mnt = nfs_do_refmount(nd->mnt, nd->dentry); + mnt = nfs_do_refmount(nd->path.mnt, nd->path.dentry); else - mnt = nfs_do_submount(nd->mnt, nd->dentry, &fh, &fattr); + mnt = nfs_do_submount(nd->path.mnt, nd->path.dentry, &fh, + &fattr); err = PTR_ERR(mnt); if (IS_ERR(mnt)) goto out_err; mntget(mnt); - err = do_add_mount(mnt, nd, nd->mnt->mnt_flags|MNT_SHRINKABLE, &nfs_automount_list); + err = do_add_mount(mnt, nd, nd->path.mnt->mnt_flags|MNT_SHRINKABLE, + &nfs_automount_list); if (err < 0) { mntput(mnt); if (err == -EBUSY) goto out_follow; goto out_err; } - mntput(nd->mnt); - dput(nd->dentry); - nd->mnt = mnt; - nd->dentry = dget(mnt->mnt_root); + mntput(nd->path.mnt); + dput(nd->path.dentry); + nd->path.mnt = mnt; + nd->path.dentry = dget(mnt->mnt_root); schedule_delayed_work(&nfs_automount_task, nfs_mountpoint_expiry_timeout); out: dprintk("%s: done, returned %d\n", __FUNCTION__, err); @@ -146,10 +148,11 @@ out: dprintk("<-- nfs_follow_mountpoint() = %d\n", err); return ERR_PTR(err); out_err: - path_release(nd); + path_put(&nd->path); goto out; out_follow: - while(d_mountpoint(nd->dentry) && follow_down(&nd->mnt, &nd->dentry)) + while (d_mountpoint(nd->path.dentry) && + follow_down(&nd->path.mnt, &nd->path.dentry)) ; err = 0; goto out; diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index 027e1095256..7ce07862c2f 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c @@ -1384,11 +1384,11 @@ out_close: struct dentry * nfs4_atomic_open(struct inode *dir, struct dentry *dentry, struct nameidata *nd) { - struct dentry *parent; struct path path = { - .mnt = nd->mnt, + .mnt = nd->path.mnt, .dentry = dentry, }; + struct dentry *parent; struct iattr attr; struct rpc_cred *cred; struct nfs4_state *state; @@ -1433,7 +1433,7 @@ int nfs4_open_revalidate(struct inode *dir, struct dentry *dentry, int openflags, struct nameidata *nd) { struct path path = { - .mnt = nd->mnt, + .mnt = nd->path.mnt, .dentry = dentry, }; struct rpc_cred *cred; @@ -1885,7 +1885,7 @@ nfs4_proc_create(struct inode *dir, struct dentry *dentry, struct iattr *sattr, int flags, struct nameidata *nd) { struct path path = { - .mnt = nd->mnt, + .mnt = nd->path.mnt, .dentry = dentry, }; struct nfs4_state *state; diff --git a/fs/nfs/nfs4state.c b/fs/nfs/nfs4state.c index f9c7432471d..6233eb5e98c 100644 --- a/fs/nfs/nfs4state.c +++ b/fs/nfs/nfs4state.c @@ -682,8 +682,8 @@ static void nfs_increment_seqid(int status, struct nfs_seqid *seqid) if (seqid->sequence->flags & NFS_SEQID_CONFIRMED) return; printk(KERN_WARNING "NFS: v4 server returned a bad" - "sequence-id error on an" - "unconfirmed sequence %p!\n", + " sequence-id error on an" + " unconfirmed sequence %p!\n", seqid->sequence); case -NFS4ERR_STALE_CLIENTID: case -NFS4ERR_STALE_STATEID: diff --git a/fs/nfs/super.c b/fs/nfs/super.c index 7f4505f6ac6..1fb38184365 100644 --- a/fs/nfs/super.c +++ b/fs/nfs/super.c @@ -190,6 +190,10 @@ static match_table_t nfs_secflavor_tokens = { { Opt_sec_lkeyi, "lkeyi" }, { Opt_sec_lkeyp, "lkeyp" }, + { Opt_sec_spkm, "spkm3" }, + { Opt_sec_spkmi, "spkm3i" }, + { Opt_sec_spkmp, "spkm3p" }, + { Opt_sec_err, NULL } }; diff --git a/fs/nfsctl.c b/fs/nfsctl.c index 51f1b31acbf..aed8145d908 100644 --- a/fs/nfsctl.c +++ b/fs/nfsctl.c @@ -41,9 +41,9 @@ static struct file *do_open(char *name, int flags) error = may_open(&nd, MAY_WRITE, FMODE_WRITE); if (!error) - return dentry_open(nd.dentry, nd.mnt, flags); + return dentry_open(nd.path.dentry, nd.path.mnt, flags); - path_release(&nd); + path_put(&nd.path); return ERR_PTR(error); } diff --git a/fs/nfsd/export.c b/fs/nfsd/export.c index 346570f6d84..8a6f7c924c7 100644 --- a/fs/nfsd/export.c +++ b/fs/nfsd/export.c @@ -63,10 +63,8 @@ static void expkey_put(struct kref *ref) struct svc_expkey *key = container_of(ref, struct svc_expkey, h.ref); if (test_bit(CACHE_VALID, &key->h.flags) && - !test_bit(CACHE_NEGATIVE, &key->h.flags)) { - dput(key->ek_dentry); - mntput(key->ek_mnt); - } + !test_bit(CACHE_NEGATIVE, &key->h.flags)) + path_put(&key->ek_path); auth_domain_put(key->ek_client); kfree(key); } @@ -169,15 +167,14 @@ static int expkey_parse(struct cache_detail *cd, char *mesg, int mlen) goto out; dprintk("Found the path %s\n", buf); - key.ek_mnt = nd.mnt; - key.ek_dentry = nd.dentry; - + key.ek_path = nd.path; + ek = svc_expkey_update(&key, ek); if (ek) cache_put(&ek->h, &svc_expkey_cache); else err = -ENOMEM; - path_release(&nd); + path_put(&nd.path); } cache_flush(); out: @@ -206,7 +203,7 @@ static int expkey_show(struct seq_file *m, if (test_bit(CACHE_VALID, &h->flags) && !test_bit(CACHE_NEGATIVE, &h->flags)) { seq_printf(m, " "); - seq_path(m, ek->ek_mnt, ek->ek_dentry, "\\ \t\n"); + seq_path(m, &ek->ek_path, "\\ \t\n"); } seq_printf(m, "\n"); return 0; @@ -243,8 +240,8 @@ static inline void expkey_update(struct cache_head *cnew, struct svc_expkey *new = container_of(cnew, struct svc_expkey, h); struct svc_expkey *item = container_of(citem, struct svc_expkey, h); - new->ek_mnt = mntget(item->ek_mnt); - new->ek_dentry = dget(item->ek_dentry); + new->ek_path = item->ek_path; + path_get(&item->ek_path); } static struct cache_head *expkey_alloc(void) @@ -332,10 +329,9 @@ static void nfsd4_fslocs_free(struct nfsd4_fs_locations *fsloc) static void svc_export_put(struct kref *ref) { struct svc_export *exp = container_of(ref, struct svc_export, h.ref); - dput(exp->ex_dentry); - mntput(exp->ex_mnt); + path_put(&exp->ex_path); auth_domain_put(exp->ex_client); - kfree(exp->ex_path); + kfree(exp->ex_pathname); nfsd4_fslocs_free(&exp->ex_fslocs); kfree(exp); } @@ -349,7 +345,7 @@ static void svc_export_request(struct cache_detail *cd, char *pth; qword_add(bpp, blen, exp->ex_client->name); - pth = d_path(exp->ex_dentry, exp->ex_mnt, *bpp, *blen); + pth = d_path(&exp->ex_path, *bpp, *blen); if (IS_ERR(pth)) { /* is this correct? */ (*bpp)[0] = '\n'; @@ -507,8 +503,8 @@ static int svc_export_parse(struct cache_detail *cd, char *mesg, int mlen) struct svc_export exp, *expp; int an_int; - nd.dentry = NULL; - exp.ex_path = NULL; + nd.path.dentry = NULL; + exp.ex_pathname = NULL; /* fs locations */ exp.ex_fslocs.locations = NULL; @@ -547,11 +543,11 @@ static int svc_export_parse(struct cache_detail *cd, char *mesg, int mlen) exp.h.flags = 0; exp.ex_client = dom; - exp.ex_mnt = nd.mnt; - exp.ex_dentry = nd.dentry; - exp.ex_path = kstrdup(buf, GFP_KERNEL); + exp.ex_path.mnt = nd.path.mnt; + exp.ex_path.dentry = nd.path.dentry; + exp.ex_pathname = kstrdup(buf, GFP_KERNEL); err = -ENOMEM; - if (!exp.ex_path) + if (!exp.ex_pathname) goto out; /* expiry */ @@ -610,7 +606,7 @@ static int svc_export_parse(struct cache_detail *cd, char *mesg, int mlen) goto out; } - err = check_export(nd.dentry->d_inode, exp.ex_flags, + err = check_export(nd.path.dentry->d_inode, exp.ex_flags, exp.ex_uuid); if (err) goto out; } @@ -628,9 +624,9 @@ static int svc_export_parse(struct cache_detail *cd, char *mesg, int mlen) out: nfsd4_fslocs_free(&exp.ex_fslocs); kfree(exp.ex_uuid); - kfree(exp.ex_path); - if (nd.dentry) - path_release(&nd); + kfree(exp.ex_pathname); + if (nd.path.dentry) + path_put(&nd.path); out_no_path: if (dom) auth_domain_put(dom); @@ -653,7 +649,7 @@ static int svc_export_show(struct seq_file *m, return 0; } exp = container_of(h, struct svc_export, h); - seq_path(m, exp->ex_mnt, exp->ex_dentry, " \t\n\\"); + seq_path(m, &exp->ex_path, " \t\n\\"); seq_putc(m, '\t'); seq_escape(m, exp->ex_client->name, " \t\n\\"); seq_putc(m, '('); @@ -680,8 +676,8 @@ static int svc_export_match(struct cache_head *a, struct cache_head *b) struct svc_export *orig = container_of(a, struct svc_export, h); struct svc_export *new = container_of(b, struct svc_export, h); return orig->ex_client == new->ex_client && - orig->ex_dentry == new->ex_dentry && - orig->ex_mnt == new->ex_mnt; + orig->ex_path.dentry == new->ex_path.dentry && + orig->ex_path.mnt == new->ex_path.mnt; } static void svc_export_init(struct cache_head *cnew, struct cache_head *citem) @@ -691,9 +687,9 @@ static void svc_export_init(struct cache_head *cnew, struct cache_head *citem) kref_get(&item->ex_client->ref); new->ex_client = item->ex_client; - new->ex_dentry = dget(item->ex_dentry); - new->ex_mnt = mntget(item->ex_mnt); - new->ex_path = NULL; + new->ex_path.dentry = dget(item->ex_path.dentry); + new->ex_path.mnt = mntget(item->ex_path.mnt); + new->ex_pathname = NULL; new->ex_fslocs.locations = NULL; new->ex_fslocs.locations_count = 0; new->ex_fslocs.migrated = 0; @@ -711,8 +707,8 @@ static void export_update(struct cache_head *cnew, struct cache_head *citem) new->ex_fsid = item->ex_fsid; new->ex_uuid = item->ex_uuid; item->ex_uuid = NULL; - new->ex_path = item->ex_path; - item->ex_path = NULL; + new->ex_pathname = item->ex_pathname; + item->ex_pathname = NULL; new->ex_fslocs.locations = item->ex_fslocs.locations; item->ex_fslocs.locations = NULL; new->ex_fslocs.locations_count = item->ex_fslocs.locations_count; @@ -755,8 +751,8 @@ svc_export_lookup(struct svc_export *exp) struct cache_head *ch; int hash; hash = hash_ptr(exp->ex_client, EXPORT_HASHBITS); - hash ^= hash_ptr(exp->ex_dentry, EXPORT_HASHBITS); - hash ^= hash_ptr(exp->ex_mnt, EXPORT_HASHBITS); + hash ^= hash_ptr(exp->ex_path.dentry, EXPORT_HASHBITS); + hash ^= hash_ptr(exp->ex_path.mnt, EXPORT_HASHBITS); ch = sunrpc_cache_lookup(&svc_export_cache, &exp->h, hash); @@ -772,8 +768,8 @@ svc_export_update(struct svc_export *new, struct svc_export *old) struct cache_head *ch; int hash; hash = hash_ptr(old->ex_client, EXPORT_HASHBITS); - hash ^= hash_ptr(old->ex_dentry, EXPORT_HASHBITS); - hash ^= hash_ptr(old->ex_mnt, EXPORT_HASHBITS); + hash ^= hash_ptr(old->ex_path.dentry, EXPORT_HASHBITS); + hash ^= hash_ptr(old->ex_path.mnt, EXPORT_HASHBITS); ch = sunrpc_cache_update(&svc_export_cache, &new->h, &old->h, @@ -815,8 +811,7 @@ static int exp_set_key(svc_client *clp, int fsid_type, u32 *fsidv, key.ek_client = clp; key.ek_fsidtype = fsid_type; memcpy(key.ek_fsid, fsidv, key_len(fsid_type)); - key.ek_mnt = exp->ex_mnt; - key.ek_dentry = exp->ex_dentry; + key.ek_path = exp->ex_path; key.h.expiry_time = NEVER; key.h.flags = 0; @@ -865,13 +860,13 @@ static svc_export *exp_get_by_name(svc_client *clp, struct vfsmount *mnt, { struct svc_export *exp, key; int err; - + if (!clp) return ERR_PTR(-ENOENT); key.ex_client = clp; - key.ex_mnt = mnt; - key.ex_dentry = dentry; + key.ex_path.mnt = mnt; + key.ex_path.dentry = dentry; exp = svc_export_lookup(&key); if (exp == NULL) @@ -968,7 +963,7 @@ static int exp_fsid_hash(svc_client *clp, struct svc_export *exp) static int exp_hash(struct auth_domain *clp, struct svc_export *exp) { u32 fsid[2]; - struct inode *inode = exp->ex_dentry->d_inode; + struct inode *inode = exp->ex_path.dentry->d_inode; dev_t dev = inode->i_sb->s_dev; if (old_valid_dev(dev)) { @@ -982,7 +977,7 @@ static int exp_hash(struct auth_domain *clp, struct svc_export *exp) static void exp_unhash(struct svc_export *exp) { struct svc_expkey *ek; - struct inode *inode = exp->ex_dentry->d_inode; + struct inode *inode = exp->ex_path.dentry->d_inode; ek = exp_get_key(exp->ex_client, inode->i_sb->s_dev, inode->i_ino); if (!IS_ERR(ek)) { @@ -1030,15 +1025,16 @@ exp_export(struct nfsctl_export *nxp) goto out_unlock; err = -EINVAL; - exp = exp_get_by_name(clp, nd.mnt, nd.dentry, NULL); + exp = exp_get_by_name(clp, nd.path.mnt, nd.path.dentry, NULL); memset(&new, 0, sizeof(new)); /* must make sure there won't be an ex_fsid clash */ if ((nxp->ex_flags & NFSEXP_FSID) && (!IS_ERR(fsid_key = exp_get_fsid_key(clp, nxp->ex_dev))) && - fsid_key->ek_mnt && - (fsid_key->ek_mnt != nd.mnt || fsid_key->ek_dentry != nd.dentry) ) + fsid_key->ek_path.mnt && + (fsid_key->ek_path.mnt != nd.path.mnt || + fsid_key->ek_path.dentry != nd.path.dentry)) goto finish; if (!IS_ERR(exp)) { @@ -1054,7 +1050,7 @@ exp_export(struct nfsctl_export *nxp) goto finish; } - err = check_export(nd.dentry->d_inode, nxp->ex_flags, NULL); + err = check_export(nd.path.dentry->d_inode, nxp->ex_flags, NULL); if (err) goto finish; err = -ENOMEM; @@ -1063,12 +1059,11 @@ exp_export(struct nfsctl_export *nxp) new.h.expiry_time = NEVER; new.h.flags = 0; - new.ex_path = kstrdup(nxp->ex_path, GFP_KERNEL); - if (!new.ex_path) + new.ex_pathname = kstrdup(nxp->ex_path, GFP_KERNEL); + if (!new.ex_pathname) goto finish; new.ex_client = clp; - new.ex_mnt = nd.mnt; - new.ex_dentry = nd.dentry; + new.ex_path = nd.path; new.ex_flags = nxp->ex_flags; new.ex_anon_uid = nxp->ex_anon_uid; new.ex_anon_gid = nxp->ex_anon_gid; @@ -1089,15 +1084,14 @@ exp_export(struct nfsctl_export *nxp) } else err = 0; finish: - if (new.ex_path) - kfree(new.ex_path); + kfree(new.ex_pathname); if (exp) exp_put(exp); if (fsid_key && !IS_ERR(fsid_key)) cache_put(&fsid_key->h, &svc_expkey_cache); if (clp) auth_domain_put(clp); - path_release(&nd); + path_put(&nd.path); out_unlock: exp_writeunlock(); out: @@ -1148,8 +1142,8 @@ exp_unexport(struct nfsctl_export *nxp) goto out_domain; err = -EINVAL; - exp = exp_get_by_name(dom, nd.mnt, nd.dentry, NULL); - path_release(&nd); + exp = exp_get_by_name(dom, nd.path.mnt, nd.path.dentry, NULL); + path_put(&nd.path); if (IS_ERR(exp)) goto out_domain; @@ -1185,12 +1179,12 @@ exp_rootfh(svc_client *clp, char *path, struct knfsd_fh *f, int maxsize) printk("nfsd: exp_rootfh path not found %s", path); return err; } - inode = nd.dentry->d_inode; + inode = nd.path.dentry->d_inode; dprintk("nfsd: exp_rootfh(%s [%p] %s:%s/%ld)\n", - path, nd.dentry, clp->name, + path, nd.path.dentry, clp->name, inode->i_sb->s_id, inode->i_ino); - exp = exp_parent(clp, nd.mnt, nd.dentry, NULL); + exp = exp_parent(clp, nd.path.mnt, nd.path.dentry, NULL); if (IS_ERR(exp)) { err = PTR_ERR(exp); goto out; @@ -1200,7 +1194,7 @@ exp_rootfh(svc_client *clp, char *path, struct knfsd_fh *f, int maxsize) * fh must be initialized before calling fh_compose */ fh_init(&fh, maxsize); - if (fh_compose(&fh, exp, nd.dentry, NULL)) + if (fh_compose(&fh, exp, nd.path.dentry, NULL)) err = -EINVAL; else err = 0; @@ -1208,7 +1202,7 @@ exp_rootfh(svc_client *clp, char *path, struct knfsd_fh *f, int maxsize) fh_put(&fh); exp_put(exp); out: - path_release(&nd); + path_put(&nd.path); return err; } @@ -1220,7 +1214,7 @@ static struct svc_export *exp_find(struct auth_domain *clp, int fsid_type, if (IS_ERR(ek)) return ERR_CAST(ek); - exp = exp_get_by_name(clp, ek->ek_mnt, ek->ek_dentry, reqp); + exp = exp_get_by_name(clp, ek->ek_path.mnt, ek->ek_path.dentry, reqp); cache_put(&ek->h, &svc_expkey_cache); if (IS_ERR(exp)) @@ -1359,7 +1353,7 @@ exp_pseudoroot(struct svc_rqst *rqstp, struct svc_fh *fhp) exp = rqst_exp_find(rqstp, FSID_NUM, fsidv); if (IS_ERR(exp)) return nfserrno(PTR_ERR(exp)); - rv = fh_compose(fhp, exp, exp->ex_dentry, NULL); + rv = fh_compose(fhp, exp, exp->ex_path.dentry, NULL); if (rv) goto out; rv = check_nfsd_access(exp, rqstp); diff --git a/fs/nfsd/nfs3proc.c b/fs/nfsd/nfs3proc.c index eac82830bfd..c721a1e6e9d 100644 --- a/fs/nfsd/nfs3proc.c +++ b/fs/nfsd/nfs3proc.c @@ -67,7 +67,7 @@ nfsd3_proc_getattr(struct svc_rqst *rqstp, struct nfsd_fhandle *argp, if (nfserr) RETURN_STATUS(nfserr); - err = vfs_getattr(resp->fh.fh_export->ex_mnt, + err = vfs_getattr(resp->fh.fh_export->ex_path.mnt, resp->fh.fh_dentry, &resp->stat); nfserr = nfserrno(err); diff --git a/fs/nfsd/nfs3xdr.c b/fs/nfsd/nfs3xdr.c index d7647f70e02..17d0dd99720 100644 --- a/fs/nfsd/nfs3xdr.c +++ b/fs/nfsd/nfs3xdr.c @@ -218,7 +218,7 @@ encode_post_op_attr(struct svc_rqst *rqstp, __be32 *p, struct svc_fh *fhp) int err; struct kstat stat; - err = vfs_getattr(fhp->fh_export->ex_mnt, dentry, &stat); + err = vfs_getattr(fhp->fh_export->ex_path.mnt, dentry, &stat); if (!err) { *p++ = xdr_one; /* attributes follow */ lease_get_mtime(dentry->d_inode, &stat.mtime); @@ -270,7 +270,7 @@ void fill_post_wcc(struct svc_fh *fhp) if (fhp->fh_post_saved) printk("nfsd: inode locked twice during operation.\n"); - err = vfs_getattr(fhp->fh_export->ex_mnt, fhp->fh_dentry, + err = vfs_getattr(fhp->fh_export->ex_path.mnt, fhp->fh_dentry, &fhp->fh_post_attr); if (err) fhp->fh_post_saved = 0; diff --git a/fs/nfsd/nfs4recover.c b/fs/nfsd/nfs4recover.c index 1602cd00dd4..1ff90625860 100644 --- a/fs/nfsd/nfs4recover.c +++ b/fs/nfsd/nfs4recover.c @@ -120,9 +120,9 @@ out_no_tfm: static void nfsd4_sync_rec_dir(void) { - mutex_lock(&rec_dir.dentry->d_inode->i_mutex); - nfsd_sync_dir(rec_dir.dentry); - mutex_unlock(&rec_dir.dentry->d_inode->i_mutex); + mutex_lock(&rec_dir.path.dentry->d_inode->i_mutex); + nfsd_sync_dir(rec_dir.path.dentry); + mutex_unlock(&rec_dir.path.dentry->d_inode->i_mutex); } int @@ -142,9 +142,9 @@ nfsd4_create_clid_dir(struct nfs4_client *clp) nfs4_save_user(&uid, &gid); /* lock the parent */ - mutex_lock(&rec_dir.dentry->d_inode->i_mutex); + mutex_lock(&rec_dir.path.dentry->d_inode->i_mutex); - dentry = lookup_one_len(dname, rec_dir.dentry, HEXDIR_LEN-1); + dentry = lookup_one_len(dname, rec_dir.path.dentry, HEXDIR_LEN-1); if (IS_ERR(dentry)) { status = PTR_ERR(dentry); goto out_unlock; @@ -154,11 +154,11 @@ nfsd4_create_clid_dir(struct nfs4_client *clp) dprintk("NFSD: nfsd4_create_clid_dir: DIRECTORY EXISTS\n"); goto out_put; } - status = vfs_mkdir(rec_dir.dentry->d_inode, dentry, S_IRWXU); + status = vfs_mkdir(rec_dir.path.dentry->d_inode, dentry, S_IRWXU); out_put: dput(dentry); out_unlock: - mutex_unlock(&rec_dir.dentry->d_inode->i_mutex); + mutex_unlock(&rec_dir.path.dentry->d_inode->i_mutex); if (status == 0) { clp->cl_firststate = 1; nfsd4_sync_rec_dir(); @@ -221,7 +221,7 @@ nfsd4_list_rec_dir(struct dentry *dir, recdir_func *f) nfs4_save_user(&uid, &gid); - filp = dentry_open(dget(dir), mntget(rec_dir.mnt), O_RDONLY); + filp = dentry_open(dget(dir), mntget(rec_dir.path.mnt), O_RDONLY); status = PTR_ERR(filp); if (IS_ERR(filp)) goto out; @@ -286,9 +286,9 @@ nfsd4_unlink_clid_dir(char *name, int namlen) dprintk("NFSD: nfsd4_unlink_clid_dir. name %.*s\n", namlen, name); - mutex_lock(&rec_dir.dentry->d_inode->i_mutex); - dentry = lookup_one_len(name, rec_dir.dentry, namlen); - mutex_unlock(&rec_dir.dentry->d_inode->i_mutex); + mutex_lock(&rec_dir.path.dentry->d_inode->i_mutex); + dentry = lookup_one_len(name, rec_dir.path.dentry, namlen); + mutex_unlock(&rec_dir.path.dentry->d_inode->i_mutex); if (IS_ERR(dentry)) { status = PTR_ERR(dentry); return status; @@ -297,7 +297,7 @@ nfsd4_unlink_clid_dir(char *name, int namlen) if (!dentry->d_inode) goto out; - status = nfsd4_clear_clid_dir(rec_dir.dentry, dentry); + status = nfsd4_clear_clid_dir(rec_dir.path.dentry, dentry); out: dput(dentry); return status; @@ -347,12 +347,12 @@ nfsd4_recdir_purge_old(void) { if (!rec_dir_init) return; - status = nfsd4_list_rec_dir(rec_dir.dentry, purge_old); + status = nfsd4_list_rec_dir(rec_dir.path.dentry, purge_old); if (status == 0) nfsd4_sync_rec_dir(); if (status) printk("nfsd4: failed to purge old clients from recovery" - " directory %s\n", rec_dir.dentry->d_name.name); + " directory %s\n", rec_dir.path.dentry->d_name.name); return; } @@ -373,10 +373,10 @@ int nfsd4_recdir_load(void) { int status; - status = nfsd4_list_rec_dir(rec_dir.dentry, load_recdir); + status = nfsd4_list_rec_dir(rec_dir.path.dentry, load_recdir); if (status) printk("nfsd4: failed loading clients from recovery" - " directory %s\n", rec_dir.dentry->d_name.name); + " directory %s\n", rec_dir.path.dentry->d_name.name); return status; } @@ -415,5 +415,5 @@ nfsd4_shutdown_recdir(void) if (!rec_dir_init) return; rec_dir_init = 0; - path_release(&rec_dir); + path_put(&rec_dir.path); } diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index f6744bc03da..bcb97d8e8b8 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c @@ -3261,11 +3261,11 @@ nfs4_reset_recoverydir(char *recdir) if (status) return status; status = -ENOTDIR; - if (S_ISDIR(nd.dentry->d_inode->i_mode)) { + if (S_ISDIR(nd.path.dentry->d_inode->i_mode)) { nfs4_set_recdir(recdir); status = 0; } - path_release(&nd); + path_put(&nd.path); return status; } diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c index b0592e7c378..0e6a179ecca 100644 --- a/fs/nfsd/nfs4xdr.c +++ b/fs/nfsd/nfs4xdr.c @@ -1330,9 +1330,9 @@ static char *nfsd4_path(struct svc_rqst *rqstp, struct svc_export *exp, __be32 * *stat = exp_pseudoroot(rqstp, &tmp_fh); if (*stat) return NULL; - rootpath = tmp_fh.fh_export->ex_path; + rootpath = tmp_fh.fh_export->ex_pathname; - path = exp->ex_path; + path = exp->ex_pathname; if (strncmp(path, rootpath, strlen(rootpath))) { dprintk("nfsd: fs_locations failed;" @@ -1481,7 +1481,7 @@ nfsd4_encode_fattr(struct svc_fh *fhp, struct svc_export *exp, goto out; } - err = vfs_getattr(exp->ex_mnt, dentry, &stat); + err = vfs_getattr(exp->ex_path.mnt, dentry, &stat); if (err) goto out_nfserr; if ((bmval0 & (FATTR4_WORD0_FILES_FREE | FATTR4_WORD0_FILES_TOTAL | @@ -1838,9 +1838,9 @@ out_acl: * and this is the root of a cross-mounted filesystem. */ if (ignore_crossmnt == 0 && - exp->ex_mnt->mnt_root->d_inode == dentry->d_inode) { - err = vfs_getattr(exp->ex_mnt->mnt_parent, - exp->ex_mnt->mnt_mountpoint, &stat); + exp->ex_path.mnt->mnt_root->d_inode == dentry->d_inode) { + err = vfs_getattr(exp->ex_path.mnt->mnt_parent, + exp->ex_path.mnt->mnt_mountpoint, &stat); if (err) goto out_nfserr; } diff --git a/fs/nfsd/nfsfh.c b/fs/nfsd/nfsfh.c index 8fbd2dc08a9..0130b345234 100644 --- a/fs/nfsd/nfsfh.c +++ b/fs/nfsd/nfsfh.c @@ -47,7 +47,7 @@ static int nfsd_acceptable(void *expv, struct dentry *dentry) return 1; tdentry = dget(dentry); - while (tdentry != exp->ex_dentry && ! IS_ROOT(tdentry)) { + while (tdentry != exp->ex_path.dentry && !IS_ROOT(tdentry)) { /* make sure parents give x permission to user */ int err; parent = dget_parent(tdentry); @@ -59,9 +59,9 @@ static int nfsd_acceptable(void *expv, struct dentry *dentry) dput(tdentry); tdentry = parent; } - if (tdentry != exp->ex_dentry) + if (tdentry != exp->ex_path.dentry) dprintk("nfsd_acceptable failed at %p %s\n", tdentry, tdentry->d_name.name); - rv = (tdentry == exp->ex_dentry); + rv = (tdentry == exp->ex_path.dentry); dput(tdentry); return rv; } @@ -209,9 +209,9 @@ fh_verify(struct svc_rqst *rqstp, struct svc_fh *fhp, int type, int access) fileid_type = fh->fh_fileid_type; if (fileid_type == FILEID_ROOT) - dentry = dget(exp->ex_dentry); + dentry = dget(exp->ex_path.dentry); else { - dentry = exportfs_decode_fh(exp->ex_mnt, fid, + dentry = exportfs_decode_fh(exp->ex_path.mnt, fid, data_left, fileid_type, nfsd_acceptable, exp); } @@ -299,7 +299,7 @@ out: static void _fh_update(struct svc_fh *fhp, struct svc_export *exp, struct dentry *dentry) { - if (dentry != exp->ex_dentry) { + if (dentry != exp->ex_path.dentry) { struct fid *fid = (struct fid *) (fhp->fh_handle.fh_auth + fhp->fh_handle.fh_size/4 - 1); int maxsize = (fhp->fh_maxsize - fhp->fh_handle.fh_size)/4; @@ -344,12 +344,12 @@ fh_compose(struct svc_fh *fhp, struct svc_export *exp, struct dentry *dentry, struct inode * inode = dentry->d_inode; struct dentry *parent = dentry->d_parent; __u32 *datap; - dev_t ex_dev = exp->ex_dentry->d_inode->i_sb->s_dev; - int root_export = (exp->ex_dentry == exp->ex_dentry->d_sb->s_root); + dev_t ex_dev = exp->ex_path.dentry->d_inode->i_sb->s_dev; + int root_export = (exp->ex_path.dentry == exp->ex_path.dentry->d_sb->s_root); dprintk("nfsd: fh_compose(exp %02x:%02x/%ld %s/%s, ino=%ld)\n", MAJOR(ex_dev), MINOR(ex_dev), - (long) exp->ex_dentry->d_inode->i_ino, + (long) exp->ex_path.dentry->d_inode->i_ino, parent->d_name.name, dentry->d_name.name, (inode ? inode->i_ino : 0)); @@ -391,7 +391,7 @@ fh_compose(struct svc_fh *fhp, struct svc_export *exp, struct dentry *dentry, /* FALL THROUGH */ case FSID_MAJOR_MINOR: case FSID_ENCODE_DEV: - if (!(exp->ex_dentry->d_inode->i_sb->s_type->fs_flags + if (!(exp->ex_path.dentry->d_inode->i_sb->s_type->fs_flags & FS_REQUIRES_DEV)) goto retry; break; @@ -454,7 +454,7 @@ fh_compose(struct svc_fh *fhp, struct svc_export *exp, struct dentry *dentry, fhp->fh_handle.ofh_dev = old_encode_dev(ex_dev); fhp->fh_handle.ofh_xdev = fhp->fh_handle.ofh_dev; fhp->fh_handle.ofh_xino = - ino_t_to_u32(exp->ex_dentry->d_inode->i_ino); + ino_t_to_u32(exp->ex_path.dentry->d_inode->i_ino); fhp->fh_handle.ofh_dirino = ino_t_to_u32(parent_ino(dentry)); if (inode) _fh_update_old(dentry, exp, &fhp->fh_handle); @@ -465,7 +465,7 @@ fh_compose(struct svc_fh *fhp, struct svc_export *exp, struct dentry *dentry, datap = fhp->fh_handle.fh_auth+0; fhp->fh_handle.fh_fsid_type = fsid_type; mk_fsid(fsid_type, datap, ex_dev, - exp->ex_dentry->d_inode->i_ino, + exp->ex_path.dentry->d_inode->i_ino, exp->ex_fsid, exp->ex_uuid); len = key_len(fsid_type); @@ -571,7 +571,7 @@ enum fsid_source fsid_source(struct svc_fh *fhp) case FSID_DEV: case FSID_ENCODE_DEV: case FSID_MAJOR_MINOR: - if (fhp->fh_export->ex_dentry->d_inode->i_sb->s_type->fs_flags + if (fhp->fh_export->ex_path.dentry->d_inode->i_sb->s_type->fs_flags & FS_REQUIRES_DEV) return FSIDSOURCE_DEV; break; diff --git a/fs/nfsd/nfsproc.c b/fs/nfsd/nfsproc.c index 977a71f64e1..6cfc96a1248 100644 --- a/fs/nfsd/nfsproc.c +++ b/fs/nfsd/nfsproc.c @@ -41,7 +41,7 @@ static __be32 nfsd_return_attrs(__be32 err, struct nfsd_attrstat *resp) { if (err) return err; - return nfserrno(vfs_getattr(resp->fh.fh_export->ex_mnt, + return nfserrno(vfs_getattr(resp->fh.fh_export->ex_path.mnt, resp->fh.fh_dentry, &resp->stat)); } @@ -49,7 +49,7 @@ static __be32 nfsd_return_dirop(__be32 err, struct nfsd_diropres *resp) { if (err) return err; - return nfserrno(vfs_getattr(resp->fh.fh_export->ex_mnt, + return nfserrno(vfs_getattr(resp->fh.fh_export->ex_path.mnt, resp->fh.fh_dentry, &resp->stat)); } @@ -164,7 +164,7 @@ nfsd_proc_read(struct svc_rqst *rqstp, struct nfsd_readargs *argp, &resp->count); if (nfserr) return nfserr; - return nfserrno(vfs_getattr(resp->fh.fh_export->ex_mnt, + return nfserrno(vfs_getattr(resp->fh.fh_export->ex_path.mnt, resp->fh.fh_dentry, &resp->stat)); } diff --git a/fs/nfsd/nfsxdr.c b/fs/nfsd/nfsxdr.c index 61ad61743d9..afd08e2c90a 100644 --- a/fs/nfsd/nfsxdr.c +++ b/fs/nfsd/nfsxdr.c @@ -207,7 +207,7 @@ encode_fattr(struct svc_rqst *rqstp, __be32 *p, struct svc_fh *fhp, __be32 *nfs2svc_encode_fattr(struct svc_rqst *rqstp, __be32 *p, struct svc_fh *fhp) { struct kstat stat; - vfs_getattr(fhp->fh_export->ex_mnt, fhp->fh_dentry, &stat); + vfs_getattr(fhp->fh_export->ex_path.mnt, fhp->fh_dentry, &stat); return encode_fattr(rqstp, p, fhp, &stat); } diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c index cc75e4fcd02..46f59d5365a 100644 --- a/fs/nfsd/vfs.c +++ b/fs/nfsd/vfs.c @@ -101,7 +101,7 @@ nfsd_cross_mnt(struct svc_rqst *rqstp, struct dentry **dpp, { struct svc_export *exp = *expp, *exp2 = NULL; struct dentry *dentry = *dpp; - struct vfsmount *mnt = mntget(exp->ex_mnt); + struct vfsmount *mnt = mntget(exp->ex_path.mnt); struct dentry *mounts = dget(dentry); int err = 0; @@ -156,15 +156,15 @@ nfsd_lookup_dentry(struct svc_rqst *rqstp, struct svc_fh *fhp, if (isdotent(name, len)) { if (len==1) dentry = dget(dparent); - else if (dparent != exp->ex_dentry) { + else if (dparent != exp->ex_path.dentry) dentry = dget_parent(dparent); - } else if (!EX_NOHIDE(exp)) + else if (!EX_NOHIDE(exp)) dentry = dget(dparent); /* .. == . just like at / */ else { /* checking mountpoint crossing is very different when stepping up */ struct svc_export *exp2 = NULL; struct dentry *dp; - struct vfsmount *mnt = mntget(exp->ex_mnt); + struct vfsmount *mnt = mntget(exp->ex_path.mnt); dentry = dget(dparent); while(dentry == mnt->mnt_root && follow_up(&mnt, &dentry)) ; @@ -721,7 +721,8 @@ nfsd_open(struct svc_rqst *rqstp, struct svc_fh *fhp, int type, DQUOT_INIT(inode); } - *filp = dentry_open(dget(dentry), mntget(fhp->fh_export->ex_mnt), flags); + *filp = dentry_open(dget(dentry), mntget(fhp->fh_export->ex_path.mnt), + flags); if (IS_ERR(*filp)) host_err = PTR_ERR(*filp); out_nfserr: @@ -1462,7 +1463,7 @@ nfsd_readlink(struct svc_rqst *rqstp, struct svc_fh *fhp, char *buf, int *lenp) if (!inode->i_op || !inode->i_op->readlink) goto out; - touch_atime(fhp->fh_export->ex_mnt, dentry); + touch_atime(fhp->fh_export->ex_path.mnt, dentry); /* N.B. Why does this call need a get_fs()?? * Remove the set_fs and watch the fireworks:-) --okir */ diff --git a/fs/open.c b/fs/open.c index 43fcd603196..54198538b67 100644 --- a/fs/open.c +++ b/fs/open.c @@ -127,10 +127,10 @@ asmlinkage long sys_statfs(const char __user * path, struct statfs __user * buf) error = user_path_walk(path, &nd); if (!error) { struct statfs tmp; - error = vfs_statfs_native(nd.dentry, &tmp); + error = vfs_statfs_native(nd.path.dentry, &tmp); if (!error && copy_to_user(buf, &tmp, sizeof(tmp))) error = -EFAULT; - path_release(&nd); + path_put(&nd.path); } return error; } @@ -146,10 +146,10 @@ asmlinkage long sys_statfs64(const char __user *path, size_t sz, struct statfs64 error = user_path_walk(path, &nd); if (!error) { struct statfs64 tmp; - error = vfs_statfs64(nd.dentry, &tmp); + error = vfs_statfs64(nd.path.dentry, &tmp); if (!error && copy_to_user(buf, &tmp, sizeof(tmp))) error = -EFAULT; - path_release(&nd); + path_put(&nd.path); } return error; } @@ -233,7 +233,7 @@ static long do_sys_truncate(const char __user * path, loff_t length) error = user_path_walk(path, &nd); if (error) goto out; - inode = nd.dentry->d_inode; + inode = nd.path.dentry->d_inode; /* For directories it's -EISDIR, for other non-regulars - -EINVAL */ error = -EISDIR; @@ -271,13 +271,13 @@ static long do_sys_truncate(const char __user * path, loff_t length) error = locks_verify_truncate(inode, NULL, length); if (!error) { DQUOT_INIT(inode); - error = do_truncate(nd.dentry, length, 0, NULL); + error = do_truncate(nd.path.dentry, length, 0, NULL); } put_write_and_out: put_write_access(inode); dput_and_out: - path_release(&nd); + path_put(&nd.path); out: return error; } @@ -455,14 +455,14 @@ asmlinkage long sys_faccessat(int dfd, const char __user *filename, int mode) res = vfs_permission(&nd, mode); /* SuS v2 requires we report a read only fs too */ if(res || !(mode & S_IWOTH) || - special_file(nd.dentry->d_inode->i_mode)) + special_file(nd.path.dentry->d_inode->i_mode)) goto out_path_release; - if(IS_RDONLY(nd.dentry->d_inode)) + if(IS_RDONLY(nd.path.dentry->d_inode)) res = -EROFS; out_path_release: - path_release(&nd); + path_put(&nd.path); out: current->fsuid = old_fsuid; current->fsgid = old_fsgid; @@ -490,10 +490,10 @@ asmlinkage long sys_chdir(const char __user * filename) if (error) goto dput_and_out; - set_fs_pwd(current->fs, nd.mnt, nd.dentry); + set_fs_pwd(current->fs, &nd.path); dput_and_out: - path_release(&nd); + path_put(&nd.path); out: return error; } @@ -501,9 +501,7 @@ out: asmlinkage long sys_fchdir(unsigned int fd) { struct file *file; - struct dentry *dentry; struct inode *inode; - struct vfsmount *mnt; int error; error = -EBADF; @@ -511,9 +509,7 @@ asmlinkage long sys_fchdir(unsigned int fd) if (!file) goto out; - dentry = file->f_path.dentry; - mnt = file->f_path.mnt; - inode = dentry->d_inode; + inode = file->f_path.dentry->d_inode; error = -ENOTDIR; if (!S_ISDIR(inode->i_mode)) @@ -521,7 +517,7 @@ asmlinkage long sys_fchdir(unsigned int fd) error = file_permission(file, MAY_EXEC); if (!error) - set_fs_pwd(current->fs, mnt, dentry); + set_fs_pwd(current->fs, &file->f_path); out_putf: fput(file); out: @@ -545,11 +541,11 @@ asmlinkage long sys_chroot(const char __user * filename) if (!capable(CAP_SYS_CHROOT)) goto dput_and_out; - set_fs_root(current->fs, nd.mnt, nd.dentry); + set_fs_root(current->fs, &nd.path); set_fs_altroot(); error = 0; dput_and_out: - path_release(&nd); + path_put(&nd.path); out: return error; } @@ -602,7 +598,7 @@ asmlinkage long sys_fchmodat(int dfd, const char __user *filename, error = __user_walk_fd(dfd, filename, LOOKUP_FOLLOW, &nd); if (error) goto out; - inode = nd.dentry->d_inode; + inode = nd.path.dentry->d_inode; error = -EROFS; if (IS_RDONLY(inode)) @@ -617,11 +613,11 @@ asmlinkage long sys_fchmodat(int dfd, const char __user *filename, mode = inode->i_mode; newattrs.ia_mode = (mode & S_IALLUGO) | (inode->i_mode & ~S_IALLUGO); newattrs.ia_valid = ATTR_MODE | ATTR_CTIME; - error = notify_change(nd.dentry, &newattrs); + error = notify_change(nd.path.dentry, &newattrs); mutex_unlock(&inode->i_mutex); dput_and_out: - path_release(&nd); + path_put(&nd.path); out: return error; } @@ -675,8 +671,8 @@ asmlinkage long sys_chown(const char __user * filename, uid_t user, gid_t group) error = user_path_walk(filename, &nd); if (error) goto out; - error = chown_common(nd.dentry, user, group); - path_release(&nd); + error = chown_common(nd.path.dentry, user, group); + path_put(&nd.path); out: return error; } @@ -695,8 +691,8 @@ asmlinkage long sys_fchownat(int dfd, const char __user *filename, uid_t user, error = __user_walk_fd(dfd, filename, follow, &nd); if (error) goto out; - error = chown_common(nd.dentry, user, group); - path_release(&nd); + error = chown_common(nd.path.dentry, user, group); + path_put(&nd.path); out: return error; } @@ -709,8 +705,8 @@ asmlinkage long sys_lchown(const char __user * filename, uid_t user, gid_t group error = user_path_walk_link(filename, &nd); if (error) goto out; - error = chown_common(nd.dentry, user, group); - path_release(&nd); + error = chown_common(nd.path.dentry, user, group); + path_put(&nd.path); out: return error; } @@ -863,7 +859,7 @@ struct file *lookup_instantiate_filp(struct nameidata *nd, struct dentry *dentry goto out; if (IS_ERR(dentry)) goto out_err; - nd->intent.open.file = __dentry_open(dget(dentry), mntget(nd->mnt), + nd->intent.open.file = __dentry_open(dget(dentry), mntget(nd->path.mnt), nd->intent.open.flags - 1, nd->intent.open.file, open); @@ -891,9 +887,10 @@ struct file *nameidata_to_filp(struct nameidata *nd, int flags) filp = nd->intent.open.file; /* Has the filesystem initialised the file for us? */ if (filp->f_path.dentry == NULL) - filp = __dentry_open(nd->dentry, nd->mnt, flags, filp, NULL); + filp = __dentry_open(nd->path.dentry, nd->path.mnt, flags, filp, + NULL); else - path_release(nd); + path_put(&nd->path); return filp; } diff --git a/fs/pipe.c b/fs/pipe.c index a07e9a54206..3c185b6527b 100644 --- a/fs/pipe.c +++ b/fs/pipe.c @@ -171,7 +171,7 @@ static void anon_pipe_buf_release(struct pipe_inode_info *pipe, * * Description: * This function returns a kernel virtual address mapping for the - * passed in @pipe_buffer. If @atomic is set, an atomic map is provided + * pipe_buffer passed in @buf. If @atomic is set, an atomic map is provided * and the caller has to be careful not to fault before calling * the unmap function. * @@ -208,15 +208,15 @@ void generic_pipe_buf_unmap(struct pipe_inode_info *pipe, } /** - * generic_pipe_buf_steal - attempt to take ownership of a @pipe_buffer + * generic_pipe_buf_steal - attempt to take ownership of a &pipe_buffer * @pipe: the pipe that the buffer belongs to * @buf: the buffer to attempt to steal * * Description: - * This function attempts to steal the @struct page attached to + * This function attempts to steal the &struct page attached to * @buf. If successful, this function returns 0 and returns with * the page locked. The caller may then reuse the page for whatever - * he wishes, the typical use is insertion into a different file + * he wishes; the typical use is insertion into a different file * page cache. */ int generic_pipe_buf_steal(struct pipe_inode_info *pipe, @@ -238,7 +238,7 @@ int generic_pipe_buf_steal(struct pipe_inode_info *pipe, } /** - * generic_pipe_buf_get - get a reference to a @struct pipe_buffer + * generic_pipe_buf_get - get a reference to a &struct pipe_buffer * @pipe: the pipe that the buffer belongs to * @buf: the buffer to get a reference to * diff --git a/fs/proc/base.c b/fs/proc/base.c index 7c6b4ec83cb..88f8edf1825 100644 --- a/fs/proc/base.c +++ b/fs/proc/base.c @@ -153,7 +153,7 @@ static int get_nr_threads(struct task_struct *tsk) return count; } -static int proc_cwd_link(struct inode *inode, struct dentry **dentry, struct vfsmount **mnt) +static int proc_cwd_link(struct inode *inode, struct path *path) { struct task_struct *task = get_proc_task(inode); struct fs_struct *fs = NULL; @@ -165,8 +165,8 @@ static int proc_cwd_link(struct inode *inode, struct dentry **dentry, struct vfs } if (fs) { read_lock(&fs->lock); - *mnt = mntget(fs->pwdmnt); - *dentry = dget(fs->pwd); + *path = fs->pwd; + path_get(&fs->pwd); read_unlock(&fs->lock); result = 0; put_fs_struct(fs); @@ -174,7 +174,7 @@ static int proc_cwd_link(struct inode *inode, struct dentry **dentry, struct vfs return result; } -static int proc_root_link(struct inode *inode, struct dentry **dentry, struct vfsmount **mnt) +static int proc_root_link(struct inode *inode, struct path *path) { struct task_struct *task = get_proc_task(inode); struct fs_struct *fs = NULL; @@ -186,8 +186,8 @@ static int proc_root_link(struct inode *inode, struct dentry **dentry, struct vf } if (fs) { read_lock(&fs->lock); - *mnt = mntget(fs->rootmnt); - *dentry = dget(fs->root); + *path = fs->root; + path_get(&fs->root); read_unlock(&fs->lock); result = 0; put_fs_struct(fs); @@ -1164,39 +1164,36 @@ static void *proc_pid_follow_link(struct dentry *dentry, struct nameidata *nd) int error = -EACCES; /* We don't need a base pointer in the /proc filesystem */ - path_release(nd); + path_put(&nd->path); /* Are we allowed to snoop on the tasks file descriptors? */ if (!proc_fd_access_allowed(inode)) goto out; - error = PROC_I(inode)->op.proc_get_link(inode, &nd->dentry, &nd->mnt); + error = PROC_I(inode)->op.proc_get_link(inode, &nd->path); nd->last_type = LAST_BIND; out: return ERR_PTR(error); } -static int do_proc_readlink(struct dentry *dentry, struct vfsmount *mnt, - char __user *buffer, int buflen) +static int do_proc_readlink(struct path *path, char __user *buffer, int buflen) { - struct inode * inode; char *tmp = (char*)__get_free_page(GFP_TEMPORARY); - char *path; + char *pathname; int len; if (!tmp) return -ENOMEM; - inode = dentry->d_inode; - path = d_path(dentry, mnt, tmp, PAGE_SIZE); - len = PTR_ERR(path); - if (IS_ERR(path)) + pathname = d_path(path, tmp, PAGE_SIZE); + len = PTR_ERR(pathname); + if (IS_ERR(pathname)) goto out; - len = tmp + PAGE_SIZE - 1 - path; + len = tmp + PAGE_SIZE - 1 - pathname; if (len > buflen) len = buflen; - if (copy_to_user(buffer, path, len)) + if (copy_to_user(buffer, pathname, len)) len = -EFAULT; out: free_page((unsigned long)tmp); @@ -1207,20 +1204,18 @@ static int proc_pid_readlink(struct dentry * dentry, char __user * buffer, int b { int error = -EACCES; struct inode *inode = dentry->d_inode; - struct dentry *de; - struct vfsmount *mnt = NULL; + struct path path; /* Are we allowed to snoop on the tasks file descriptors? */ if (!proc_fd_access_allowed(inode)) goto out; - error = PROC_I(inode)->op.proc_get_link(inode, &de, &mnt); + error = PROC_I(inode)->op.proc_get_link(inode, &path); if (error) goto out; - error = do_proc_readlink(de, mnt, buffer, buflen); - dput(de); - mntput(mnt); + error = do_proc_readlink(&path, buffer, buflen); + path_put(&path); out: return error; } @@ -1447,8 +1442,7 @@ out: #define PROC_FDINFO_MAX 64 -static int proc_fd_info(struct inode *inode, struct dentry **dentry, - struct vfsmount **mnt, char *info) +static int proc_fd_info(struct inode *inode, struct path *path, char *info) { struct task_struct *task = get_proc_task(inode); struct files_struct *files = NULL; @@ -1467,10 +1461,10 @@ static int proc_fd_info(struct inode *inode, struct dentry **dentry, spin_lock(&files->file_lock); file = fcheck_files(files, fd); if (file) { - if (mnt) - *mnt = mntget(file->f_path.mnt); - if (dentry) - *dentry = dget(file->f_path.dentry); + if (path) { + *path = file->f_path; + path_get(&file->f_path); + } if (info) snprintf(info, PROC_FDINFO_MAX, "pos:\t%lli\n" @@ -1487,10 +1481,9 @@ static int proc_fd_info(struct inode *inode, struct dentry **dentry, return -ENOENT; } -static int proc_fd_link(struct inode *inode, struct dentry **dentry, - struct vfsmount **mnt) +static int proc_fd_link(struct inode *inode, struct path *path) { - return proc_fd_info(inode, dentry, mnt, NULL); + return proc_fd_info(inode, path, NULL); } static int tid_fd_revalidate(struct dentry *dentry, struct nameidata *nd) @@ -1684,7 +1677,7 @@ static ssize_t proc_fdinfo_read(struct file *file, char __user *buf, size_t len, loff_t *ppos) { char tmp[PROC_FDINFO_MAX]; - int err = proc_fd_info(file->f_path.dentry->d_inode, NULL, NULL, tmp); + int err = proc_fd_info(file->f_path.dentry->d_inode, NULL, tmp); if (!err) err = simple_read_from_buffer(buf, len, ppos, tmp, strlen(tmp)); return err; diff --git a/fs/proc/internal.h b/fs/proc/internal.h index ea496ffeabe..1c81c8f1aee 100644 --- a/fs/proc/internal.h +++ b/fs/proc/internal.h @@ -48,7 +48,7 @@ extern int maps_protect; extern void create_seq_entry(char *name, mode_t mode, const struct file_operations *f); -extern int proc_exe_link(struct inode *, struct dentry **, struct vfsmount **); +extern int proc_exe_link(struct inode *, struct path *); extern int proc_tid_stat(struct seq_file *m, struct pid_namespace *ns, struct pid *pid, struct task_struct *task); extern int proc_tgid_stat(struct seq_file *m, struct pid_namespace *ns, diff --git a/fs/proc/nommu.c b/fs/proc/nommu.c index 5d9147b9d73..941e95114b5 100644 --- a/fs/proc/nommu.c +++ b/fs/proc/nommu.c @@ -67,7 +67,7 @@ int nommu_vma_show(struct seq_file *m, struct vm_area_struct *vma) if (len < 1) len = 1; seq_printf(m, "%*c", len, ' '); - seq_path(m, file->f_path.mnt, file->f_path.dentry, ""); + seq_path(m, &file->f_path, ""); } seq_putc(m, '\n'); diff --git a/fs/proc/proc_sysctl.c b/fs/proc/proc_sysctl.c index b9cb23c08f6..614c34b6d1c 100644 --- a/fs/proc/proc_sysctl.c +++ b/fs/proc/proc_sysctl.c @@ -407,7 +407,7 @@ static int proc_sys_permission(struct inode *inode, int mask, struct nameidata * if (!nd || !depth) goto out; - dentry = nd->dentry; + dentry = nd->path.dentry; table = do_proc_sys_lookup(dentry->d_parent, &dentry->d_name, &head); /* If the entry does not exist deny permission */ diff --git a/fs/proc/task_mmu.c b/fs/proc/task_mmu.c index ae4d3f2c8cb..49958cffbd8 100644 --- a/fs/proc/task_mmu.c +++ b/fs/proc/task_mmu.c @@ -75,7 +75,7 @@ int task_statm(struct mm_struct *mm, int *shared, int *text, return mm->total_vm; } -int proc_exe_link(struct inode *inode, struct dentry **dentry, struct vfsmount **mnt) +int proc_exe_link(struct inode *inode, struct path *path) { struct vm_area_struct * vma; int result = -ENOENT; @@ -98,8 +98,8 @@ int proc_exe_link(struct inode *inode, struct dentry **dentry, struct vfsmount * } if (vma) { - *mnt = mntget(vma->vm_file->f_path.mnt); - *dentry = dget(vma->vm_file->f_path.dentry); + *path = vma->vm_file->f_path; + path_get(&vma->vm_file->f_path); result = 0; } @@ -271,7 +271,7 @@ static int show_map(struct seq_file *m, void *v) */ if (file) { pad_len_spaces(m, len); - seq_path(m, file->f_path.mnt, file->f_path.dentry, "\n"); + seq_path(m, &file->f_path, "\n"); } else { const char *name = arch_vma_name(vma); if (!name) { diff --git a/fs/proc/task_nommu.c b/fs/proc/task_nommu.c index abfc6f5e56c..8011528518b 100644 --- a/fs/proc/task_nommu.c +++ b/fs/proc/task_nommu.c @@ -103,7 +103,7 @@ int task_statm(struct mm_struct *mm, int *shared, int *text, return size; } -int proc_exe_link(struct inode *inode, struct dentry **dentry, struct vfsmount **mnt) +int proc_exe_link(struct inode *inode, struct path *path) { struct vm_list_struct *vml; struct vm_area_struct *vma; @@ -126,8 +126,8 @@ int proc_exe_link(struct inode *inode, struct dentry **dentry, struct vfsmount * } if (vma) { - *mnt = mntget(vma->vm_file->f_path.mnt); - *dentry = dget(vma->vm_file->f_path.dentry); + *path = vma->vm_file->f_path; + path_get(&vma->vm_file->f_path); result = 0; } diff --git a/fs/reiserfs/super.c b/fs/reiserfs/super.c index 6033f0c3bd0..6841452e0de 100644 --- a/fs/reiserfs/super.c +++ b/fs/reiserfs/super.c @@ -2026,29 +2026,29 @@ static int reiserfs_quota_on(struct super_block *sb, int type, int format_id, if (err) return err; /* Quotafile not on the same filesystem? */ - if (nd.mnt->mnt_sb != sb) { - path_release(&nd); + if (nd.path.mnt->mnt_sb != sb) { + path_put(&nd.path); return -EXDEV; } /* We must not pack tails for quota files on reiserfs for quota IO to work */ - if (!REISERFS_I(nd.dentry->d_inode)->i_flags & i_nopack_mask) { + if (!REISERFS_I(nd.path.dentry->d_inode)->i_flags & i_nopack_mask) { reiserfs_warning(sb, "reiserfs: Quota file must have tail packing disabled."); - path_release(&nd); + path_put(&nd.path); return -EINVAL; } /* Not journalling quota? No more tests needed... */ if (!REISERFS_SB(sb)->s_qf_names[USRQUOTA] && !REISERFS_SB(sb)->s_qf_names[GRPQUOTA]) { - path_release(&nd); + path_put(&nd.path); return vfs_quota_on(sb, type, format_id, path); } /* Quotafile not of fs root? */ - if (nd.dentry->d_parent->d_inode != sb->s_root->d_inode) + if (nd.path.dentry->d_parent->d_inode != sb->s_root->d_inode) reiserfs_warning(sb, "reiserfs: Quota file not on filesystem root. " "Journalled quota will not work."); - path_release(&nd); + path_put(&nd.path); return vfs_quota_on(sb, type, format_id, path); } diff --git a/fs/seq_file.c b/fs/seq_file.c index ca71c115bda..853770274f2 100644 --- a/fs/seq_file.c +++ b/fs/seq_file.c @@ -342,13 +342,11 @@ int seq_printf(struct seq_file *m, const char *f, ...) } EXPORT_SYMBOL(seq_printf); -int seq_path(struct seq_file *m, - struct vfsmount *mnt, struct dentry *dentry, - char *esc) +int seq_path(struct seq_file *m, struct path *path, char *esc) { if (m->count < m->size) { char *s = m->buf + m->count; - char *p = d_path(dentry, mnt, s, m->size - m->count); + char *p = d_path(path, s, m->size - m->count); if (!IS_ERR(p)) { while (s <= p) { char c = *p++; diff --git a/fs/smbfs/inode.c b/fs/smbfs/inode.c index 4e5c22ca802..376ef3ee6ed 100644 --- a/fs/smbfs/inode.c +++ b/fs/smbfs/inode.c @@ -505,7 +505,7 @@ static int smb_fill_super(struct super_block *sb, void *raw_data, int silent) if (warn_count < 5) { warn_count++; printk(KERN_EMERG "smbfs is deprecated and will be removed" - "from the 2.6.27 kernel. Please migrate to cifs\n"); + " from the 2.6.27 kernel. Please migrate to cifs\n"); } if (!raw_data) diff --git a/fs/stat.c b/fs/stat.c index 68510068a64..9cf41f719d5 100644 --- a/fs/stat.c +++ b/fs/stat.c @@ -62,8 +62,8 @@ int vfs_stat_fd(int dfd, char __user *name, struct kstat *stat) error = __user_walk_fd(dfd, name, LOOKUP_FOLLOW, &nd); if (!error) { - error = vfs_getattr(nd.mnt, nd.dentry, stat); - path_release(&nd); + error = vfs_getattr(nd.path.mnt, nd.path.dentry, stat); + path_put(&nd.path); } return error; } @@ -82,8 +82,8 @@ int vfs_lstat_fd(int dfd, char __user *name, struct kstat *stat) error = __user_walk_fd(dfd, name, 0, &nd); if (!error) { - error = vfs_getattr(nd.mnt, nd.dentry, stat); - path_release(&nd); + error = vfs_getattr(nd.path.mnt, nd.path.dentry, stat); + path_put(&nd.path); } return error; } @@ -302,17 +302,18 @@ asmlinkage long sys_readlinkat(int dfd, const char __user *path, error = __user_walk_fd(dfd, path, 0, &nd); if (!error) { - struct inode * inode = nd.dentry->d_inode; + struct inode *inode = nd.path.dentry->d_inode; error = -EINVAL; if (inode->i_op && inode->i_op->readlink) { - error = security_inode_readlink(nd.dentry); + error = security_inode_readlink(nd.path.dentry); if (!error) { - touch_atime(nd.mnt, nd.dentry); - error = inode->i_op->readlink(nd.dentry, buf, bufsiz); + touch_atime(nd.path.mnt, nd.path.dentry); + error = inode->i_op->readlink(nd.path.dentry, + buf, bufsiz); } } - path_release(&nd); + path_put(&nd.path); } return error; } diff --git a/fs/udf/balloc.c b/fs/udf/balloc.c index d721a1af197..f855dcbbdfb 100644 --- a/fs/udf/balloc.c +++ b/fs/udf/balloc.c @@ -145,7 +145,7 @@ static bool udf_add_free_space(struct udf_sb_info *sbi, { struct logicalVolIntegrityDesc *lvid; - if (sbi->s_lvid_bh) + if (sbi->s_lvid_bh == NULL) return false; lvid = (struct logicalVolIntegrityDesc *)sbi->s_lvid_bh->b_data; diff --git a/fs/udf/dir.c b/fs/udf/dir.c index 4b44e23caa1..8d8643ada19 100644 --- a/fs/udf/dir.c +++ b/fs/udf/dir.c @@ -43,13 +43,13 @@ static int do_udf_readdir(struct inode *dir, struct file *filp, struct fileIdentDesc *fi = NULL; struct fileIdentDesc cfi; int block, iblock; - loff_t nf_pos = filp->f_pos - 1; + loff_t nf_pos = (filp->f_pos - 1) << 2; int flen; char fname[UDF_NAME_LEN]; char *nameptr; uint16_t liu; uint8_t lfi; - loff_t size = (udf_ext0_offset(dir) + dir->i_size) >> 2; + loff_t size = udf_ext0_offset(dir) + dir->i_size; struct buffer_head *tmp, *bha[16]; kernel_lb_addr eloc; uint32_t elen; @@ -63,13 +63,13 @@ static int do_udf_readdir(struct inode *dir, struct file *filp, return 0; if (nf_pos == 0) - nf_pos = (udf_ext0_offset(dir) >> 2); + nf_pos = udf_ext0_offset(dir); - fibh.soffset = fibh.eoffset = (nf_pos & ((dir->i_sb->s_blocksize - 1) >> 2)) << 2; + fibh.soffset = fibh.eoffset = nf_pos & (dir->i_sb->s_blocksize - 1); iinfo = UDF_I(dir); if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB) { fibh.sbh = fibh.ebh = NULL; - } else if (inode_bmap(dir, nf_pos >> (dir->i_sb->s_blocksize_bits - 2), + } else if (inode_bmap(dir, nf_pos >> dir->i_sb->s_blocksize_bits, &epos, &eloc, &elen, &offset) == (EXT_RECORDED_ALLOCATED >> 30)) { block = udf_get_lb_pblock(dir->i_sb, eloc, offset); if ((++offset << dir->i_sb->s_blocksize_bits) < elen) { @@ -111,7 +111,7 @@ static int do_udf_readdir(struct inode *dir, struct file *filp, } while (nf_pos < size) { - filp->f_pos = nf_pos + 1; + filp->f_pos = (nf_pos >> 2) + 1; fi = udf_fileident_read(dir, &nf_pos, &fibh, &cfi, &epos, &eloc, &elen, &offset); @@ -178,7 +178,7 @@ static int do_udf_readdir(struct inode *dir, struct file *filp, } } /* end while */ - filp->f_pos = nf_pos + 1; + filp->f_pos = (nf_pos >> 2) + 1; if (fibh.sbh != fibh.ebh) brelse(fibh.ebh); diff --git a/fs/utimes.c b/fs/utimes.c index e5588cd8530..b18da9c0b97 100644 --- a/fs/utimes.c +++ b/fs/utimes.c @@ -84,7 +84,7 @@ long do_utimes(int dfd, char __user *filename, struct timespec *times, int flags if (error) goto out; - dentry = nd.dentry; + dentry = nd.path.dentry; } inode = dentry->d_inode; @@ -138,7 +138,7 @@ dput_and_out: if (f) fput(f); else - path_release(&nd); + path_put(&nd.path); out: return error; } diff --git a/fs/xattr.c b/fs/xattr.c index f7c8f87bb39..3acab161546 100644 --- a/fs/xattr.c +++ b/fs/xattr.c @@ -262,8 +262,8 @@ sys_setxattr(char __user *path, char __user *name, void __user *value, error = user_path_walk(path, &nd); if (error) return error; - error = setxattr(nd.dentry, name, value, size, flags); - path_release(&nd); + error = setxattr(nd.path.dentry, name, value, size, flags); + path_put(&nd.path); return error; } @@ -277,8 +277,8 @@ sys_lsetxattr(char __user *path, char __user *name, void __user *value, error = user_path_walk_link(path, &nd); if (error) return error; - error = setxattr(nd.dentry, name, value, size, flags); - path_release(&nd); + error = setxattr(nd.path.dentry, name, value, size, flags); + path_put(&nd.path); return error; } @@ -347,8 +347,8 @@ sys_getxattr(char __user *path, char __user *name, void __user *value, error = user_path_walk(path, &nd); if (error) return error; - error = getxattr(nd.dentry, name, value, size); - path_release(&nd); + error = getxattr(nd.path.dentry, name, value, size); + path_put(&nd.path); return error; } @@ -362,8 +362,8 @@ sys_lgetxattr(char __user *path, char __user *name, void __user *value, error = user_path_walk_link(path, &nd); if (error) return error; - error = getxattr(nd.dentry, name, value, size); - path_release(&nd); + error = getxattr(nd.path.dentry, name, value, size); + path_put(&nd.path); return error; } @@ -421,8 +421,8 @@ sys_listxattr(char __user *path, char __user *list, size_t size) error = user_path_walk(path, &nd); if (error) return error; - error = listxattr(nd.dentry, list, size); - path_release(&nd); + error = listxattr(nd.path.dentry, list, size); + path_put(&nd.path); return error; } @@ -435,8 +435,8 @@ sys_llistxattr(char __user *path, char __user *list, size_t size) error = user_path_walk_link(path, &nd); if (error) return error; - error = listxattr(nd.dentry, list, size); - path_release(&nd); + error = listxattr(nd.path.dentry, list, size); + path_put(&nd.path); return error; } @@ -482,8 +482,8 @@ sys_removexattr(char __user *path, char __user *name) error = user_path_walk(path, &nd); if (error) return error; - error = removexattr(nd.dentry, name); - path_release(&nd); + error = removexattr(nd.path.dentry, name); + path_put(&nd.path); return error; } @@ -496,8 +496,8 @@ sys_lremovexattr(char __user *path, char __user *name) error = user_path_walk_link(path, &nd); if (error) return error; - error = removexattr(nd.dentry, name); - path_release(&nd); + error = removexattr(nd.path.dentry, name); + path_put(&nd.path); return error; } diff --git a/fs/xfs/Kbuild b/fs/xfs/Kbuild deleted file mode 100644 index 2566e96706f..00000000000 --- a/fs/xfs/Kbuild +++ /dev/null @@ -1,6 +0,0 @@ -# -# The xfs people like to share Makefile with 2.6 and 2.4. -# Utilise file named Kbuild file which has precedence over Makefile. -# - -include $(srctree)/$(obj)/Makefile-linux-2.6 diff --git a/fs/xfs/Makefile b/fs/xfs/Makefile index 49e3e7e5e3d..36ec614e699 100644 --- a/fs/xfs/Makefile +++ b/fs/xfs/Makefile @@ -1 +1,117 @@ -include $(TOPDIR)/fs/xfs/Makefile-linux-$(VERSION).$(PATCHLEVEL) +# +# Copyright (c) 2000-2005 Silicon Graphics, Inc. +# All Rights Reserved. +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it would 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 the Free Software Foundation, +# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +# + +EXTRA_CFLAGS += -I$(src) -I$(src)/linux-2.6 -funsigned-char + +XFS_LINUX := linux-2.6 + +ifeq ($(CONFIG_XFS_DEBUG),y) + EXTRA_CFLAGS += -g +endif + +obj-$(CONFIG_XFS_FS) += xfs.o + +xfs-$(CONFIG_XFS_QUOTA) += $(addprefix quota/, \ + xfs_dquot.o \ + xfs_dquot_item.o \ + xfs_trans_dquot.o \ + xfs_qm_syscalls.o \ + xfs_qm_bhv.o \ + xfs_qm.o) + +ifeq ($(CONFIG_XFS_QUOTA),y) +xfs-$(CONFIG_PROC_FS) += quota/xfs_qm_stats.o +endif + +xfs-$(CONFIG_XFS_RT) += xfs_rtalloc.o +xfs-$(CONFIG_XFS_POSIX_ACL) += xfs_acl.o +xfs-$(CONFIG_PROC_FS) += $(XFS_LINUX)/xfs_stats.o +xfs-$(CONFIG_SYSCTL) += $(XFS_LINUX)/xfs_sysctl.o +xfs-$(CONFIG_COMPAT) += $(XFS_LINUX)/xfs_ioctl32.o + + +xfs-y += xfs_alloc.o \ + xfs_alloc_btree.o \ + xfs_attr.o \ + xfs_attr_leaf.o \ + xfs_bit.o \ + xfs_bmap.o \ + xfs_bmap_btree.o \ + xfs_btree.o \ + xfs_buf_item.o \ + xfs_da_btree.o \ + xfs_dir2.o \ + xfs_dir2_block.o \ + xfs_dir2_data.o \ + xfs_dir2_leaf.o \ + xfs_dir2_node.o \ + xfs_dir2_sf.o \ + xfs_error.o \ + xfs_extfree_item.o \ + xfs_filestream.o \ + xfs_fsops.o \ + xfs_ialloc.o \ + xfs_ialloc_btree.o \ + xfs_iget.o \ + xfs_inode.o \ + xfs_inode_item.o \ + xfs_iomap.o \ + xfs_itable.o \ + xfs_dfrag.o \ + xfs_log.o \ + xfs_log_recover.o \ + xfs_mount.o \ + xfs_mru_cache.o \ + xfs_rename.o \ + xfs_trans.o \ + xfs_trans_ail.o \ + xfs_trans_buf.o \ + xfs_trans_extfree.o \ + xfs_trans_inode.o \ + xfs_trans_item.o \ + xfs_utils.o \ + xfs_vfsops.o \ + xfs_vnodeops.o \ + xfs_rw.o \ + xfs_dmops.o \ + xfs_qmops.o + +xfs-$(CONFIG_XFS_TRACE) += xfs_dir2_trace.o + +# Objects in linux/ +xfs-y += $(addprefix $(XFS_LINUX)/, \ + kmem.o \ + xfs_aops.o \ + xfs_buf.o \ + xfs_export.o \ + xfs_file.o \ + xfs_fs_subr.o \ + xfs_globals.o \ + xfs_ioctl.o \ + xfs_iops.o \ + xfs_lrw.o \ + xfs_super.o \ + xfs_vnode.o) + +# Objects in support/ +xfs-y += $(addprefix support/, \ + debug.o \ + uuid.o) + +xfs-$(CONFIG_XFS_TRACE) += support/ktrace.o + diff --git a/fs/xfs/Makefile-linux-2.6 b/fs/xfs/Makefile-linux-2.6 index 97316451fc6..e69de29bb2d 100644 --- a/fs/xfs/Makefile-linux-2.6 +++ b/fs/xfs/Makefile-linux-2.6 @@ -1,117 +0,0 @@ -# -# Copyright (c) 2000-2005 Silicon Graphics, Inc. -# All Rights Reserved. -# -# This program is free software; you can redistribute it and/or -# modify it under the terms of the GNU General Public License as -# published by the Free Software Foundation. -# -# This program is distributed in the hope that it would 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 the Free Software Foundation, -# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -# - -EXTRA_CFLAGS += -Ifs/xfs -Ifs/xfs/linux-2.6 -funsigned-char - -XFS_LINUX := linux-2.6 - -ifeq ($(CONFIG_XFS_DEBUG),y) - EXTRA_CFLAGS += -g -endif - -obj-$(CONFIG_XFS_FS) += xfs.o - -xfs-$(CONFIG_XFS_QUOTA) += $(addprefix quota/, \ - xfs_dquot.o \ - xfs_dquot_item.o \ - xfs_trans_dquot.o \ - xfs_qm_syscalls.o \ - xfs_qm_bhv.o \ - xfs_qm.o) - -ifeq ($(CONFIG_XFS_QUOTA),y) -xfs-$(CONFIG_PROC_FS) += quota/xfs_qm_stats.o -endif - -xfs-$(CONFIG_XFS_RT) += xfs_rtalloc.o -xfs-$(CONFIG_XFS_POSIX_ACL) += xfs_acl.o -xfs-$(CONFIG_PROC_FS) += $(XFS_LINUX)/xfs_stats.o -xfs-$(CONFIG_SYSCTL) += $(XFS_LINUX)/xfs_sysctl.o -xfs-$(CONFIG_COMPAT) += $(XFS_LINUX)/xfs_ioctl32.o - - -xfs-y += xfs_alloc.o \ - xfs_alloc_btree.o \ - xfs_attr.o \ - xfs_attr_leaf.o \ - xfs_bit.o \ - xfs_bmap.o \ - xfs_bmap_btree.o \ - xfs_btree.o \ - xfs_buf_item.o \ - xfs_da_btree.o \ - xfs_dir2.o \ - xfs_dir2_block.o \ - xfs_dir2_data.o \ - xfs_dir2_leaf.o \ - xfs_dir2_node.o \ - xfs_dir2_sf.o \ - xfs_error.o \ - xfs_extfree_item.o \ - xfs_filestream.o \ - xfs_fsops.o \ - xfs_ialloc.o \ - xfs_ialloc_btree.o \ - xfs_iget.o \ - xfs_inode.o \ - xfs_inode_item.o \ - xfs_iomap.o \ - xfs_itable.o \ - xfs_dfrag.o \ - xfs_log.o \ - xfs_log_recover.o \ - xfs_mount.o \ - xfs_mru_cache.o \ - xfs_rename.o \ - xfs_trans.o \ - xfs_trans_ail.o \ - xfs_trans_buf.o \ - xfs_trans_extfree.o \ - xfs_trans_inode.o \ - xfs_trans_item.o \ - xfs_utils.o \ - xfs_vfsops.o \ - xfs_vnodeops.o \ - xfs_rw.o \ - xfs_dmops.o \ - xfs_qmops.o - -xfs-$(CONFIG_XFS_TRACE) += xfs_dir2_trace.o - -# Objects in linux/ -xfs-y += $(addprefix $(XFS_LINUX)/, \ - kmem.o \ - xfs_aops.o \ - xfs_buf.o \ - xfs_export.o \ - xfs_file.o \ - xfs_fs_subr.o \ - xfs_globals.o \ - xfs_ioctl.o \ - xfs_iops.o \ - xfs_lrw.o \ - xfs_super.o \ - xfs_vnode.o) - -# Objects in support/ -xfs-y += $(addprefix support/, \ - debug.o \ - uuid.o) - -xfs-$(CONFIG_XFS_TRACE) += support/ktrace.o - diff --git a/fs/xfs/linux-2.6/xfs_ioctl.c b/fs/xfs/linux-2.6/xfs_ioctl.c index 4c82a050a3a..a9952e490ac 100644 --- a/fs/xfs/linux-2.6/xfs_ioctl.c +++ b/fs/xfs/linux-2.6/xfs_ioctl.c @@ -91,10 +91,10 @@ xfs_find_handle( if (error) return error; - ASSERT(nd.dentry); - ASSERT(nd.dentry->d_inode); - inode = igrab(nd.dentry->d_inode); - path_release(&nd); + ASSERT(nd.path.dentry); + ASSERT(nd.path.dentry->d_inode); + inode = igrab(nd.path.dentry->d_inode); + path_put(&nd.path); break; } diff --git a/fs/xfs/quota/xfs_qm.c b/fs/xfs/quota/xfs_qm.c index 35582fe9d64..1f3da5b8657 100644 --- a/fs/xfs/quota/xfs_qm.c +++ b/fs/xfs/quota/xfs_qm.c @@ -1648,14 +1648,14 @@ xfs_qm_quotacheck_dqadjust( * Adjust the inode count and the block count to reflect this inode's * resource usage. */ - be64_add(&dqp->q_core.d_icount, 1); + be64_add_cpu(&dqp->q_core.d_icount, 1); dqp->q_res_icount++; if (nblks) { - be64_add(&dqp->q_core.d_bcount, nblks); + be64_add_cpu(&dqp->q_core.d_bcount, nblks); dqp->q_res_bcount += nblks; } if (rtblks) { - be64_add(&dqp->q_core.d_rtbcount, rtblks); + be64_add_cpu(&dqp->q_core.d_rtbcount, rtblks); dqp->q_res_rtbcount += rtblks; } diff --git a/fs/xfs/quota/xfs_trans_dquot.c b/fs/xfs/quota/xfs_trans_dquot.c index 7de6874bf1b..f441f836ca8 100644 --- a/fs/xfs/quota/xfs_trans_dquot.c +++ b/fs/xfs/quota/xfs_trans_dquot.c @@ -421,13 +421,13 @@ xfs_trans_apply_dquot_deltas( (xfs_qcnt_t) -qtrx->qt_icount_delta); #endif if (totalbdelta) - be64_add(&d->d_bcount, (xfs_qcnt_t)totalbdelta); + be64_add_cpu(&d->d_bcount, (xfs_qcnt_t)totalbdelta); if (qtrx->qt_icount_delta) - be64_add(&d->d_icount, (xfs_qcnt_t)qtrx->qt_icount_delta); + be64_add_cpu(&d->d_icount, (xfs_qcnt_t)qtrx->qt_icount_delta); if (totalrtbdelta) - be64_add(&d->d_rtbcount, (xfs_qcnt_t)totalrtbdelta); + be64_add_cpu(&d->d_rtbcount, (xfs_qcnt_t)totalrtbdelta); /* * Get any default limits in use. diff --git a/fs/xfs/xfs_alloc.c b/fs/xfs/xfs_alloc.c index ea6aa60ace0..bdbfbbee495 100644 --- a/fs/xfs/xfs_alloc.c +++ b/fs/xfs/xfs_alloc.c @@ -592,7 +592,7 @@ xfs_alloc_ag_vextent( if (!(args->wasfromfl)) { agf = XFS_BUF_TO_AGF(args->agbp); - be32_add(&agf->agf_freeblks, -(args->len)); + be32_add_cpu(&agf->agf_freeblks, -(args->len)); xfs_trans_agblocks_delta(args->tp, -((long)(args->len))); args->pag->pagf_freeblks -= args->len; @@ -1720,7 +1720,7 @@ xfs_free_ag_extent( agf = XFS_BUF_TO_AGF(agbp); pag = &mp->m_perag[agno]; - be32_add(&agf->agf_freeblks, len); + be32_add_cpu(&agf->agf_freeblks, len); xfs_trans_agblocks_delta(tp, len); pag->pagf_freeblks += len; XFS_WANT_CORRUPTED_GOTO( @@ -2008,18 +2008,18 @@ xfs_alloc_get_freelist( * Get the block number and update the data structures. */ bno = be32_to_cpu(agfl->agfl_bno[be32_to_cpu(agf->agf_flfirst)]); - be32_add(&agf->agf_flfirst, 1); + be32_add_cpu(&agf->agf_flfirst, 1); xfs_trans_brelse(tp, agflbp); if (be32_to_cpu(agf->agf_flfirst) == XFS_AGFL_SIZE(mp)) agf->agf_flfirst = 0; pag = &mp->m_perag[be32_to_cpu(agf->agf_seqno)]; - be32_add(&agf->agf_flcount, -1); + be32_add_cpu(&agf->agf_flcount, -1); xfs_trans_agflist_delta(tp, -1); pag->pagf_flcount--; logflags = XFS_AGF_FLFIRST | XFS_AGF_FLCOUNT; if (btreeblk) { - be32_add(&agf->agf_btreeblks, 1); + be32_add_cpu(&agf->agf_btreeblks, 1); pag->pagf_btreeblks++; logflags |= XFS_AGF_BTREEBLKS; } @@ -2117,17 +2117,17 @@ xfs_alloc_put_freelist( be32_to_cpu(agf->agf_seqno), &agflbp))) return error; agfl = XFS_BUF_TO_AGFL(agflbp); - be32_add(&agf->agf_fllast, 1); + be32_add_cpu(&agf->agf_fllast, 1); if (be32_to_cpu(agf->agf_fllast) == XFS_AGFL_SIZE(mp)) agf->agf_fllast = 0; pag = &mp->m_perag[be32_to_cpu(agf->agf_seqno)]; - be32_add(&agf->agf_flcount, 1); + be32_add_cpu(&agf->agf_flcount, 1); xfs_trans_agflist_delta(tp, 1); pag->pagf_flcount++; logflags = XFS_AGF_FLLAST | XFS_AGF_FLCOUNT; if (btreeblk) { - be32_add(&agf->agf_btreeblks, -1); + be32_add_cpu(&agf->agf_btreeblks, -1); pag->pagf_btreeblks--; logflags |= XFS_AGF_BTREEBLKS; } diff --git a/fs/xfs/xfs_alloc_btree.c b/fs/xfs/xfs_alloc_btree.c index 1603ce59585..3ce2645508a 100644 --- a/fs/xfs/xfs_alloc_btree.c +++ b/fs/xfs/xfs_alloc_btree.c @@ -221,7 +221,7 @@ xfs_alloc_delrec( */ bno = be32_to_cpu(agf->agf_roots[cur->bc_btnum]); agf->agf_roots[cur->bc_btnum] = *lpp; - be32_add(&agf->agf_levels[cur->bc_btnum], -1); + be32_add_cpu(&agf->agf_levels[cur->bc_btnum], -1); mp->m_perag[be32_to_cpu(agf->agf_seqno)].pagf_levels[cur->bc_btnum]--; /* * Put this buffer/block on the ag's freelist. @@ -1256,9 +1256,9 @@ xfs_alloc_lshift( /* * Bump and log left's numrecs, decrement and log right's numrecs. */ - be16_add(&left->bb_numrecs, 1); + be16_add_cpu(&left->bb_numrecs, 1); xfs_alloc_log_block(cur->bc_tp, lbp, XFS_BB_NUMRECS); - be16_add(&right->bb_numrecs, -1); + be16_add_cpu(&right->bb_numrecs, -1); xfs_alloc_log_block(cur->bc_tp, rbp, XFS_BB_NUMRECS); /* * Slide the contents of right down one entry. @@ -1346,7 +1346,7 @@ xfs_alloc_newroot( agf = XFS_BUF_TO_AGF(cur->bc_private.a.agbp); agf->agf_roots[cur->bc_btnum] = cpu_to_be32(nbno); - be32_add(&agf->agf_levels[cur->bc_btnum], 1); + be32_add_cpu(&agf->agf_levels[cur->bc_btnum], 1); seqno = be32_to_cpu(agf->agf_seqno); mp->m_perag[seqno].pagf_levels[cur->bc_btnum]++; xfs_alloc_log_agf(cur->bc_tp, cur->bc_private.a.agbp, @@ -1558,9 +1558,9 @@ xfs_alloc_rshift( /* * Decrement and log left's numrecs, bump and log right's numrecs. */ - be16_add(&left->bb_numrecs, -1); + be16_add_cpu(&left->bb_numrecs, -1); xfs_alloc_log_block(cur->bc_tp, lbp, XFS_BB_NUMRECS); - be16_add(&right->bb_numrecs, 1); + be16_add_cpu(&right->bb_numrecs, 1); xfs_alloc_log_block(cur->bc_tp, rbp, XFS_BB_NUMRECS); /* * Using a temporary cursor, update the parent key values of the @@ -1643,7 +1643,7 @@ xfs_alloc_split( */ if ((be16_to_cpu(left->bb_numrecs) & 1) && cur->bc_ptrs[level] <= be16_to_cpu(right->bb_numrecs) + 1) - be16_add(&right->bb_numrecs, 1); + be16_add_cpu(&right->bb_numrecs, 1); i = be16_to_cpu(left->bb_numrecs) - be16_to_cpu(right->bb_numrecs) + 1; /* * For non-leaf blocks, copy keys and addresses over to the new block. @@ -1689,7 +1689,7 @@ xfs_alloc_split( * Adjust numrecs, sibling pointers. */ lbno = XFS_DADDR_TO_AGBNO(cur->bc_mp, XFS_BUF_ADDR(lbp)); - be16_add(&left->bb_numrecs, -(be16_to_cpu(right->bb_numrecs))); + be16_add_cpu(&left->bb_numrecs, -(be16_to_cpu(right->bb_numrecs))); right->bb_rightsib = left->bb_rightsib; left->bb_rightsib = cpu_to_be32(rbno); right->bb_leftsib = cpu_to_be32(lbno); diff --git a/fs/xfs/xfs_arch.h b/fs/xfs/xfs_arch.h index c4836890b72..f9472a2076d 100644 --- a/fs/xfs/xfs_arch.h +++ b/fs/xfs/xfs_arch.h @@ -170,21 +170,6 @@ } \ } -static inline void be16_add(__be16 *a, __s16 b) -{ - *a = cpu_to_be16(be16_to_cpu(*a) + b); -} - -static inline void be32_add(__be32 *a, __s32 b) -{ - *a = cpu_to_be32(be32_to_cpu(*a) + b); -} - -static inline void be64_add(__be64 *a, __s64 b) -{ - *a = cpu_to_be64(be64_to_cpu(*a) + b); -} - /* * In directories inode numbers are stored as unaligned arrays of unsigned * 8bit integers on disk. diff --git a/fs/xfs/xfs_attr_leaf.c b/fs/xfs/xfs_attr_leaf.c index eb3815ebb7a..b08e2a2a8ad 100644 --- a/fs/xfs/xfs_attr_leaf.c +++ b/fs/xfs/xfs_attr_leaf.c @@ -317,7 +317,7 @@ xfs_attr_shortform_add(xfs_da_args_t *args, int forkoff) memcpy(sfe->nameval, args->name, args->namelen); memcpy(&sfe->nameval[args->namelen], args->value, args->valuelen); sf->hdr.count++; - be16_add(&sf->hdr.totsize, size); + be16_add_cpu(&sf->hdr.totsize, size); xfs_trans_log_inode(args->trans, dp, XFS_ILOG_CORE | XFS_ILOG_ADATA); xfs_sbversion_add_attr2(mp, args->trans); @@ -363,7 +363,7 @@ xfs_attr_shortform_remove(xfs_da_args_t *args) if (end != totsize) memmove(&((char *)sf)[base], &((char *)sf)[end], totsize - end); sf->hdr.count--; - be16_add(&sf->hdr.totsize, -size); + be16_add_cpu(&sf->hdr.totsize, -size); /* * Fix up the start offset of the attribute fork @@ -1133,7 +1133,7 @@ xfs_attr_leaf_add_work(xfs_dabuf_t *bp, xfs_da_args_t *args, int mapindex) xfs_da_log_buf(args->trans, bp, XFS_DA_LOGRANGE(leaf, entry, tmp + sizeof(*entry))); } - be16_add(&hdr->count, 1); + be16_add_cpu(&hdr->count, 1); /* * Allocate space for the new string (at the end of the run). @@ -1147,7 +1147,7 @@ xfs_attr_leaf_add_work(xfs_dabuf_t *bp, xfs_da_args_t *args, int mapindex) mp->m_sb.sb_blocksize, NULL)); ASSERT(be16_to_cpu(map->size) < XFS_LBSIZE(mp)); ASSERT((be16_to_cpu(map->size) & 0x3) == 0); - be16_add(&map->size, + be16_add_cpu(&map->size, -xfs_attr_leaf_newentsize(args->namelen, args->valuelen, mp->m_sb.sb_blocksize, &tmp)); entry->nameidx = cpu_to_be16(be16_to_cpu(map->base) + @@ -1214,12 +1214,12 @@ xfs_attr_leaf_add_work(xfs_dabuf_t *bp, xfs_da_args_t *args, int mapindex) map = &hdr->freemap[0]; for (i = 0; i < XFS_ATTR_LEAF_MAPSIZE; map++, i++) { if (be16_to_cpu(map->base) == tmp) { - be16_add(&map->base, sizeof(xfs_attr_leaf_entry_t)); - be16_add(&map->size, + be16_add_cpu(&map->base, sizeof(xfs_attr_leaf_entry_t)); + be16_add_cpu(&map->size, -((int)sizeof(xfs_attr_leaf_entry_t))); } } - be16_add(&hdr->usedbytes, xfs_attr_leaf_entsize(leaf, args->index)); + be16_add_cpu(&hdr->usedbytes, xfs_attr_leaf_entsize(leaf, args->index)); xfs_da_log_buf(args->trans, bp, XFS_DA_LOGRANGE(leaf, hdr, sizeof(*hdr))); return(0); @@ -1727,9 +1727,9 @@ xfs_attr_leaf_remove(xfs_dabuf_t *bp, xfs_da_args_t *args) ASSERT(be16_to_cpu(map->base) < XFS_LBSIZE(mp)); ASSERT(be16_to_cpu(map->size) < XFS_LBSIZE(mp)); if (be16_to_cpu(map->base) == tablesize) { - be16_add(&map->base, + be16_add_cpu(&map->base, -((int)sizeof(xfs_attr_leaf_entry_t))); - be16_add(&map->size, sizeof(xfs_attr_leaf_entry_t)); + be16_add_cpu(&map->size, sizeof(xfs_attr_leaf_entry_t)); } if ((be16_to_cpu(map->base) + be16_to_cpu(map->size)) @@ -1751,19 +1751,19 @@ xfs_attr_leaf_remove(xfs_dabuf_t *bp, xfs_da_args_t *args) if ((before >= 0) || (after >= 0)) { if ((before >= 0) && (after >= 0)) { map = &hdr->freemap[before]; - be16_add(&map->size, entsize); - be16_add(&map->size, + be16_add_cpu(&map->size, entsize); + be16_add_cpu(&map->size, be16_to_cpu(hdr->freemap[after].size)); hdr->freemap[after].base = 0; hdr->freemap[after].size = 0; } else if (before >= 0) { map = &hdr->freemap[before]; - be16_add(&map->size, entsize); + be16_add_cpu(&map->size, entsize); } else { map = &hdr->freemap[after]; /* both on-disk, don't endian flip twice */ map->base = entry->nameidx; - be16_add(&map->size, entsize); + be16_add_cpu(&map->size, entsize); } } else { /* @@ -1788,7 +1788,7 @@ xfs_attr_leaf_remove(xfs_dabuf_t *bp, xfs_da_args_t *args) * Compress the remaining entries and zero out the removed stuff. */ memset(XFS_ATTR_LEAF_NAME(leaf, args->index), 0, entsize); - be16_add(&hdr->usedbytes, -entsize); + be16_add_cpu(&hdr->usedbytes, -entsize); xfs_da_log_buf(args->trans, bp, XFS_DA_LOGRANGE(leaf, XFS_ATTR_LEAF_NAME(leaf, args->index), entsize)); @@ -1796,7 +1796,7 @@ xfs_attr_leaf_remove(xfs_dabuf_t *bp, xfs_da_args_t *args) tmp = (be16_to_cpu(hdr->count) - args->index) * sizeof(xfs_attr_leaf_entry_t); memmove((char *)entry, (char *)(entry+1), tmp); - be16_add(&hdr->count, -1); + be16_add_cpu(&hdr->count, -1); xfs_da_log_buf(args->trans, bp, XFS_DA_LOGRANGE(leaf, entry, tmp + sizeof(*entry))); entry = &leaf->entries[be16_to_cpu(hdr->count)]; @@ -2182,15 +2182,15 @@ xfs_attr_leaf_moveents(xfs_attr_leafblock_t *leaf_s, int start_s, */ if (entry_s->flags & XFS_ATTR_INCOMPLETE) { /* skip partials? */ memset(XFS_ATTR_LEAF_NAME(leaf_s, start_s + i), 0, tmp); - be16_add(&hdr_s->usedbytes, -tmp); - be16_add(&hdr_s->count, -1); + be16_add_cpu(&hdr_s->usedbytes, -tmp); + be16_add_cpu(&hdr_s->count, -1); entry_d--; /* to compensate for ++ in loop hdr */ desti--; if ((start_s + i) < offset) result++; /* insertion index adjustment */ } else { #endif /* GROT */ - be16_add(&hdr_d->firstused, -tmp); + be16_add_cpu(&hdr_d->firstused, -tmp); /* both on-disk, don't endian flip twice */ entry_d->hashval = entry_s->hashval; /* both on-disk, don't endian flip twice */ @@ -2203,10 +2203,10 @@ xfs_attr_leaf_moveents(xfs_attr_leafblock_t *leaf_s, int start_s, ASSERT(be16_to_cpu(entry_s->nameidx) + tmp <= XFS_LBSIZE(mp)); memset(XFS_ATTR_LEAF_NAME(leaf_s, start_s + i), 0, tmp); - be16_add(&hdr_s->usedbytes, -tmp); - be16_add(&hdr_d->usedbytes, tmp); - be16_add(&hdr_s->count, -1); - be16_add(&hdr_d->count, 1); + be16_add_cpu(&hdr_s->usedbytes, -tmp); + be16_add_cpu(&hdr_d->usedbytes, tmp); + be16_add_cpu(&hdr_s->count, -1); + be16_add_cpu(&hdr_d->count, 1); tmp = be16_to_cpu(hdr_d->count) * sizeof(xfs_attr_leaf_entry_t) + sizeof(xfs_attr_leaf_hdr_t); @@ -2247,7 +2247,7 @@ xfs_attr_leaf_moveents(xfs_attr_leafblock_t *leaf_s, int start_s, * Fill in the freemap information */ hdr_d->freemap[0].base = cpu_to_be16(sizeof(xfs_attr_leaf_hdr_t)); - be16_add(&hdr_d->freemap[0].base, be16_to_cpu(hdr_d->count) * + be16_add_cpu(&hdr_d->freemap[0].base, be16_to_cpu(hdr_d->count) * sizeof(xfs_attr_leaf_entry_t)); hdr_d->freemap[0].size = cpu_to_be16(be16_to_cpu(hdr_d->firstused) - be16_to_cpu(hdr_d->freemap[0].base)); diff --git a/fs/xfs/xfs_bmap_btree.c b/fs/xfs/xfs_bmap_btree.c index c4181d85605..bd18987326a 100644 --- a/fs/xfs/xfs_bmap_btree.c +++ b/fs/xfs/xfs_bmap_btree.c @@ -631,7 +631,7 @@ xfs_bmbt_delrec( memcpy(lrp, rrp, numrrecs * sizeof(*lrp)); xfs_bmbt_log_recs(cur, lbp, numlrecs + 1, numlrecs + numrrecs); } - be16_add(&left->bb_numrecs, numrrecs); + be16_add_cpu(&left->bb_numrecs, numrrecs); left->bb_rightsib = right->bb_rightsib; xfs_bmbt_log_block(cur, lbp, XFS_BB_RIGHTSIB | XFS_BB_NUMRECS); if (be64_to_cpu(left->bb_rightsib) != NULLDFSBNO) { @@ -924,7 +924,7 @@ xfs_bmbt_killroot( xfs_iroot_realloc(ip, i, cur->bc_private.b.whichfork); block = ifp->if_broot; } - be16_add(&block->bb_numrecs, i); + be16_add_cpu(&block->bb_numrecs, i); ASSERT(block->bb_numrecs == cblock->bb_numrecs); kp = XFS_BMAP_KEY_IADDR(block, 1, cur); ckp = XFS_BMAP_KEY_IADDR(cblock, 1, cur); @@ -947,7 +947,7 @@ xfs_bmbt_killroot( XFS_TRANS_DQ_BCOUNT, -1L); xfs_trans_binval(cur->bc_tp, cbp); cur->bc_bufs[level - 1] = NULL; - be16_add(&block->bb_level, -1); + be16_add_cpu(&block->bb_level, -1); xfs_trans_log_inode(cur->bc_tp, ip, XFS_ILOG_CORE | XFS_ILOG_FBROOT(cur->bc_private.b.whichfork)); cur->bc_nlevels--; @@ -1401,9 +1401,9 @@ xfs_bmbt_rshift( key.br_startoff = cpu_to_be64(xfs_bmbt_disk_get_startoff(rrp)); rkp = &key; } - be16_add(&left->bb_numrecs, -1); + be16_add_cpu(&left->bb_numrecs, -1); xfs_bmbt_log_block(cur, lbp, XFS_BB_NUMRECS); - be16_add(&right->bb_numrecs, 1); + be16_add_cpu(&right->bb_numrecs, 1); #ifdef DEBUG if (level > 0) xfs_btree_check_key(XFS_BTNUM_BMAP, rkp, rkp + 1); @@ -1535,7 +1535,7 @@ xfs_bmbt_split( right->bb_numrecs = cpu_to_be16(be16_to_cpu(left->bb_numrecs) / 2); if ((be16_to_cpu(left->bb_numrecs) & 1) && cur->bc_ptrs[level] <= be16_to_cpu(right->bb_numrecs) + 1) - be16_add(&right->bb_numrecs, 1); + be16_add_cpu(&right->bb_numrecs, 1); i = be16_to_cpu(left->bb_numrecs) - be16_to_cpu(right->bb_numrecs) + 1; if (level > 0) { lkp = XFS_BMAP_KEY_IADDR(left, i, cur); @@ -1562,7 +1562,7 @@ xfs_bmbt_split( xfs_bmbt_log_recs(cur, rbp, 1, be16_to_cpu(right->bb_numrecs)); *startoff = xfs_bmbt_disk_get_startoff(rrp); } - be16_add(&left->bb_numrecs, -(be16_to_cpu(right->bb_numrecs))); + be16_add_cpu(&left->bb_numrecs, -(be16_to_cpu(right->bb_numrecs))); right->bb_rightsib = left->bb_rightsib; left->bb_rightsib = cpu_to_be64(args.fsbno); right->bb_leftsib = cpu_to_be64(lbno); @@ -2240,7 +2240,7 @@ xfs_bmbt_newroot( bp = xfs_btree_get_bufl(args.mp, cur->bc_tp, args.fsbno, 0); cblock = XFS_BUF_TO_BMBT_BLOCK(bp); *cblock = *block; - be16_add(&block->bb_level, 1); + be16_add_cpu(&block->bb_level, 1); block->bb_numrecs = cpu_to_be16(1); cur->bc_nlevels++; cur->bc_ptrs[level + 1] = 1; diff --git a/fs/xfs/xfs_da_btree.c b/fs/xfs/xfs_da_btree.c index 1b446849fb3..021a8f7e563 100644 --- a/fs/xfs/xfs_da_btree.c +++ b/fs/xfs/xfs_da_btree.c @@ -511,12 +511,12 @@ xfs_da_node_rebalance(xfs_da_state_t *state, xfs_da_state_blk_t *blk1, * Move the req'd B-tree elements from high in node1 to * low in node2. */ - be16_add(&node2->hdr.count, count); + be16_add_cpu(&node2->hdr.count, count); tmp = count * (uint)sizeof(xfs_da_node_entry_t); btree_s = &node1->btree[be16_to_cpu(node1->hdr.count) - count]; btree_d = &node2->btree[0]; memcpy(btree_d, btree_s, tmp); - be16_add(&node1->hdr.count, -count); + be16_add_cpu(&node1->hdr.count, -count); } else { /* * Move the req'd B-tree elements from low in node2 to @@ -527,7 +527,7 @@ xfs_da_node_rebalance(xfs_da_state_t *state, xfs_da_state_blk_t *blk1, btree_s = &node2->btree[0]; btree_d = &node1->btree[be16_to_cpu(node1->hdr.count)]; memcpy(btree_d, btree_s, tmp); - be16_add(&node1->hdr.count, count); + be16_add_cpu(&node1->hdr.count, count); xfs_da_log_buf(tp, blk1->bp, XFS_DA_LOGRANGE(node1, btree_d, tmp)); @@ -539,7 +539,7 @@ xfs_da_node_rebalance(xfs_da_state_t *state, xfs_da_state_blk_t *blk1, btree_s = &node2->btree[count]; btree_d = &node2->btree[0]; memmove(btree_d, btree_s, tmp); - be16_add(&node2->hdr.count, -count); + be16_add_cpu(&node2->hdr.count, -count); } /* @@ -604,7 +604,7 @@ xfs_da_node_add(xfs_da_state_t *state, xfs_da_state_blk_t *oldblk, btree->before = cpu_to_be32(newblk->blkno); xfs_da_log_buf(state->args->trans, oldblk->bp, XFS_DA_LOGRANGE(node, btree, tmp + sizeof(*btree))); - be16_add(&node->hdr.count, 1); + be16_add_cpu(&node->hdr.count, 1); xfs_da_log_buf(state->args->trans, oldblk->bp, XFS_DA_LOGRANGE(node, &node->hdr, sizeof(node->hdr))); @@ -959,7 +959,7 @@ xfs_da_node_remove(xfs_da_state_t *state, xfs_da_state_blk_t *drop_blk) memset((char *)btree, 0, sizeof(xfs_da_node_entry_t)); xfs_da_log_buf(state->args->trans, drop_blk->bp, XFS_DA_LOGRANGE(node, btree, sizeof(*btree))); - be16_add(&node->hdr.count, -1); + be16_add_cpu(&node->hdr.count, -1); xfs_da_log_buf(state->args->trans, drop_blk->bp, XFS_DA_LOGRANGE(node, &node->hdr, sizeof(node->hdr))); @@ -1018,7 +1018,7 @@ xfs_da_node_unbalance(xfs_da_state_t *state, xfs_da_state_blk_t *drop_blk, */ tmp = be16_to_cpu(drop_node->hdr.count) * (uint)sizeof(xfs_da_node_entry_t); memcpy(btree, &drop_node->btree[0], tmp); - be16_add(&save_node->hdr.count, be16_to_cpu(drop_node->hdr.count)); + be16_add_cpu(&save_node->hdr.count, be16_to_cpu(drop_node->hdr.count)); xfs_da_log_buf(tp, save_blk->bp, XFS_DA_LOGRANGE(save_node, &save_node->hdr, diff --git a/fs/xfs/xfs_dir2_block.c b/fs/xfs/xfs_dir2_block.c index a5f4f4fb886..fb5a556725b 100644 --- a/fs/xfs/xfs_dir2_block.c +++ b/fs/xfs/xfs_dir2_block.c @@ -271,7 +271,7 @@ xfs_dir2_block_addname( } lfloglow = toidx + 1 - (be32_to_cpu(btp->stale) - 1); lfloghigh -= be32_to_cpu(btp->stale) - 1; - be32_add(&btp->count, -(be32_to_cpu(btp->stale) - 1)); + be32_add_cpu(&btp->count, -(be32_to_cpu(btp->stale) - 1)); xfs_dir2_data_make_free(tp, bp, (xfs_dir2_data_aoff_t)((char *)blp - (char *)block), (xfs_dir2_data_aoff_t)((be32_to_cpu(btp->stale) - 1) * sizeof(*blp)), @@ -326,7 +326,7 @@ xfs_dir2_block_addname( /* * Update the tail (entry count). */ - be32_add(&btp->count, 1); + be32_add_cpu(&btp->count, 1); /* * If we now need to rebuild the bestfree map, do so. * This needs to happen before the next call to use_free. @@ -387,7 +387,7 @@ xfs_dir2_block_addname( lfloglow = MIN(mid, lfloglow); lfloghigh = MAX(highstale, lfloghigh); } - be32_add(&btp->stale, -1); + be32_add_cpu(&btp->stale, -1); } /* * Point to the new data entry. @@ -767,7 +767,7 @@ xfs_dir2_block_removename( /* * Fix up the block tail. */ - be32_add(&btp->stale, 1); + be32_add_cpu(&btp->stale, 1); xfs_dir2_block_log_tail(tp, bp); /* * Remove the leaf entry by marking it stale. diff --git a/fs/xfs/xfs_dir2_data.c b/fs/xfs/xfs_dir2_data.c index d2452699e9b..fb8c9e08b23 100644 --- a/fs/xfs/xfs_dir2_data.c +++ b/fs/xfs/xfs_dir2_data.c @@ -587,7 +587,7 @@ xfs_dir2_data_make_free( /* * Fix up the new big freespace. */ - be16_add(&prevdup->length, len + be16_to_cpu(postdup->length)); + be16_add_cpu(&prevdup->length, len + be16_to_cpu(postdup->length)); *xfs_dir2_data_unused_tag_p(prevdup) = cpu_to_be16((char *)prevdup - (char *)d); xfs_dir2_data_log_unused(tp, bp, prevdup); @@ -621,7 +621,7 @@ xfs_dir2_data_make_free( */ else if (prevdup) { dfp = xfs_dir2_data_freefind(d, prevdup); - be16_add(&prevdup->length, len); + be16_add_cpu(&prevdup->length, len); *xfs_dir2_data_unused_tag_p(prevdup) = cpu_to_be16((char *)prevdup - (char *)d); xfs_dir2_data_log_unused(tp, bp, prevdup); diff --git a/fs/xfs/xfs_dir2_leaf.c b/fs/xfs/xfs_dir2_leaf.c index 0ca0020ba09..bc52b803d79 100644 --- a/fs/xfs/xfs_dir2_leaf.c +++ b/fs/xfs/xfs_dir2_leaf.c @@ -359,7 +359,7 @@ xfs_dir2_leaf_addname( bestsp--; memmove(&bestsp[0], &bestsp[1], be32_to_cpu(ltp->bestcount) * sizeof(bestsp[0])); - be32_add(<p->bestcount, 1); + be32_add_cpu(<p->bestcount, 1); xfs_dir2_leaf_log_tail(tp, lbp); xfs_dir2_leaf_log_bests(tp, lbp, 0, be32_to_cpu(ltp->bestcount) - 1); } @@ -445,7 +445,7 @@ xfs_dir2_leaf_addname( */ lfloglow = index; lfloghigh = be16_to_cpu(leaf->hdr.count); - be16_add(&leaf->hdr.count, 1); + be16_add_cpu(&leaf->hdr.count, 1); } /* * There are stale entries. @@ -523,7 +523,7 @@ xfs_dir2_leaf_addname( lfloglow = MIN(index, lfloglow); lfloghigh = MAX(highstale, lfloghigh); } - be16_add(&leaf->hdr.stale, -1); + be16_add_cpu(&leaf->hdr.stale, -1); } /* * Fill in the new leaf entry. @@ -626,7 +626,7 @@ xfs_dir2_leaf_compact( * Update and log the header, log the leaf entries. */ ASSERT(be16_to_cpu(leaf->hdr.stale) == from - to); - be16_add(&leaf->hdr.count, -(be16_to_cpu(leaf->hdr.stale))); + be16_add_cpu(&leaf->hdr.count, -(be16_to_cpu(leaf->hdr.stale))); leaf->hdr.stale = 0; xfs_dir2_leaf_log_header(args->trans, bp); if (loglow != -1) @@ -728,7 +728,7 @@ xfs_dir2_leaf_compact_x1( /* * Adjust the leaf header values. */ - be16_add(&leaf->hdr.count, -(from - to)); + be16_add_cpu(&leaf->hdr.count, -(from - to)); leaf->hdr.stale = cpu_to_be16(1); /* * Remember the low/high stale value only in the "right" @@ -1470,7 +1470,7 @@ xfs_dir2_leaf_removename( /* * We just mark the leaf entry stale by putting a null in it. */ - be16_add(&leaf->hdr.stale, 1); + be16_add_cpu(&leaf->hdr.stale, 1); xfs_dir2_leaf_log_header(tp, lbp); lep->address = cpu_to_be32(XFS_DIR2_NULL_DATAPTR); xfs_dir2_leaf_log_ents(tp, lbp, index, index); @@ -1531,7 +1531,7 @@ xfs_dir2_leaf_removename( */ memmove(&bestsp[db - i], bestsp, (be32_to_cpu(ltp->bestcount) - (db - i)) * sizeof(*bestsp)); - be32_add(<p->bestcount, -(db - i)); + be32_add_cpu(<p->bestcount, -(db - i)); xfs_dir2_leaf_log_tail(tp, lbp); xfs_dir2_leaf_log_bests(tp, lbp, 0, be32_to_cpu(ltp->bestcount) - 1); } else @@ -1712,7 +1712,7 @@ xfs_dir2_leaf_trim_data( * Eliminate the last bests entry from the table. */ bestsp = xfs_dir2_leaf_bests_p(ltp); - be32_add(<p->bestcount, -1); + be32_add_cpu(<p->bestcount, -1); memmove(&bestsp[1], &bestsp[0], be32_to_cpu(ltp->bestcount) * sizeof(*bestsp)); xfs_dir2_leaf_log_tail(tp, lbp); xfs_dir2_leaf_log_bests(tp, lbp, 0, be32_to_cpu(ltp->bestcount) - 1); diff --git a/fs/xfs/xfs_dir2_node.c b/fs/xfs/xfs_dir2_node.c index eb18e399e83..8dade711f09 100644 --- a/fs/xfs/xfs_dir2_node.c +++ b/fs/xfs/xfs_dir2_node.c @@ -254,7 +254,7 @@ xfs_dir2_leafn_add( (be16_to_cpu(leaf->hdr.count) - index) * sizeof(*lep)); lfloglow = index; lfloghigh = be16_to_cpu(leaf->hdr.count); - be16_add(&leaf->hdr.count, 1); + be16_add_cpu(&leaf->hdr.count, 1); } /* * There are stale entries. We'll use one for the new entry. @@ -322,7 +322,7 @@ xfs_dir2_leafn_add( lfloglow = MIN(index, lfloglow); lfloghigh = MAX(highstale, lfloghigh); } - be16_add(&leaf->hdr.stale, -1); + be16_add_cpu(&leaf->hdr.stale, -1); } /* * Insert the new entry, log everything. @@ -697,10 +697,10 @@ xfs_dir2_leafn_moveents( /* * Update the headers and log them. */ - be16_add(&leaf_s->hdr.count, -(count)); - be16_add(&leaf_s->hdr.stale, -(stale)); - be16_add(&leaf_d->hdr.count, count); - be16_add(&leaf_d->hdr.stale, stale); + be16_add_cpu(&leaf_s->hdr.count, -(count)); + be16_add_cpu(&leaf_s->hdr.stale, -(stale)); + be16_add_cpu(&leaf_d->hdr.count, count); + be16_add_cpu(&leaf_d->hdr.stale, stale); xfs_dir2_leaf_log_header(tp, bp_s); xfs_dir2_leaf_log_header(tp, bp_d); xfs_dir2_leafn_check(args->dp, bp_s); @@ -885,7 +885,7 @@ xfs_dir2_leafn_remove( * Kill the leaf entry by marking it stale. * Log the leaf block changes. */ - be16_add(&leaf->hdr.stale, 1); + be16_add_cpu(&leaf->hdr.stale, 1); xfs_dir2_leaf_log_header(tp, bp); lep->address = cpu_to_be32(XFS_DIR2_NULL_DATAPTR); xfs_dir2_leaf_log_ents(tp, bp, index, index); @@ -971,7 +971,7 @@ xfs_dir2_leafn_remove( /* * One less used entry in the free table. */ - be32_add(&free->hdr.nused, -1); + be32_add_cpu(&free->hdr.nused, -1); xfs_dir2_free_log_header(tp, fbp); /* * If this was the last entry in the table, we can @@ -1642,7 +1642,7 @@ xfs_dir2_node_addname_int( * (this should always be true) then update the header. */ if (be16_to_cpu(free->bests[findex]) == NULLDATAOFF) { - be32_add(&free->hdr.nused, 1); + be32_add_cpu(&free->hdr.nused, 1); xfs_dir2_free_log_header(tp, fbp); } /* diff --git a/fs/xfs/xfs_fsops.c b/fs/xfs/xfs_fsops.c index b8de7f3cc17..eadc1591c79 100644 --- a/fs/xfs/xfs_fsops.c +++ b/fs/xfs/xfs_fsops.c @@ -318,7 +318,7 @@ xfs_growfs_data_private( } ASSERT(bp); agi = XFS_BUF_TO_AGI(bp); - be32_add(&agi->agi_length, new); + be32_add_cpu(&agi->agi_length, new); ASSERT(nagcount == oagcount || be32_to_cpu(agi->agi_length) == mp->m_sb.sb_agblocks); xfs_ialloc_log_agi(tp, bp, XFS_AGI_LENGTH); @@ -331,7 +331,7 @@ xfs_growfs_data_private( } ASSERT(bp); agf = XFS_BUF_TO_AGF(bp); - be32_add(&agf->agf_length, new); + be32_add_cpu(&agf->agf_length, new); ASSERT(be32_to_cpu(agf->agf_length) == be32_to_cpu(agi->agi_length)); xfs_alloc_log_agf(tp, bp, XFS_AGF_LENGTH); diff --git a/fs/xfs/xfs_ialloc.c b/fs/xfs/xfs_ialloc.c index 1409c2d61c1..c5836b951d0 100644 --- a/fs/xfs/xfs_ialloc.c +++ b/fs/xfs/xfs_ialloc.c @@ -301,8 +301,8 @@ xfs_ialloc_ag_alloc( } xfs_trans_inode_alloc_buf(tp, fbuf); } - be32_add(&agi->agi_count, newlen); - be32_add(&agi->agi_freecount, newlen); + be32_add_cpu(&agi->agi_count, newlen); + be32_add_cpu(&agi->agi_freecount, newlen); agno = be32_to_cpu(agi->agi_seqno); down_read(&args.mp->m_peraglock); args.mp->m_perag[agno].pagi_freecount += newlen; @@ -885,7 +885,7 @@ nextag: if ((error = xfs_inobt_update(cur, rec.ir_startino, rec.ir_freecount, rec.ir_free))) goto error0; - be32_add(&agi->agi_freecount, -1); + be32_add_cpu(&agi->agi_freecount, -1); xfs_ialloc_log_agi(tp, agbp, XFS_AGI_FREECOUNT); down_read(&mp->m_peraglock); mp->m_perag[tagno].pagi_freecount--; @@ -1065,8 +1065,8 @@ xfs_difree( * to be freed when the transaction is committed. */ ilen = XFS_IALLOC_INODES(mp); - be32_add(&agi->agi_count, -ilen); - be32_add(&agi->agi_freecount, -(ilen - 1)); + be32_add_cpu(&agi->agi_count, -ilen); + be32_add_cpu(&agi->agi_freecount, -(ilen - 1)); xfs_ialloc_log_agi(tp, agbp, XFS_AGI_COUNT | XFS_AGI_FREECOUNT); down_read(&mp->m_peraglock); mp->m_perag[agno].pagi_freecount -= ilen - 1; @@ -1095,7 +1095,7 @@ xfs_difree( /* * Change the inode free counts and log the ag/sb changes. */ - be32_add(&agi->agi_freecount, 1); + be32_add_cpu(&agi->agi_freecount, 1); xfs_ialloc_log_agi(tp, agbp, XFS_AGI_FREECOUNT); down_read(&mp->m_peraglock); mp->m_perag[agno].pagi_freecount++; diff --git a/fs/xfs/xfs_ialloc_btree.c b/fs/xfs/xfs_ialloc_btree.c index 8cdeeaf8632..e5310c90e50 100644 --- a/fs/xfs/xfs_ialloc_btree.c +++ b/fs/xfs/xfs_ialloc_btree.c @@ -189,7 +189,7 @@ xfs_inobt_delrec( */ bno = be32_to_cpu(agi->agi_root); agi->agi_root = *pp; - be32_add(&agi->agi_level, -1); + be32_add_cpu(&agi->agi_level, -1); /* * Free the block. */ @@ -1132,7 +1132,7 @@ xfs_inobt_lshift( /* * Bump and log left's numrecs, decrement and log right's numrecs. */ - be16_add(&left->bb_numrecs, 1); + be16_add_cpu(&left->bb_numrecs, 1); xfs_inobt_log_block(cur->bc_tp, lbp, XFS_BB_NUMRECS); #ifdef DEBUG if (level > 0) @@ -1140,7 +1140,7 @@ xfs_inobt_lshift( else xfs_btree_check_rec(cur->bc_btnum, lrp - 1, lrp); #endif - be16_add(&right->bb_numrecs, -1); + be16_add_cpu(&right->bb_numrecs, -1); xfs_inobt_log_block(cur->bc_tp, rbp, XFS_BB_NUMRECS); /* * Slide the contents of right down one entry. @@ -1232,7 +1232,7 @@ xfs_inobt_newroot( * Set the root data in the a.g. inode structure. */ agi->agi_root = cpu_to_be32(args.agbno); - be32_add(&agi->agi_level, 1); + be32_add_cpu(&agi->agi_level, 1); xfs_ialloc_log_agi(args.tp, cur->bc_private.i.agbp, XFS_AGI_ROOT | XFS_AGI_LEVEL); /* @@ -1426,9 +1426,9 @@ xfs_inobt_rshift( /* * Decrement and log left's numrecs, bump and log right's numrecs. */ - be16_add(&left->bb_numrecs, -1); + be16_add_cpu(&left->bb_numrecs, -1); xfs_inobt_log_block(cur->bc_tp, lbp, XFS_BB_NUMRECS); - be16_add(&right->bb_numrecs, 1); + be16_add_cpu(&right->bb_numrecs, 1); #ifdef DEBUG if (level > 0) xfs_btree_check_key(cur->bc_btnum, rkp, rkp + 1); @@ -1529,7 +1529,7 @@ xfs_inobt_split( */ if ((be16_to_cpu(left->bb_numrecs) & 1) && cur->bc_ptrs[level] <= be16_to_cpu(right->bb_numrecs) + 1) - be16_add(&right->bb_numrecs, 1); + be16_add_cpu(&right->bb_numrecs, 1); i = be16_to_cpu(left->bb_numrecs) - be16_to_cpu(right->bb_numrecs) + 1; /* * For non-leaf blocks, copy keys and addresses over to the new block. @@ -1565,7 +1565,7 @@ xfs_inobt_split( * Find the left block number by looking in the buffer. * Adjust numrecs, sibling pointers. */ - be16_add(&left->bb_numrecs, -(be16_to_cpu(right->bb_numrecs))); + be16_add_cpu(&left->bb_numrecs, -(be16_to_cpu(right->bb_numrecs))); right->bb_rightsib = left->bb_rightsib; left->bb_rightsib = cpu_to_be32(args.agbno); right->bb_leftsib = cpu_to_be32(lbno); diff --git a/fs/xfs/xfs_log.c b/fs/xfs/xfs_log.c index b3ac3805d3c..a75edca1860 100644 --- a/fs/xfs/xfs_log.c +++ b/fs/xfs/xfs_log.c @@ -1509,9 +1509,9 @@ xlog_sync(xlog_t *log, * case, though. */ for (i = 0; i < split; i += BBSIZE) { - be32_add((__be32 *)dptr, 1); + be32_add_cpu((__be32 *)dptr, 1); if (be32_to_cpu(*(__be32 *)dptr) == XLOG_HEADER_MAGIC_NUM) - be32_add((__be32 *)dptr, 1); + be32_add_cpu((__be32 *)dptr, 1); dptr += BBSIZE; } @@ -1600,7 +1600,7 @@ xlog_state_finish_copy(xlog_t *log, { spin_lock(&log->l_icloglock); - be32_add(&iclog->ic_header.h_num_logops, record_cnt); + be32_add_cpu(&iclog->ic_header.h_num_logops, record_cnt); iclog->ic_offset += copy_bytes; spin_unlock(&log->l_icloglock); diff --git a/fs/xfs/xfs_trans.c b/fs/xfs/xfs_trans.c index 71e4c8dcc69..140386434aa 100644 --- a/fs/xfs/xfs_trans.c +++ b/fs/xfs/xfs_trans.c @@ -567,26 +567,26 @@ xfs_trans_apply_sb_deltas( */ if (!xfs_sb_version_haslazysbcount(&(tp->t_mountp->m_sb))) { if (tp->t_icount_delta) - be64_add(&sbp->sb_icount, tp->t_icount_delta); + be64_add_cpu(&sbp->sb_icount, tp->t_icount_delta); if (tp->t_ifree_delta) - be64_add(&sbp->sb_ifree, tp->t_ifree_delta); + be64_add_cpu(&sbp->sb_ifree, tp->t_ifree_delta); if (tp->t_fdblocks_delta) - be64_add(&sbp->sb_fdblocks, tp->t_fdblocks_delta); + be64_add_cpu(&sbp->sb_fdblocks, tp->t_fdblocks_delta); if (tp->t_res_fdblocks_delta) - be64_add(&sbp->sb_fdblocks, tp->t_res_fdblocks_delta); + be64_add_cpu(&sbp->sb_fdblocks, tp->t_res_fdblocks_delta); } if (tp->t_frextents_delta) - be64_add(&sbp->sb_frextents, tp->t_frextents_delta); + be64_add_cpu(&sbp->sb_frextents, tp->t_frextents_delta); if (tp->t_res_frextents_delta) - be64_add(&sbp->sb_frextents, tp->t_res_frextents_delta); + be64_add_cpu(&sbp->sb_frextents, tp->t_res_frextents_delta); if (tp->t_dblocks_delta) { - be64_add(&sbp->sb_dblocks, tp->t_dblocks_delta); + be64_add_cpu(&sbp->sb_dblocks, tp->t_dblocks_delta); whole = 1; } if (tp->t_agcount_delta) { - be32_add(&sbp->sb_agcount, tp->t_agcount_delta); + be32_add_cpu(&sbp->sb_agcount, tp->t_agcount_delta); whole = 1; } if (tp->t_imaxpct_delta) { @@ -594,19 +594,19 @@ xfs_trans_apply_sb_deltas( whole = 1; } if (tp->t_rextsize_delta) { - be32_add(&sbp->sb_rextsize, tp->t_rextsize_delta); + be32_add_cpu(&sbp->sb_rextsize, tp->t_rextsize_delta); whole = 1; } if (tp->t_rbmblocks_delta) { - be32_add(&sbp->sb_rbmblocks, tp->t_rbmblocks_delta); + be32_add_cpu(&sbp->sb_rbmblocks, tp->t_rbmblocks_delta); whole = 1; } if (tp->t_rblocks_delta) { - be64_add(&sbp->sb_rblocks, tp->t_rblocks_delta); + be64_add_cpu(&sbp->sb_rblocks, tp->t_rblocks_delta); whole = 1; } if (tp->t_rextents_delta) { - be64_add(&sbp->sb_rextents, tp->t_rextents_delta); + be64_add_cpu(&sbp->sb_rextents, tp->t_rextents_delta); whole = 1; } if (tp->t_rextslog_delta) { diff --git a/include/acpi/acpiosxf.h b/include/acpi/acpiosxf.h index 022a5fd80c8..4839f2af94c 100644 --- a/include/acpi/acpiosxf.h +++ b/include/acpi/acpiosxf.h @@ -222,7 +222,7 @@ acpi_os_write_memory(acpi_physical_address address, u32 value, u32 width); */ acpi_status acpi_os_read_pci_configuration(struct acpi_pci_id *pci_id, - u32 reg, void *value, u32 width); + u32 reg, u32 *value, u32 width); acpi_status acpi_os_write_pci_configuration(struct acpi_pci_id *pci_id, diff --git a/include/acpi/processor.h b/include/acpi/processor.h index cdc8004cfd1..06480bcabfd 100644 --- a/include/acpi/processor.h +++ b/include/acpi/processor.h @@ -32,9 +32,11 @@ #define DOMAIN_COORD_TYPE_SW_ANY 0xfd #define DOMAIN_COORD_TYPE_HW_ALL 0xfe -#define ACPI_CSTATE_SYSTEMIO (0) -#define ACPI_CSTATE_FFH (1) -#define ACPI_CSTATE_HALT (2) +#define ACPI_CSTATE_SYSTEMIO 0 +#define ACPI_CSTATE_FFH 1 +#define ACPI_CSTATE_HALT 2 + +#define ACPI_CX_DESC_LEN 32 /* Power Management */ @@ -74,6 +76,7 @@ struct acpi_processor_cx { u64 time; struct acpi_processor_cx_policy promotion; struct acpi_processor_cx_policy demotion; + char desc[ACPI_CX_DESC_LEN]; }; struct acpi_processor_power { diff --git a/include/asm-m68knommu/cacheflush.h b/include/asm-m68knommu/cacheflush.h index 29bc0aad2eb..87e5dc0413b 100644 --- a/include/asm-m68knommu/cacheflush.h +++ b/include/asm-m68knommu/cacheflush.h @@ -54,28 +54,28 @@ static inline void __flush_cache_all(void) #if defined(CONFIG_M527x) || defined(CONFIG_M528x) __asm__ __volatile__ ( "movel #0x81000200, %%d0\n\t" - "movec %%d0, %%CACR\n\t" + "movec %%d0, %%CACR\n\t" "nop\n\t" : : : "d0" ); #endif /* CONFIG_M527x || CONFIG_M528x */ #if defined(CONFIG_M5206) || defined(CONFIG_M5206e) || defined(CONFIG_M5272) __asm__ __volatile__ ( - "movel #0x81000100, %%d0\n\t" - "movec %%d0, %%CACR\n\t" + "movel #0x81000100, %%d0\n\t" + "movec %%d0, %%CACR\n\t" "nop\n\t" : : : "d0" ); #endif /* CONFIG_M5206 || CONFIG_M5206e || CONFIG_M5272 */ #ifdef CONFIG_M5249 __asm__ __volatile__ ( - "movel #0xa1000200, %%d0\n\t" - "movec %%d0, %%CACR\n\t" + "movel #0xa1000200, %%d0\n\t" + "movec %%d0, %%CACR\n\t" "nop\n\t" : : : "d0" ); #endif /* CONFIG_M5249 */ #ifdef CONFIG_M532x __asm__ __volatile__ ( - "movel #0x81000200, %%d0\n\t" - "movec %%d0, %%CACR\n\t" + "movel #0x81000200, %%d0\n\t" + "movec %%d0, %%CACR\n\t" "nop\n\t" : : : "d0" ); #endif /* CONFIG_M532x */ diff --git a/include/asm-m68knommu/system.h b/include/asm-m68knommu/system.h index 039ab3f8173..64c64432bbb 100644 --- a/include/asm-m68knommu/system.h +++ b/include/asm-m68knommu/system.h @@ -104,7 +104,7 @@ asmlinkage void resume(void); #define mb() asm volatile ("" : : :"memory") #define rmb() asm volatile ("" : : :"memory") #define wmb() asm volatile ("" : : :"memory") -#define set_mb(var, value) do { xchg(&var, value); } while (0) +#define set_mb(var, value) ({ (var) = (value); wmb(); }) #ifdef CONFIG_SMP #define smp_mb() mb() diff --git a/include/asm-mn10300/highmem.h b/include/asm-mn10300/highmem.h index 383c0c42982..5256854c045 100644 --- a/include/asm-mn10300/highmem.h +++ b/include/asm-mn10300/highmem.h @@ -42,8 +42,8 @@ extern void __init kmap_init(void); #define PKMAP_NR(virt) ((virt - PKMAP_BASE) >> PAGE_SHIFT) #define PKMAP_ADDR(nr) (PKMAP_BASE + ((nr) << PAGE_SHIFT)) -extern unsigned long __fastcall kmap_high(struct page *page); -extern void __fastcall kunmap_high(struct page *page); +extern unsigned long kmap_high(struct page *page); +extern void kunmap_high(struct page *page); static inline unsigned long kmap(struct page *page) { diff --git a/include/asm-mn10300/linkage.h b/include/asm-mn10300/linkage.h index 29a32e46752..dda3002a5df 100644 --- a/include/asm-mn10300/linkage.h +++ b/include/asm-mn10300/linkage.h @@ -13,8 +13,6 @@ /* don't override anything */ #define asmlinkage -#define FASTCALL(x) x -#define fastcall #define __ALIGN .align 4,0xcb #define __ALIGN_STR ".align 4,0xcb" diff --git a/include/asm-powerpc/systbl.h b/include/asm-powerpc/systbl.h index e996521fb3a..ae7085c6569 100644 --- a/include/asm-powerpc/systbl.h +++ b/include/asm-powerpc/systbl.h @@ -309,8 +309,10 @@ SYSCALL_SPU(getcpu) COMPAT_SYS(epoll_pwait) COMPAT_SYS_SPU(utimensat) COMPAT_SYS_SPU(signalfd) -SYSCALL(ni_syscall) +SYSCALL_SPU(timerfd_create) SYSCALL_SPU(eventfd) COMPAT_SYS_SPU(sync_file_range2) COMPAT_SYS(fallocate) SYSCALL(subpage_prot) +COMPAT_SYS_SPU(timerfd_settime) +COMPAT_SYS_SPU(timerfd_gettime) diff --git a/include/asm-powerpc/unistd.h b/include/asm-powerpc/unistd.h index fedc4b8e49e..ce91bb66206 100644 --- a/include/asm-powerpc/unistd.h +++ b/include/asm-powerpc/unistd.h @@ -328,15 +328,17 @@ #define __NR_epoll_pwait 303 #define __NR_utimensat 304 #define __NR_signalfd 305 -#define __NR_timerfd 306 +#define __NR_timerfd_create 306 #define __NR_eventfd 307 #define __NR_sync_file_range2 308 #define __NR_fallocate 309 #define __NR_subpage_prot 310 +#define __NR_timerfd_settime 311 +#define __NR_timerfd_gettime 312 #ifdef __KERNEL__ -#define __NR_syscalls 311 +#define __NR_syscalls 313 #define __NR__exit __NR_exit #define NR_syscalls __NR_syscalls diff --git a/include/asm-ppc/page.h b/include/asm-ppc/page.h index ad4c5a1bc9d..37e4756b6b2 100644 --- a/include/asm-ppc/page.h +++ b/include/asm-ppc/page.h @@ -125,6 +125,8 @@ extern __inline__ int get_order(unsigned long size) return 32 - lz; } +typedef struct page *pgtable_t; + #endif /* __ASSEMBLY__ */ #define VM_DATA_DEFAULT_FLAGS (VM_READ | VM_WRITE | VM_EXEC | \ diff --git a/include/asm-sh/bugs.h b/include/asm-sh/bugs.h index def8128b8b7..cfda7d5bf02 100644 --- a/include/asm-sh/bugs.h +++ b/include/asm-sh/bugs.h @@ -39,7 +39,7 @@ static void __init check_bugs(void) *p++ = '4'; *p++ = 'a'; break; - case CPU_SH7343 ... CPU_SH7722: + case CPU_SH7343 ... CPU_SH7366: *p++ = '4'; *p++ = 'a'; *p++ = 'l'; diff --git a/include/asm-sh/cpu-sh4/freq.h b/include/asm-sh/cpu-sh4/freq.h index 1ac10b9a078..ec028c64921 100644 --- a/include/asm-sh/cpu-sh4/freq.h +++ b/include/asm-sh/cpu-sh4/freq.h @@ -10,12 +10,14 @@ #ifndef __ASM_CPU_SH4_FREQ_H #define __ASM_CPU_SH4_FREQ_H -#if defined(CONFIG_CPU_SUBTYPE_SH7722) +#if defined(CONFIG_CPU_SUBTYPE_SH7722) || defined(CONFIG_CPU_SUBTYPE_SH7366) #define FRQCR 0xa4150000 #define VCLKCR 0xa4150004 #define SCLKACR 0xa4150008 #define SCLKBCR 0xa415000c +#if defined(CONFIG_CPU_SUBTYPE_SH7722) #define IrDACLKCR 0xa4150010 +#endif #elif defined(CONFIG_CPU_SUBTYPE_SH7763) || \ defined(CONFIG_CPU_SUBTYPE_SH7780) #define FRQCR 0xffc80000 diff --git a/include/asm-sh/cpu-sh5/cacheflush.h b/include/asm-sh/cpu-sh5/cacheflush.h index 98edb5b1da3..5a11f0b7e66 100644 --- a/include/asm-sh/cpu-sh5/cacheflush.h +++ b/include/asm-sh/cpu-sh5/cacheflush.h @@ -3,15 +3,13 @@ #ifndef __ASSEMBLY__ -#include <asm/page.h> - struct vm_area_struct; struct page; struct mm_struct; extern void flush_cache_all(void); extern void flush_cache_mm(struct mm_struct *mm); -extern void flush_cache_sigtramp(unsigned long start, unsigned long end); +extern void flush_cache_sigtramp(unsigned long vaddr); extern void flush_cache_range(struct vm_area_struct *vma, unsigned long start, unsigned long end); extern void flush_cache_page(struct vm_area_struct *vma, unsigned long addr, unsigned long pfn); @@ -27,7 +25,7 @@ extern void flush_icache_user_range(struct vm_area_struct *vma, #define flush_dcache_mmap_unlock(mapping) do { } while (0) #define flush_icache_page(vma, page) do { } while (0) -#define p3_cache_init() do { } while (0) +void p3_cache_init(void); #endif /* __ASSEMBLY__ */ diff --git a/include/asm-sh/cpu-sh5/mmu_context.h b/include/asm-sh/cpu-sh5/mmu_context.h index df857fc0996..68a1d2cff45 100644 --- a/include/asm-sh/cpu-sh5/mmu_context.h +++ b/include/asm-sh/cpu-sh5/mmu_context.h @@ -16,12 +16,6 @@ /* This has to be a common function because the next location to fill * information is shared. */ extern void __do_tlb_refill(unsigned long address, unsigned long long is_text_not_data, pte_t *pte); - -/* Profiling counter. */ -#ifdef CONFIG_SH64_PROC_TLB -extern unsigned long long calls_to_do_fast_page_fault; -#endif - #endif /* __ASSEMBLY__ */ #endif /* __ASM_SH_CPU_SH5_MMU_CONTEXT_H */ diff --git a/include/asm-sh/hp6xx.h b/include/asm-sh/hp6xx.h index 53ca5643d9c..0d4165a32dc 100644 --- a/include/asm-sh/hp6xx.h +++ b/include/asm-sh/hp6xx.h @@ -10,9 +10,9 @@ * */ -#define HP680_BTN_IRQ 32 /* IRQ0_IRQ */ -#define HP680_TS_IRQ 35 /* IRQ3_IRQ */ -#define HP680_HD64461_IRQ 36 /* IRQ4_IRQ */ +#define HP680_BTN_IRQ 32 /* IRQ0_IRQ */ +#define HP680_TS_IRQ 35 /* IRQ3_IRQ */ +#define HP680_HD64461_IRQ 36 /* IRQ4_IRQ */ #define DAC_LCD_BRIGHTNESS 0 #define DAC_SPEAKER_VOLUME 1 @@ -55,26 +55,4 @@ #define PJDR 0xa4000130 #define PKDR 0xa4000132 -static inline void hp6xx_led_red(int on) -{ - u16 v16; - v16 = ctrl_inw(CONFIG_HD64461_IOBASE + HD64461_GPBDR - 0x10000); - if (on) - ctrl_outw(v16 & (~HD64461_GPBDR_LED_RED), CONFIG_HD64461_IOBASE + HD64461_GPBDR - 0x10000); - else - ctrl_outw(v16 | HD64461_GPBDR_LED_RED, CONFIG_HD64461_IOBASE + HD64461_GPBDR - 0x10000); -} - -static inline void hp6xx_led_green(int on) -{ - u8 v8; - - v8 = ctrl_inb(PKDR); - if (on) - ctrl_outb(v8 & (~PKDR_LED_GREEN), PKDR); - else - ctrl_outb(v8 | PKDR_LED_GREEN, PKDR); -} - - #endif /* __ASM_SH_HP6XX_H */ diff --git a/include/asm-sh/io.h b/include/asm-sh/io.h index 94900c08951..356e50d0674 100644 --- a/include/asm-sh/io.h +++ b/include/asm-sh/io.h @@ -38,6 +38,7 @@ */ #define __IO_PREFIX generic #include <asm/io_generic.h> +#include <asm/io_trapped.h> #define maybebadio(port) \ printk(KERN_ERR "bad PC-like io %s:%u for port 0x%lx at 0x%08x\n", \ @@ -181,13 +182,13 @@ __BUILD_MEMORY_STRING(w, u16) #define iowrite32(v,a) writel((v),(a)) #define iowrite32be(v,a) __raw_writel(cpu_to_be32((v)),(a)) -#define ioread8_rep(a,d,c) insb((a),(d),(c)) -#define ioread16_rep(a,d,c) insw((a),(d),(c)) -#define ioread32_rep(a,d,c) insl((a),(d),(c)) +#define ioread8_rep(a, d, c) readsb((a), (d), (c)) +#define ioread16_rep(a, d, c) readsw((a), (d), (c)) +#define ioread32_rep(a, d, c) readsl((a), (d), (c)) -#define iowrite8_rep(a,s,c) outsb((a),(s),(c)) -#define iowrite16_rep(a,s,c) outsw((a),(s),(c)) -#define iowrite32_rep(a,s,c) outsl((a),(s),(c)) +#define iowrite8_rep(a, s, c) writesb((a), (s), (c)) +#define iowrite16_rep(a, s, c) writesw((a), (s), (c)) +#define iowrite32_rep(a, s, c) writesl((a), (s), (c)) #define mmiowb() wmb() /* synco on SH-4A, otherwise a nop */ @@ -207,6 +208,8 @@ static inline void __set_io_port_base(unsigned long pbase) generic_io_base = pbase; } +#define __ioport_map(p, n) sh_mv.mv_ioport_map((p), (n)) + /* We really want to try and get these to memcpy etc */ extern void memcpy_fromio(void *, volatile void __iomem *, unsigned long); extern void memcpy_toio(volatile void __iomem *, const void *, unsigned long); @@ -309,7 +312,14 @@ __ioremap_mode(unsigned long offset, unsigned long size, unsigned long flags) { #ifdef CONFIG_SUPERH32 unsigned long last_addr = offset + size - 1; +#endif + void __iomem *ret; + ret = __ioremap_trapped(offset, size); + if (ret) + return ret; + +#ifdef CONFIG_SUPERH32 /* * For P1 and P2 space this is trivial, as everything is already * mapped. Uncached access for P1 addresses are done through P2. diff --git a/include/asm-sh/io_trapped.h b/include/asm-sh/io_trapped.h new file mode 100644 index 00000000000..f1251d4f0ba --- /dev/null +++ b/include/asm-sh/io_trapped.h @@ -0,0 +1,58 @@ +#ifndef __ASM_SH_IO_TRAPPED_H +#define __ASM_SH_IO_TRAPPED_H + +#include <linux/list.h> +#include <linux/ioport.h> +#include <asm/page.h> + +#define IO_TRAPPED_MAGIC 0xfeedbeef + +struct trapped_io { + unsigned int magic; + struct resource *resource; + unsigned int num_resources; + unsigned int minimum_bus_width; + struct list_head list; + void __iomem *virt_base; +} __aligned(PAGE_SIZE); + +#ifdef CONFIG_IO_TRAPPED +int register_trapped_io(struct trapped_io *tiop); +int handle_trapped_io(struct pt_regs *regs, unsigned long address); + +void __iomem *match_trapped_io_handler(struct list_head *list, + unsigned long offset, + unsigned long size); + +#ifdef CONFIG_HAS_IOMEM +extern struct list_head trapped_mem; + +static inline void __iomem * +__ioremap_trapped(unsigned long offset, unsigned long size) +{ + return match_trapped_io_handler(&trapped_mem, offset, size); +} +#else +#define __ioremap_trapped(offset, size) NULL +#endif + +#ifdef CONFIG_HAS_IOPORT +extern struct list_head trapped_io; + +static inline void __iomem * +__ioport_map_trapped(unsigned long offset, unsigned long size) +{ + return match_trapped_io_handler(&trapped_io, offset, size); +} +#else +#define __ioport_map_trapped(offset, size) NULL +#endif + +#else +#define register_trapped_io(tiop) (-1) +#define handle_trapped_io(tiop, address) 0 +#define __ioremap_trapped(offset, size) NULL +#define __ioport_map_trapped(offset, size) NULL +#endif + +#endif /* __ASM_SH_IO_TRAPPED_H */ diff --git a/include/asm-sh/ioctls.h b/include/asm-sh/ioctls.h index 35805df010a..c212c371a4a 100644 --- a/include/asm-sh/ioctls.h +++ b/include/asm-sh/ioctls.h @@ -78,6 +78,10 @@ #define TIOCSBRK _IO('T', 39) /* 0x5427 */ /* BSD compatibility */ #define TIOCCBRK _IO('T', 40) /* 0x5428 */ /* BSD compatibility */ #define TIOCGSID _IOR('T', 41, pid_t) /* 0x5429 */ /* Return the session ID of FD */ +#define TCGETS2 _IOR('T', 42, struct termios2) +#define TCSETS2 _IOW('T', 43, struct termios2) +#define TCSETSW2 _IOW('T', 44, struct termios2) +#define TCSETSF2 _IOW('T', 45, struct termios2) #define TIOCGPTN _IOR('T',0x30, unsigned int) /* Get Pty Number (of pty-mux device) */ #define TIOCSPTLCK _IOW('T',0x31, int) /* Lock/unlock Pty */ diff --git a/include/asm-sh/irq.h b/include/asm-sh/irq.h index 11850f65c92..ca66e5df69d 100644 --- a/include/asm-sh/irq.h +++ b/include/asm-sh/irq.h @@ -50,4 +50,8 @@ extern void irq_ctx_exit(int cpu); # define irq_ctx_exit(cpu) do { } while (0) #endif +#ifdef CONFIG_CPU_SH5 +#include <asm/cpu/irq.h> +#endif + #endif /* __ASM_SH_IRQ_H */ diff --git a/include/asm-sh/mmu_context_64.h b/include/asm-sh/mmu_context_64.h index 020be744b08..9649f1c07ca 100644 --- a/include/asm-sh/mmu_context_64.h +++ b/include/asm-sh/mmu_context_64.h @@ -66,6 +66,9 @@ static inline void set_asid(unsigned long asid) : "=r" (sr), "=r" (pc) : "0" (sr)); } +/* arch/sh/kernel/cpu/sh5/entry.S */ +extern unsigned long switch_and_save_asid(unsigned long new_asid); + /* No spare register to twiddle, so use a software cache */ extern pgd_t *mmu_pdtp_cache; diff --git a/include/asm-sh/page.h b/include/asm-sh/page.h index 134562dc8c4..304c30b5d94 100644 --- a/include/asm-sh/page.h +++ b/include/asm-sh/page.h @@ -55,11 +55,14 @@ extern void clear_page(void *to); extern void copy_page(void *to, void *from); #if !defined(CONFIG_CACHE_OFF) && defined(CONFIG_MMU) && \ - (defined(CONFIG_CPU_SH4) || defined(CONFIG_SH7705_CACHE_32KB)) + (defined(CONFIG_CPU_SH5) || defined(CONFIG_CPU_SH4) || \ + defined(CONFIG_SH7705_CACHE_32KB)) struct page; struct vm_area_struct; extern void clear_user_page(void *to, unsigned long address, struct page *page); -#ifdef CONFIG_CPU_SH4 +extern void copy_user_page(void *to, void *from, unsigned long address, + struct page *page); +#if defined(CONFIG_CPU_SH4) extern void copy_user_highpage(struct page *to, struct page *from, unsigned long vaddr, struct vm_area_struct *vma); #define __HAVE_ARCH_COPY_USER_HIGHPAGE diff --git a/include/asm-sh/pgtable_64.h b/include/asm-sh/pgtable_64.h index 972211671c9..f9dd9d31144 100644 --- a/include/asm-sh/pgtable_64.h +++ b/include/asm-sh/pgtable_64.h @@ -138,6 +138,14 @@ static __inline__ void pmd_set(pmd_t *pmdp,pte_t *ptep) #endif /* + * Stub out _PAGE_SZHUGE if we don't have a good definition for it, + * to make pte_mkhuge() happy. + */ +#ifndef _PAGE_SZHUGE +# define _PAGE_SZHUGE (0) +#endif + +/* * Default flags for a Kernel page. * This is fundametally also SHARED because the main use of this define * (other than for PGD/PMD entries) is for the VMALLOC pool which is @@ -179,6 +187,11 @@ static __inline__ void pmd_set(pmd_t *pmdp,pte_t *ptep) _PAGE_WRITE | _PAGE_EXECUTE) #define PAGE_KERNEL __pgprot(_KERNPG_TABLE) +#define PAGE_KERNEL_NOCACHE \ + __pgprot(_PAGE_PRESENT | _PAGE_READ | _PAGE_WRITE | \ + _PAGE_EXECUTE | _PAGE_ACCESSED | \ + _PAGE_DIRTY | _PAGE_SHARED) + /* Make it a device mapping for maximum safety (e.g. for mapping device registers into user-space via /dev/map). */ #define pgprot_noncached(x) __pgprot(((x).pgprot & ~(_PAGE_CACHABLE)) | _PAGE_DEVICE) diff --git a/include/asm-sh/processor.h b/include/asm-sh/processor.h index c9b14161f73..19fe47c1ca1 100644 --- a/include/asm-sh/processor.h +++ b/include/asm-sh/processor.h @@ -33,7 +33,7 @@ enum cpu_type { CPU_SH7763, CPU_SH7770, CPU_SH7780, CPU_SH7781, CPU_SH7785, CPU_SHX3, /* SH4AL-DSP types */ - CPU_SH7343, CPU_SH7722, + CPU_SH7343, CPU_SH7722, CPU_SH7366, /* SH-5 types */ CPU_SH5_101, CPU_SH5_103, diff --git a/include/asm-sh/r7780rp.h b/include/asm-sh/r7780rp.h index bdecea0840a..1770460a461 100644 --- a/include/asm-sh/r7780rp.h +++ b/include/asm-sh/r7780rp.h @@ -195,7 +195,4 @@ unsigned char *highlander_init_irq_r7780mp(void); unsigned char *highlander_init_irq_r7780rp(void); unsigned char *highlander_init_irq_r7785rp(void); -#define __IO_PREFIX r7780rp -#include <asm/io_generic.h> - #endif /* __ASM_SH_RENESAS_R7780RP */ diff --git a/include/asm-sh/rts7751r2d.h b/include/asm-sh/rts7751r2d.h index 83b9c111f17..0a800157b82 100644 --- a/include/asm-sh/rts7751r2d.h +++ b/include/asm-sh/rts7751r2d.h @@ -67,7 +67,4 @@ void init_rts7751r2d_IRQ(void); int rts7751r2d_irq_demux(int); -#define __IO_PREFIX rts7751r2d -#include <asm/io_generic.h> - #endif /* __ASM_SH_RENESAS_RTS7751R2D */ diff --git a/include/asm-sh/system.h b/include/asm-sh/system.h index 772cd1a0a67..5145aa2a0ce 100644 --- a/include/asm-sh/system.h +++ b/include/asm-sh/system.h @@ -182,6 +182,11 @@ BUILD_TRAP_HANDLER(fpu_state_restore); #define arch_align_stack(x) (x) +struct mem_access { + unsigned long (*from)(void *dst, const void *src, unsigned long cnt); + unsigned long (*to)(void *dst, const void *src, unsigned long cnt); +}; + #ifdef CONFIG_SUPERH32 # include "system_32.h" #else diff --git a/include/asm-sh/system_32.h b/include/asm-sh/system_32.h index 7ff08d956ba..f11bcf0855e 100644 --- a/include/asm-sh/system_32.h +++ b/include/asm-sh/system_32.h @@ -96,4 +96,7 @@ do { \ : "=&r" (__dummy)); \ } while (0) +int handle_unaligned_access(opcode_t instruction, struct pt_regs *regs, + struct mem_access *ma); + #endif /* __ASM_SH_SYSTEM_32_H */ diff --git a/include/asm-sh/termbits.h b/include/asm-sh/termbits.h index 7ee1b42eeab..77db116948c 100644 --- a/include/asm-sh/termbits.h +++ b/include/asm-sh/termbits.h @@ -140,6 +140,7 @@ struct ktermios { #define HUPCL 0002000 #define CLOCAL 0004000 #define CBAUDEX 0010000 +#define BOTHER 0010000 #define B57600 0010001 #define B115200 0010002 #define B230400 0010003 @@ -155,10 +156,12 @@ struct ktermios { #define B3000000 0010015 #define B3500000 0010016 #define B4000000 0010017 -#define CIBAUD 002003600000 /* input baud rate (not used) */ +#define CIBAUD 002003600000 /* input baud rate */ #define CMSPAR 010000000000 /* mark or space (stick) parity */ #define CRTSCTS 020000000000 /* flow control */ +#define IBSHIFT 16 /* Shift from CBAUD to CIBAUD */ + /* c_lflag bits */ #define ISIG 0000001 #define ICANON 0000002 diff --git a/include/asm-sh/termios.h b/include/asm-sh/termios.h index e7c8f86ef89..0a8c793c76f 100644 --- a/include/asm-sh/termios.h +++ b/include/asm-sh/termios.h @@ -80,8 +80,10 @@ struct termio { copy_to_user((termio)->c_cc, (termios)->c_cc, NCC); \ }) -#define user_termios_to_kernel_termios(k, u) copy_from_user(k, u, sizeof(struct termios)) -#define kernel_termios_to_user_termios(u, k) copy_to_user(u, k, sizeof(struct termios)) +#define user_termios_to_kernel_termios(k, u) copy_from_user(k, u, sizeof(struct termios2)) +#define kernel_termios_to_user_termios(u, k) copy_to_user(u, k, sizeof(struct termios2)) +#define user_termios_to_kernel_termios_1(k, u) copy_from_user(k, u, sizeof(struct termios)) +#define kernel_termios_to_user_termios_1(u, k) copy_to_user(u, k, sizeof(struct termios)) #endif /* __KERNEL__ */ diff --git a/include/asm-sh/tlb.h b/include/asm-sh/tlb.h index 56ad1fb888a..88ff1ae8a6b 100644 --- a/include/asm-sh/tlb.h +++ b/include/asm-sh/tlb.h @@ -20,6 +20,7 @@ */ #define tlb_flush(tlb) flush_tlb_mm((tlb)->mm) +#include <linux/pagemap.h> #include <asm-generic/tlb.h> #endif /* __ASSEMBLY__ */ diff --git a/include/asm-sh/uaccess.h b/include/asm-sh/uaccess.h index ff24ce95b23..b3440c305b5 100644 --- a/include/asm-sh/uaccess.h +++ b/include/asm-sh/uaccess.h @@ -1,5 +1,34 @@ +#ifndef __ASM_SH_UACCESS_H +#define __ASM_SH_UACCESS_H + #ifdef CONFIG_SUPERH32 # include "uaccess_32.h" #else # include "uaccess_64.h" #endif + +static inline unsigned long +copy_from_user(void *to, const void __user *from, unsigned long n) +{ + unsigned long __copy_from = (unsigned long) from; + __kernel_size_t __copy_size = (__kernel_size_t) n; + + if (__copy_size && __access_ok(__copy_from, __copy_size)) + return __copy_user(to, from, __copy_size); + + return __copy_size; +} + +static inline unsigned long +copy_to_user(void __user *to, const void *from, unsigned long n) +{ + unsigned long __copy_to = (unsigned long) to; + __kernel_size_t __copy_size = (__kernel_size_t) n; + + if (__copy_size && __access_ok(__copy_to, __copy_size)) + return __copy_user(to, from, __copy_size); + + return __copy_size; +} + +#endif /* __ASM_SH_UACCESS_H */ diff --git a/include/asm-sh/uaccess_32.h b/include/asm-sh/uaccess_32.h index b6082f3c1dc..c0318b60889 100644 --- a/include/asm-sh/uaccess_32.h +++ b/include/asm-sh/uaccess_32.h @@ -10,8 +10,8 @@ * Copyright (C) 1996, 1997, 1998 by Ralf Baechle * and i386 version. */ -#ifndef __ASM_SH_UACCESS_H -#define __ASM_SH_UACCESS_H +#ifndef __ASM_SH_UACCESS_32_H +#define __ASM_SH_UACCESS_32_H #include <linux/errno.h> #include <linux/sched.h> @@ -302,24 +302,6 @@ extern void __put_user_unknown(void); /* Return the number of bytes NOT copied */ __kernel_size_t __copy_user(void *to, const void *from, __kernel_size_t n); -#define copy_to_user(to,from,n) ({ \ -void *__copy_to = (void *) (to); \ -__kernel_size_t __copy_size = (__kernel_size_t) (n); \ -__kernel_size_t __copy_res; \ -if(__copy_size && __access_ok((unsigned long)__copy_to, __copy_size)) { \ -__copy_res = __copy_user(__copy_to, (void *) (from), __copy_size); \ -} else __copy_res = __copy_size; \ -__copy_res; }) - -#define copy_from_user(to,from,n) ({ \ -void *__copy_to = (void *) (to); \ -void *__copy_from = (void *) (from); \ -__kernel_size_t __copy_size = (__kernel_size_t) (n); \ -__kernel_size_t __copy_res; \ -if(__copy_size && __access_ok((unsigned long)__copy_from, __copy_size)) { \ -__copy_res = __copy_user(__copy_to, __copy_from, __copy_size); \ -} else __copy_res = __copy_size; \ -__copy_res; }) static __always_inline unsigned long __copy_from_user(void *to, const void __user *from, unsigned long n) @@ -507,4 +489,4 @@ struct exception_table_entry extern int fixup_exception(struct pt_regs *regs); -#endif /* __ASM_SH_UACCESS_H */ +#endif /* __ASM_SH_UACCESS_32_H */ diff --git a/include/asm-sh/uaccess_64.h b/include/asm-sh/uaccess_64.h index d54ec082d25..f956b7b316c 100644 --- a/include/asm-sh/uaccess_64.h +++ b/include/asm-sh/uaccess_64.h @@ -202,15 +202,6 @@ extern void __put_user_unknown(void); /* XXX: should be such that: 4byte and the rest. */ extern __kernel_size_t __copy_user(void *__to, const void *__from, __kernel_size_t __n); -#define copy_to_user(to,from,n) ({ \ -void *__copy_to = (void *) (to); \ -__kernel_size_t __copy_size = (__kernel_size_t) (n); \ -__kernel_size_t __copy_res; \ -if(__copy_size && __access_ok((unsigned long)__copy_to, __copy_size)) { \ -__copy_res = __copy_user(__copy_to, (void *) (from), __copy_size); \ -} else __copy_res = __copy_size; \ -__copy_res; }) - #define copy_to_user_ret(to,from,n,retval) ({ \ if (copy_to_user(to,from,n)) \ return retval; \ @@ -225,16 +216,6 @@ if (__copy_to_user(to,from,n)) \ return retval; \ }) -#define copy_from_user(to,from,n) ({ \ -void *__copy_to = (void *) (to); \ -void *__copy_from = (void *) (from); \ -__kernel_size_t __copy_size = (__kernel_size_t) (n); \ -__kernel_size_t __copy_res; \ -if(__copy_size && __access_ok((unsigned long)__copy_from, __copy_size)) { \ -__copy_res = __copy_user(__copy_to, __copy_from, __copy_size); \ -} else __copy_res = __copy_size; \ -__copy_res; }) - #define copy_from_user_ret(to,from,n,retval) ({ \ if (copy_from_user(to,from,n)) \ return retval; \ diff --git a/include/asm-sh/unistd_32.h b/include/asm-sh/unistd_32.h index 433fd1b48fa..0b07212ec65 100644 --- a/include/asm-sh/unistd_32.h +++ b/include/asm-sh/unistd_32.h @@ -330,11 +330,13 @@ #define __NR_epoll_pwait 319 #define __NR_utimensat 320 #define __NR_signalfd 321 -/* #define __NR_timerfd 322 removed */ +#define __NR_timerfd_create 322 #define __NR_eventfd 323 #define __NR_fallocate 324 +#define __NR_timerfd_settime 325 +#define __NR_timerfd_gettime 326 -#define NR_syscalls 325 +#define NR_syscalls 327 #ifdef __KERNEL__ diff --git a/include/asm-sh/unistd_64.h b/include/asm-sh/unistd_64.h index 108d2ba897f..9d21eab5242 100644 --- a/include/asm-sh/unistd_64.h +++ b/include/asm-sh/unistd_64.h @@ -90,7 +90,7 @@ #define __NR_sigpending 73 #define __NR_sethostname 74 #define __NR_setrlimit 75 -#define __NR_getrlimit 76 /* Back compatible 2Gig limited rlimit */ +#define __NR_getrlimit 76 /* Back compatible 2Gig limited rlimit */ #define __NR_getrusage 77 #define __NR_gettimeofday 78 #define __NR_settimeofday 79 @@ -370,9 +370,11 @@ #define __NR_epoll_pwait 347 #define __NR_utimensat 348 #define __NR_signalfd 349 -/* #define __NR_timerfd 350 removed */ +#define __NR_timerfd_create 350 #define __NR_eventfd 351 #define __NR_fallocate 352 +#define __NR_timerfd_settime 353 +#define __NR_timerfd_gettime 354 #ifdef __KERNEL__ diff --git a/include/asm-x86/cacheflush.h b/include/asm-x86/cacheflush.h index 6a22212b4b2..5396c212d8c 100644 --- a/include/asm-x86/cacheflush.h +++ b/include/asm-x86/cacheflush.h @@ -48,12 +48,15 @@ void cpa_init(void); #ifdef CONFIG_DEBUG_RODATA void mark_rodata_ro(void); +extern const int rodata_test_data; #endif + #ifdef CONFIG_DEBUG_RODATA_TEST -void rodata_test(void); +int rodata_test(void); #else -static inline void rodata_test(void) +static inline int rodata_test(void) { + return 0; } #endif diff --git a/include/asm-x86/kdebug.h b/include/asm-x86/kdebug.h index dd442a1632c..99dcbafa151 100644 --- a/include/asm-x86/kdebug.h +++ b/include/asm-x86/kdebug.h @@ -31,7 +31,6 @@ extern void show_trace(struct task_struct *t, struct pt_regs *regs, unsigned long *sp, unsigned long bp); extern void __show_regs(struct pt_regs *regs); extern void show_regs(struct pt_regs *regs); -extern void dump_pagetable(unsigned long); extern unsigned long oops_begin(void); extern void oops_end(unsigned long, struct pt_regs *, int signr); diff --git a/include/asm-x86/pgtable_64.h b/include/asm-x86/pgtable_64.h index bd4740a60f2..7fd5e0e2361 100644 --- a/include/asm-x86/pgtable_64.h +++ b/include/asm-x86/pgtable_64.h @@ -246,6 +246,7 @@ static inline int pud_large(pud_t pte) #define __swp_entry_to_pte(x) ((pte_t) { .pte = (x).val }) extern int kern_addr_valid(unsigned long addr); +extern void cleanup_highmap(void); #define io_remap_pfn_range(vma, vaddr, pfn, size, prot) \ remap_pfn_range(vma, vaddr, pfn, size, prot) diff --git a/include/asm-x86/sigcontext.h b/include/asm-x86/sigcontext.h index 681deade5f0..d743947f4c7 100644 --- a/include/asm-x86/sigcontext.h +++ b/include/asm-x86/sigcontext.h @@ -58,6 +58,7 @@ struct _fpstate { #define X86_FXSR_MAGIC 0x0000 +#ifdef __KERNEL__ struct sigcontext { unsigned short gs, __gsh; unsigned short fs, __fsh; @@ -82,6 +83,35 @@ struct sigcontext { unsigned long oldmask; unsigned long cr2; }; +#else /* __KERNEL__ */ +/* + * User-space might still rely on the old definition: + */ +struct sigcontext { + unsigned short gs, __gsh; + unsigned short fs, __fsh; + unsigned short es, __esh; + unsigned short ds, __dsh; + unsigned long edi; + unsigned long esi; + unsigned long ebp; + unsigned long esp; + unsigned long ebx; + unsigned long edx; + unsigned long ecx; + unsigned long eax; + unsigned long trapno; + unsigned long err; + unsigned long eip; + unsigned short cs, __csh; + unsigned long eflags; + unsigned long esp_at_signal; + unsigned short ss, __ssh; + struct _fpstate __user * fpstate; + unsigned long oldmask; + unsigned long cr2; +}; +#endif /* !__KERNEL__ */ #else /* __i386__ */ @@ -102,6 +132,7 @@ struct _fpstate { __u32 reserved2[24]; }; +#ifdef __KERNEL__ struct sigcontext { unsigned long r8; unsigned long r9; @@ -132,6 +163,41 @@ struct sigcontext { struct _fpstate __user *fpstate; /* zero when no FPU context */ unsigned long reserved1[8]; }; +#else /* __KERNEL__ */ +/* + * User-space might still rely on the old definition: + */ +struct sigcontext { + unsigned long r8; + unsigned long r9; + unsigned long r10; + unsigned long r11; + unsigned long r12; + unsigned long r13; + unsigned long r14; + unsigned long r15; + unsigned long rdi; + unsigned long rsi; + unsigned long rbp; + unsigned long rbx; + unsigned long rdx; + unsigned long rax; + unsigned long rcx; + unsigned long rsp; + unsigned long rip; + unsigned long eflags; /* RFLAGS */ + unsigned short cs; + unsigned short gs; + unsigned short fs; + unsigned short __pad0; + unsigned long err; + unsigned long trapno; + unsigned long oldmask; + unsigned long cr2; + struct _fpstate __user *fpstate; /* zero when no FPU context */ + unsigned long reserved1[8]; +}; +#endif /* !__KERNEL__ */ #endif /* !__i386__ */ diff --git a/include/linux/Kbuild b/include/linux/Kbuild index 5cae9b5960e..aada32fffec 100644 --- a/include/linux/Kbuild +++ b/include/linux/Kbuild @@ -70,7 +70,6 @@ header-y += fuse.h header-y += genetlink.h header-y += gen_stats.h header-y += gigaset_dev.h -header-y += hdsmart.h header-y += hysdn_if.h header-y += i2o-dev.h header-y += i8k.h @@ -211,6 +210,7 @@ unifdef-y += hayesesp.h unifdef-y += hdlcdrv.h unifdef-y += hdlc.h unifdef-y += hdreg.h +unifdef-y += hdsmart.h unifdef-y += hiddev.h unifdef-y += hpet.h unifdef-y += i2c.h diff --git a/include/linux/acpi.h b/include/linux/acpi.h index ddbe7efe590..2c7e003356a 100644 --- a/include/linux/acpi.h +++ b/include/linux/acpi.h @@ -203,6 +203,7 @@ extern bool wmi_has_guid(const char *guid); extern int acpi_blacklisted(void); #ifdef CONFIG_DMI extern void acpi_dmi_osi_linux(int enable, const struct dmi_system_id *d); +extern int acpi_osi_setup(char *str); #endif #ifdef CONFIG_ACPI_NUMA diff --git a/include/linux/aio.h b/include/linux/aio.h index 7ef8de66200..a9931e2e562 100644 --- a/include/linux/aio.h +++ b/include/linux/aio.h @@ -206,21 +206,21 @@ struct kioctx { /* prototypes */ extern unsigned aio_max_size; -extern ssize_t FASTCALL(wait_on_sync_kiocb(struct kiocb *iocb)); -extern int FASTCALL(aio_put_req(struct kiocb *iocb)); -extern void FASTCALL(kick_iocb(struct kiocb *iocb)); -extern int FASTCALL(aio_complete(struct kiocb *iocb, long res, long res2)); -extern void FASTCALL(__put_ioctx(struct kioctx *ctx)); +extern ssize_t wait_on_sync_kiocb(struct kiocb *iocb); +extern int aio_put_req(struct kiocb *iocb); +extern void kick_iocb(struct kiocb *iocb); +extern int aio_complete(struct kiocb *iocb, long res, long res2); +extern void __put_ioctx(struct kioctx *ctx); struct mm_struct; -extern void FASTCALL(exit_aio(struct mm_struct *mm)); +extern void exit_aio(struct mm_struct *mm); extern struct kioctx *lookup_ioctx(unsigned long ctx_id); -extern int FASTCALL(io_submit_one(struct kioctx *ctx, - struct iocb __user *user_iocb, struct iocb *iocb)); +extern int io_submit_one(struct kioctx *ctx, struct iocb __user *user_iocb, + struct iocb *iocb); /* semi private, but used by the 32bit emulations: */ struct kioctx *lookup_ioctx(unsigned long ctx_id); -int FASTCALL(io_submit_one(struct kioctx *ctx, struct iocb __user *user_iocb, - struct iocb *iocb)); +int io_submit_one(struct kioctx *ctx, struct iocb __user *user_iocb, + struct iocb *iocb); #define get_ioctx(kioctx) do { \ BUG_ON(atomic_read(&(kioctx)->users) <= 0); \ diff --git a/include/linux/audit.h b/include/linux/audit.h index 97153027207..2af9ec02501 100644 --- a/include/linux/audit.h +++ b/include/linux/audit.h @@ -534,8 +534,7 @@ extern void audit_log_n_untrustedstring(struct audit_buffer *ab, const char *string); extern void audit_log_d_path(struct audit_buffer *ab, const char *prefix, - struct dentry *dentry, - struct vfsmount *vfsmnt); + struct path *path); extern void audit_log_lost(const char *message); /* Private API (for audit.c only) */ extern int audit_filter_user(struct netlink_skb_parms *cb, int type); @@ -552,7 +551,7 @@ extern int audit_enabled; #define audit_log_hex(a,b,l) do { ; } while (0) #define audit_log_untrustedstring(a,s) do { ; } while (0) #define audit_log_n_untrustedstring(a,n,s) do { ; } while (0) -#define audit_log_d_path(b,p,d,v) do { ; } while (0) +#define audit_log_d_path(b, p, d) do { ; } while (0) #define audit_enabled 0 #endif #endif diff --git a/include/linux/buffer_head.h b/include/linux/buffer_head.h index e98801f06dc..932eb02a275 100644 --- a/include/linux/buffer_head.h +++ b/include/linux/buffer_head.h @@ -144,7 +144,7 @@ BUFFER_FNS(Unwritten, unwritten) * Declarations */ -void FASTCALL(mark_buffer_dirty(struct buffer_head *bh)); +void mark_buffer_dirty(struct buffer_head *bh); void init_buffer(struct buffer_head *, bh_end_io_t *, void *); void set_bh_page(struct buffer_head *bh, struct page *page, unsigned long offset); @@ -185,8 +185,8 @@ struct buffer_head *__bread(struct block_device *, sector_t block, unsigned size void invalidate_bh_lrus(void); struct buffer_head *alloc_buffer_head(gfp_t gfp_flags); void free_buffer_head(struct buffer_head * bh); -void FASTCALL(unlock_buffer(struct buffer_head *bh)); -void FASTCALL(__lock_buffer(struct buffer_head *bh)); +void unlock_buffer(struct buffer_head *bh); +void __lock_buffer(struct buffer_head *bh); void ll_rw_block(int, int, struct buffer_head * bh[]); int sync_dirty_buffer(struct buffer_head *bh); int submit_bh(int, struct buffer_head *); diff --git a/include/linux/cgroup_subsys.h b/include/linux/cgroup_subsys.h index 228235c5ae5..ac6aad98b60 100644 --- a/include/linux/cgroup_subsys.h +++ b/include/linux/cgroup_subsys.h @@ -25,7 +25,7 @@ SUBSYS(ns) /* */ -#ifdef CONFIG_FAIR_CGROUP_SCHED +#ifdef CONFIG_CGROUP_SCHED SUBSYS(cpu_cgroup) #endif diff --git a/include/linux/configfs.h b/include/linux/configfs.h index 8c6967f3fb1..4b287ad9371 100644 --- a/include/linux/configfs.h +++ b/include/linux/configfs.h @@ -37,6 +37,7 @@ #ifdef __KERNEL__ +#include <linux/kernel.h> #include <linux/types.h> #include <linux/list.h> #include <linux/kref.h> diff --git a/include/linux/cpuidle.h b/include/linux/cpuidle.h index 385d45b616d..6b72a458408 100644 --- a/include/linux/cpuidle.h +++ b/include/linux/cpuidle.h @@ -19,6 +19,7 @@ #define CPUIDLE_STATE_MAX 8 #define CPUIDLE_NAME_LEN 16 +#define CPUIDLE_DESC_LEN 32 struct cpuidle_device; @@ -29,6 +30,7 @@ struct cpuidle_device; struct cpuidle_state { char name[CPUIDLE_NAME_LEN]; + char desc[CPUIDLE_DESC_LEN]; void *driver_data; unsigned int flags; diff --git a/include/linux/dcache.h b/include/linux/dcache.h index c2c153f97e8..6bd646096fa 100644 --- a/include/linux/dcache.h +++ b/include/linux/dcache.h @@ -10,6 +10,7 @@ #include <linux/rcupdate.h> struct nameidata; +struct path; struct vfsmount; /* @@ -300,8 +301,8 @@ extern int d_validate(struct dentry *, struct dentry *); */ extern char *dynamic_dname(struct dentry *, char *, int, const char *, ...); -extern char * d_path(struct dentry *, struct vfsmount *, char *, int); - +extern char *d_path(struct path *, char *, int); + /* Allocation counts.. */ /** diff --git a/include/linux/dcookies.h b/include/linux/dcookies.h index 98c69ab80c8..24c806f12a6 100644 --- a/include/linux/dcookies.h +++ b/include/linux/dcookies.h @@ -13,6 +13,7 @@ #ifdef CONFIG_PROFILING #include <linux/dcache.h> +#include <linux/path.h> #include <linux/types.h> struct dcookie_user; @@ -43,8 +44,7 @@ void dcookie_unregister(struct dcookie_user * user); * * Returns 0 on success, with *cookie filled in */ -int get_dcookie(struct dentry * dentry, struct vfsmount * vfsmnt, - unsigned long * cookie); +int get_dcookie(struct path *path, unsigned long *cookie); #else @@ -57,13 +57,12 @@ static inline void dcookie_unregister(struct dcookie_user * user) { return; } - -static inline int get_dcookie(struct dentry * dentry, - struct vfsmount * vfsmnt, unsigned long * cookie) + +static inline int get_dcookie(struct path *path, unsigned long *cookie) { return -ENOSYS; -} - +} + #endif /* CONFIG_PROFILING */ - + #endif /* DCOOKIES_H */ diff --git a/include/linux/dm9000.h b/include/linux/dm9000.h index 0008e2ad0c9..a3750462f9e 100644 --- a/include/linux/dm9000.h +++ b/include/linux/dm9000.h @@ -19,6 +19,8 @@ #define DM9000_PLATF_8BITONLY (0x0001) #define DM9000_PLATF_16BITONLY (0x0002) #define DM9000_PLATF_32BITONLY (0x0004) +#define DM9000_PLATF_EXT_PHY (0x0008) +#define DM9000_PLATF_NO_EEPROM (0x0010) /* platfrom data for platfrom device structure's platfrom_data field */ diff --git a/include/linux/etherdevice.h b/include/linux/etherdevice.h index b7558ec81ed..25d62e6e329 100644 --- a/include/linux/etherdevice.h +++ b/include/linux/etherdevice.h @@ -70,8 +70,7 @@ static inline int is_multicast_ether_addr(const u8 *addr) } /** - * is_local_ether_addr - Determine if the Ethernet address is locally-assigned - * one (IEEE 802). + * is_local_ether_addr - Determine if the Ethernet address is locally-assigned one (IEEE 802). * @addr: Pointer to a six-byte array containing the Ethernet address * * Return true if the address is a local address. diff --git a/include/linux/file.h b/include/linux/file.h index 56023c74e9f..7239baac81a 100644 --- a/include/linux/file.h +++ b/include/linux/file.h @@ -59,8 +59,8 @@ struct files_struct { extern struct kmem_cache *filp_cachep; -extern void FASTCALL(__fput(struct file *)); -extern void FASTCALL(fput(struct file *)); +extern void __fput(struct file *); +extern void fput(struct file *); struct file_operations; struct vfsmount; @@ -77,13 +77,13 @@ static inline void fput_light(struct file *file, int fput_needed) fput(file); } -extern struct file * FASTCALL(fget(unsigned int fd)); -extern struct file * FASTCALL(fget_light(unsigned int fd, int *fput_needed)); -extern void FASTCALL(set_close_on_exec(unsigned int fd, int flag)); +extern struct file *fget(unsigned int fd); +extern struct file *fget_light(unsigned int fd, int *fput_needed); +extern void set_close_on_exec(unsigned int fd, int flag); extern void put_filp(struct file *); extern int get_unused_fd(void); extern int get_unused_fd_flags(int flags); -extern void FASTCALL(put_unused_fd(unsigned int fd)); +extern void put_unused_fd(unsigned int fd); struct kmem_cache; extern int expand_files(struct files_struct *, int nr); @@ -110,12 +110,12 @@ static inline struct file * fcheck_files(struct files_struct *files, unsigned in */ #define fcheck(fd) fcheck_files(current->files, fd) -extern void FASTCALL(fd_install(unsigned int fd, struct file * file)); +extern void fd_install(unsigned int fd, struct file *file); struct task_struct; struct files_struct *get_files_struct(struct task_struct *); -void FASTCALL(put_files_struct(struct files_struct *fs)); +void put_files_struct(struct files_struct *fs); void reset_files_struct(struct task_struct *, struct files_struct *); extern struct kmem_cache *files_cachep; diff --git a/include/linux/fs.h b/include/linux/fs.h index 18cfbf76ec5..98ffb6ead43 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -1284,8 +1284,10 @@ struct super_operations { * * I_DIRTY_SYNC Inode is dirty, but doesn't have to be written on * fdatasync(). i_atime is the usual cause. - * I_DIRTY_DATASYNC Inode is dirty and must be written on fdatasync(), f.e. - * because i_size changed. + * I_DIRTY_DATASYNC Data-related inode changes pending. We keep track of + * these changes separately from I_DIRTY_SYNC so that we + * don't have to write inode on fdatasync() when only + * mtime has changed in it. * I_DIRTY_PAGES Inode has dirty pages. Inode itself may be clean. * I_NEW get_new_inode() sets i_state to I_LOCK|I_NEW. Both * are cleared by unlock_new_inode(), called from iget(). diff --git a/include/linux/fs_struct.h b/include/linux/fs_struct.h index 11a36ceddf7..282f5421912 100644 --- a/include/linux/fs_struct.h +++ b/include/linux/fs_struct.h @@ -1,15 +1,13 @@ #ifndef _LINUX_FS_STRUCT_H #define _LINUX_FS_STRUCT_H -struct dentry; -struct vfsmount; +#include <linux/path.h> struct fs_struct { atomic_t count; rwlock_t lock; int umask; - struct dentry * root, * pwd, * altroot; - struct vfsmount * rootmnt, * pwdmnt, * altrootmnt; + struct path root, pwd, altroot; }; #define INIT_FS { \ @@ -22,8 +20,8 @@ extern struct kmem_cache *fs_cachep; extern void exit_fs(struct task_struct *); extern void set_fs_altroot(void); -extern void set_fs_root(struct fs_struct *, struct vfsmount *, struct dentry *); -extern void set_fs_pwd(struct fs_struct *, struct vfsmount *, struct dentry *); +extern void set_fs_root(struct fs_struct *, struct path *); +extern void set_fs_pwd(struct fs_struct *, struct path *); extern struct fs_struct *copy_fs_struct(struct fs_struct *); extern void put_fs_struct(struct fs_struct *); diff --git a/include/linux/gfp.h b/include/linux/gfp.h index 0c6ce515185..164be9da3c1 100644 --- a/include/linux/gfp.h +++ b/include/linux/gfp.h @@ -172,8 +172,7 @@ static inline void arch_free_page(struct page *page, int order) { } static inline void arch_alloc_page(struct page *page, int order) { } #endif -extern struct page * -FASTCALL(__alloc_pages(gfp_t, unsigned int, struct zonelist *)); +extern struct page *__alloc_pages(gfp_t, unsigned int, struct zonelist *); static inline struct page *alloc_pages_node(int nid, gfp_t gfp_mask, unsigned int order) @@ -209,8 +208,8 @@ extern struct page *alloc_page_vma(gfp_t gfp_mask, #endif #define alloc_page(gfp_mask) alloc_pages(gfp_mask, 0) -extern unsigned long FASTCALL(__get_free_pages(gfp_t gfp_mask, unsigned int order)); -extern unsigned long FASTCALL(get_zeroed_page(gfp_t gfp_mask)); +extern unsigned long __get_free_pages(gfp_t gfp_mask, unsigned int order); +extern unsigned long get_zeroed_page(gfp_t gfp_mask); #define __get_free_page(gfp_mask) \ __get_free_pages((gfp_mask),0) @@ -218,10 +217,10 @@ extern unsigned long FASTCALL(get_zeroed_page(gfp_t gfp_mask)); #define __get_dma_pages(gfp_mask, order) \ __get_free_pages((gfp_mask) | GFP_DMA,(order)) -extern void FASTCALL(__free_pages(struct page *page, unsigned int order)); -extern void FASTCALL(free_pages(unsigned long addr, unsigned int order)); -extern void FASTCALL(free_hot_page(struct page *page)); -extern void FASTCALL(free_cold_page(struct page *page)); +extern void __free_pages(struct page *page, unsigned int order); +extern void free_pages(unsigned long addr, unsigned int order); +extern void free_hot_page(struct page *page); +extern void free_cold_page(struct page *page); #define __free_page(page) __free_pages((page), 0) #define free_page(addr) free_pages((addr),0) diff --git a/include/linux/hdsmart.h b/include/linux/hdsmart.h index e69192159d4..4f4faf9d423 100644 --- a/include/linux/hdsmart.h +++ b/include/linux/hdsmart.h @@ -17,7 +17,7 @@ #ifndef _LINUX_HDSMART_H #define _LINUX_HDSMART_H -#ifndef __KERNEL +#ifndef __KERNEL__ #define OFFLINE_FULL_SCAN 0 #define SHORT_SELF_TEST 1 #define EXTEND_SELF_TEST 2 @@ -121,6 +121,6 @@ typedef struct ata_smart_selftestlog_s { unsigned char resevered[2]; unsigned char chksum; } __attribute__ ((packed)) ata_smart_selftestlog_t; -#endif /* __KERNEL__ * +#endif /* __KERNEL__ */ #endif /* _LINUX_HDSMART_H */ diff --git a/include/linux/hid.h b/include/linux/hid.h index 3902690647b..74ff57596eb 100644 --- a/include/linux/hid.h +++ b/include/linux/hid.h @@ -528,7 +528,7 @@ int hid_set_field(struct hid_field *, unsigned, __s32); int hid_input_report(struct hid_device *, int type, u8 *, int, int); int hidinput_find_field(struct hid_device *hid, unsigned int type, unsigned int code, struct hid_field **field); int hidinput_mapping_quirks(struct hid_usage *, struct input_dev *, unsigned long **, int *); -void hidinput_event_quirks(struct hid_device *, struct hid_field *, struct hid_usage *, __s32); +int hidinput_event_quirks(struct hid_device *, struct hid_field *, struct hid_usage *, __s32); int hidinput_apple_event(struct hid_device *, struct input_dev *, struct hid_usage *, __s32); void hid_input_field(struct hid_device *hid, struct hid_field *field, __u8 *data, int interrupt); void hid_output_report(struct hid_report *report, __u8 *data); diff --git a/include/linux/hugetlb.h b/include/linux/hugetlb.h index 7ca198b379a..addca4cd4f1 100644 --- a/include/linux/hugetlb.h +++ b/include/linux/hugetlb.h @@ -33,8 +33,8 @@ int hugetlb_reserve_pages(struct inode *inode, long from, long to); void hugetlb_unreserve_pages(struct inode *inode, long offset, long freed); extern unsigned long max_huge_pages; +extern unsigned long sysctl_overcommit_huge_pages; extern unsigned long hugepages_treat_as_movable; -extern unsigned long nr_overcommit_huge_pages; extern const unsigned long hugetlb_zero, hugetlb_infinity; extern int sysctl_hugetlb_shm_group; diff --git a/include/linux/if_ether.h b/include/linux/if_ether.h index e157c1399b6..42dc6a3571e 100644 --- a/include/linux/if_ether.h +++ b/include/linux/if_ether.h @@ -129,8 +129,7 @@ extern ssize_t sysfs_format_mac(char *buf, const unsigned char *addr, int len); /* * Display a 6 byte device address (MAC) in a readable format. */ -extern char *print_mac(char *buf, const unsigned char *addr); -#define MAC_FMT "%02x:%02x:%02x:%02x:%02x:%02x" +extern __pure char *print_mac(char *buf, const unsigned char *addr); #define MAC_BUF_SIZE 18 #define DECLARE_MAC_BUF(var) char var[MAC_BUF_SIZE] __maybe_unused diff --git a/include/linux/interrupt.h b/include/linux/interrupt.h index dea7598aeff..f8ab4ce7056 100644 --- a/include/linux/interrupt.h +++ b/include/linux/interrupt.h @@ -273,8 +273,8 @@ asmlinkage void do_softirq(void); extern void open_softirq(int nr, void (*action)(struct softirq_action*), void *data); extern void softirq_init(void); #define __raise_softirq_irqoff(nr) do { or_softirq_pending(1UL << (nr)); } while (0) -extern void FASTCALL(raise_softirq_irqoff(unsigned int nr)); -extern void FASTCALL(raise_softirq(unsigned int nr)); +extern void raise_softirq_irqoff(unsigned int nr); +extern void raise_softirq(unsigned int nr); /* Tasklets --- multithreaded analogue of BHs. @@ -341,7 +341,7 @@ static inline void tasklet_unlock_wait(struct tasklet_struct *t) #define tasklet_unlock(t) do { } while (0) #endif -extern void FASTCALL(__tasklet_schedule(struct tasklet_struct *t)); +extern void __tasklet_schedule(struct tasklet_struct *t); static inline void tasklet_schedule(struct tasklet_struct *t) { @@ -349,7 +349,7 @@ static inline void tasklet_schedule(struct tasklet_struct *t) __tasklet_schedule(t); } -extern void FASTCALL(__tasklet_hi_schedule(struct tasklet_struct *t)); +extern void __tasklet_hi_schedule(struct tasklet_struct *t); static inline void tasklet_hi_schedule(struct tasklet_struct *t) { diff --git a/include/linux/irq.h b/include/linux/irq.h index bfd9efb5cb4..176e5e790a4 100644 --- a/include/linux/irq.h +++ b/include/linux/irq.h @@ -285,7 +285,6 @@ extern void handle_bad_irq(unsigned int irq, struct irq_desc *desc); /* * Monolithic do_IRQ implementation. - * (is an explicit fastcall, because i386 4KSTACKS calls it from assembly) */ #ifndef CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ extern unsigned int __do_IRQ(unsigned int irq); diff --git a/include/linux/ktime.h b/include/linux/ktime.h index 36c542b70c6..2cd7fa73d1a 100644 --- a/include/linux/ktime.h +++ b/include/linux/ktime.h @@ -310,6 +310,8 @@ static inline ktime_t ktime_sub_us(const ktime_t kt, const u64 usec) return ktime_sub_ns(kt, usec * 1000); } +extern ktime_t ktime_add_safe(const ktime_t lhs, const ktime_t rhs); + /* * The resolution of the clocks. The resolution value is returned in * the clock_getres() system call to give application programmers an diff --git a/include/linux/linkage.h b/include/linux/linkage.h index 3faf599ea58..0592936344c 100644 --- a/include/linux/linkage.h +++ b/include/linux/linkage.h @@ -73,9 +73,4 @@ #define ATTRIB_NORET __attribute__((noreturn)) #define NORET_AND noreturn, -#ifndef FASTCALL -#define FASTCALL(x) x -#define fastcall -#endif - #endif diff --git a/include/linux/maple.h b/include/linux/maple.h index bad9a7b319d..3f01e2bae1a 100644 --- a/include/linux/maple.h +++ b/include/linux/maple.h @@ -7,74 +7,74 @@ extern struct bus_type maple_bus_type; /* Maple Bus command and response codes */ enum maple_code { - MAPLE_RESPONSE_FILEERR = -5, - MAPLE_RESPONSE_AGAIN = -4, /* request should be retransmitted */ - MAPLE_RESPONSE_BADCMD = -3, - MAPLE_RESPONSE_BADFUNC = -2, - MAPLE_RESPONSE_NONE = -1, /* unit didn't respond at all */ - MAPLE_COMMAND_DEVINFO = 1, - MAPLE_COMMAND_ALLINFO = 2, - MAPLE_COMMAND_RESET = 3, - MAPLE_COMMAND_KILL = 4, - MAPLE_RESPONSE_DEVINFO = 5, - MAPLE_RESPONSE_ALLINFO = 6, - MAPLE_RESPONSE_OK = 7, - MAPLE_RESPONSE_DATATRF = 8, - MAPLE_COMMAND_GETCOND = 9, - MAPLE_COMMAND_GETMINFO = 10, - MAPLE_COMMAND_BREAD = 11, - MAPLE_COMMAND_BWRITE = 12, - MAPLE_COMMAND_SETCOND = 14 + MAPLE_RESPONSE_FILEERR = -5, + MAPLE_RESPONSE_AGAIN = -4, /* request should be retransmitted */ + MAPLE_RESPONSE_BADCMD = -3, + MAPLE_RESPONSE_BADFUNC = -2, + MAPLE_RESPONSE_NONE = -1, /* unit didn't respond at all */ + MAPLE_COMMAND_DEVINFO = 1, + MAPLE_COMMAND_ALLINFO = 2, + MAPLE_COMMAND_RESET = 3, + MAPLE_COMMAND_KILL = 4, + MAPLE_RESPONSE_DEVINFO = 5, + MAPLE_RESPONSE_ALLINFO = 6, + MAPLE_RESPONSE_OK = 7, + MAPLE_RESPONSE_DATATRF = 8, + MAPLE_COMMAND_GETCOND = 9, + MAPLE_COMMAND_GETMINFO = 10, + MAPLE_COMMAND_BREAD = 11, + MAPLE_COMMAND_BWRITE = 12, + MAPLE_COMMAND_SETCOND = 14 }; struct mapleq { - struct list_head list; - struct maple_device *dev; - void *sendbuf, *recvbuf, *recvbufdcsp; - unsigned char length; - enum maple_code command; + struct list_head list; + struct maple_device *dev; + void *sendbuf, *recvbuf, *recvbufdcsp; + unsigned char length; + enum maple_code command; }; struct maple_devinfo { - unsigned long function; - unsigned long function_data[3]; - unsigned char area_code; - unsigned char connector_directon; - char product_name[31]; - char product_licence[61]; - unsigned short standby_power; - unsigned short max_power; + unsigned long function; + unsigned long function_data[3]; + unsigned char area_code; + unsigned char connector_direction; + char product_name[31]; + char product_licence[61]; + unsigned short standby_power; + unsigned short max_power; }; struct maple_device { - struct maple_driver *driver; - struct mapleq *mq; - void *private_data; - void (*callback) (struct mapleq * mq); - unsigned long when, interval, function; - struct maple_devinfo devinfo; - unsigned char port, unit; - char product_name[32]; - char product_licence[64]; - int registered; - struct device dev; + struct maple_driver *driver; + struct mapleq *mq; + void *private_data; + void (*callback) (struct mapleq * mq); + unsigned long when, interval, function; + struct maple_devinfo devinfo; + unsigned char port, unit; + char product_name[32]; + char product_licence[64]; + struct device dev; }; struct maple_driver { - unsigned long function; - int (*connect) (struct maple_device * dev); - void (*disconnect) (struct maple_device * dev); - struct device_driver drv; + unsigned long function; + int (*connect) (struct maple_device * dev); + void (*disconnect) (struct maple_device * dev); + struct device_driver drv; + int registered; }; void maple_getcond_callback(struct maple_device *dev, - void (*callback) (struct mapleq * mq), - unsigned long interval, - unsigned long function); + void (*callback) (struct mapleq * mq), + unsigned long interval, + unsigned long function); int maple_driver_register(struct device_driver *drv); void maple_add_packet(struct mapleq *mq); #define to_maple_dev(n) container_of(n, struct maple_device, dev) #define to_maple_driver(n) container_of(n, struct maple_driver, drv) -#endif /* __LINUX_MAPLE_H */ +#endif /* __LINUX_MAPLE_H */ diff --git a/include/linux/marker.h b/include/linux/marker.h index 5f36cf946bc..5df879dc377 100644 --- a/include/linux/marker.h +++ b/include/linux/marker.h @@ -19,16 +19,23 @@ struct marker; /** * marker_probe_func - Type of a marker probe function - * @mdata: pointer of type struct marker - * @private_data: caller site private data + * @probe_private: probe private data + * @call_private: call site private data * @fmt: format string - * @...: variable argument list + * @args: variable argument list pointer. Use a pointer to overcome C's + * inability to pass this around as a pointer in a portable manner in + * the callee otherwise. * * Type of marker probe functions. They receive the mdata and need to parse the * format string to recover the variable argument list. */ -typedef void marker_probe_func(const struct marker *mdata, - void *private_data, const char *fmt, ...); +typedef void marker_probe_func(void *probe_private, void *call_private, + const char *fmt, va_list *args); + +struct marker_probe_closure { + marker_probe_func *func; /* Callback */ + void *probe_private; /* Private probe data */ +}; struct marker { const char *name; /* Marker name */ @@ -36,8 +43,11 @@ struct marker { * variable argument list. */ char state; /* Marker state. */ - marker_probe_func *call;/* Probe handler function pointer */ - void *private; /* Private probe data */ + char ptype; /* probe type : 0 : single, 1 : multi */ + void (*call)(const struct marker *mdata, /* Probe wrapper */ + void *call_private, const char *fmt, ...); + struct marker_probe_closure single; + struct marker_probe_closure *multi; } __attribute__((aligned(8))); #ifdef CONFIG_MARKERS @@ -49,35 +59,31 @@ struct marker { * not add unwanted padding between the beginning of the section and the * structure. Force alignment to the same alignment as the section start. */ -#define __trace_mark(name, call_data, format, args...) \ +#define __trace_mark(name, call_private, format, args...) \ do { \ - static const char __mstrtab_name_##name[] \ - __attribute__((section("__markers_strings"))) \ - = #name; \ - static const char __mstrtab_format_##name[] \ + static const char __mstrtab_##name[] \ __attribute__((section("__markers_strings"))) \ - = format; \ + = #name "\0" format; \ static struct marker __mark_##name \ __attribute__((section("__markers"), aligned(8))) = \ - { __mstrtab_name_##name, __mstrtab_format_##name, \ - 0, __mark_empty_function, NULL }; \ + { __mstrtab_##name, &__mstrtab_##name[sizeof(#name)], \ + 0, 0, marker_probe_cb, \ + { __mark_empty_function, NULL}, NULL }; \ __mark_check_format(format, ## args); \ if (unlikely(__mark_##name.state)) { \ - preempt_disable(); \ (*__mark_##name.call) \ - (&__mark_##name, call_data, \ + (&__mark_##name, call_private, \ format, ## args); \ - preempt_enable(); \ } \ } while (0) extern void marker_update_probe_range(struct marker *begin, - struct marker *end, struct module *probe_module, int *refcount); + struct marker *end); #else /* !CONFIG_MARKERS */ -#define __trace_mark(name, call_data, format, args...) \ +#define __trace_mark(name, call_private, format, args...) \ __mark_check_format(format, ## args) static inline void marker_update_probe_range(struct marker *begin, - struct marker *end, struct module *probe_module, int *refcount) + struct marker *end) { } #endif /* CONFIG_MARKERS */ @@ -92,8 +98,6 @@ static inline void marker_update_probe_range(struct marker *begin, #define trace_mark(name, format, args...) \ __trace_mark(name, NULL, format, ## args) -#define MARK_MAX_FORMAT_LEN 1024 - /** * MARK_NOARGS - Format string for a marker with no argument. */ @@ -106,24 +110,30 @@ static inline void __printf(1, 2) __mark_check_format(const char *fmt, ...) extern marker_probe_func __mark_empty_function; +extern void marker_probe_cb(const struct marker *mdata, + void *call_private, const char *fmt, ...); +extern void marker_probe_cb_noarg(const struct marker *mdata, + void *call_private, const char *fmt, ...); + /* * Connect a probe to a marker. * private data pointer must be a valid allocated memory address, or NULL. */ extern int marker_probe_register(const char *name, const char *format, - marker_probe_func *probe, void *private); + marker_probe_func *probe, void *probe_private); /* * Returns the private data given to marker_probe_register. */ -extern void *marker_probe_unregister(const char *name); +extern int marker_probe_unregister(const char *name, + marker_probe_func *probe, void *probe_private); /* * Unregister a marker by providing the registered private data. */ -extern void *marker_probe_unregister_private_data(void *private); +extern int marker_probe_unregister_private_data(marker_probe_func *probe, + void *probe_private); -extern int marker_arm(const char *name); -extern int marker_disarm(const char *name); -extern void *marker_get_private_data(const char *name); +extern void *marker_get_private_data(const char *name, marker_probe_func *probe, + int num); #endif diff --git a/include/linux/mm.h b/include/linux/mm.h index e8abb381420..26c7124b841 100644 --- a/include/linux/mm.h +++ b/include/linux/mm.h @@ -786,7 +786,7 @@ int __set_page_dirty_nobuffers(struct page *page); int __set_page_dirty_no_writeback(struct page *page); int redirty_page_for_writepage(struct writeback_control *wbc, struct page *page); -int FASTCALL(set_page_dirty(struct page *page)); +int set_page_dirty(struct page *page); int set_page_dirty_lock(struct page *page); int clear_page_dirty_for_io(struct page *page); @@ -829,7 +829,7 @@ extern void unregister_shrinker(struct shrinker *); int vma_wants_writenotify(struct vm_area_struct *vma); -extern pte_t *FASTCALL(get_locked_pte(struct mm_struct *mm, unsigned long addr, spinlock_t **ptl)); +extern pte_t *get_locked_pte(struct mm_struct *mm, unsigned long addr, spinlock_t **ptl); #ifdef __PAGETABLE_PUD_FOLDED static inline int __pud_alloc(struct mm_struct *mm, pgd_t *pgd, diff --git a/include/linux/module.h b/include/linux/module.h index ac28e8761e8..819c4e889bf 100644 --- a/include/linux/module.h +++ b/include/linux/module.h @@ -465,7 +465,7 @@ int unregister_module_notifier(struct notifier_block * nb); extern void print_modules(void); -extern void module_update_markers(struct module *probe_module, int *refcount); +extern void module_update_markers(void); #else /* !CONFIG_MODULES... */ #define EXPORT_SYMBOL(sym) @@ -567,8 +567,7 @@ static inline void print_modules(void) { } -static inline void module_update_markers(struct module *probe_module, - int *refcount) +static inline void module_update_markers(void) { } diff --git a/include/linux/moduleparam.h b/include/linux/moduleparam.h index 8126e55c5bd..ec624381c84 100644 --- a/include/linux/moduleparam.h +++ b/include/linux/moduleparam.h @@ -62,6 +62,16 @@ struct kparam_array void *elem; }; +/* On alpha, ia64 and ppc64 relocations to global data cannot go into + read-only sections (which is part of respective UNIX ABI on these + platforms). So 'const' makes no sense and even causes compile failures + with some compilers. */ +#if defined(CONFIG_ALPHA) || defined(CONFIG_IA64) || defined(CONFIG_PPC64) +#define __moduleparam_const +#else +#define __moduleparam_const const +#endif + /* This is the fundamental function for registering boot/module parameters. perm sets the visibility in sysfs: 000 means it's not there, read bits mean it's readable, write bits mean it's @@ -71,7 +81,7 @@ struct kparam_array static int __param_perm_check_##name __attribute__((unused)) = \ BUILD_BUG_ON_ZERO((perm) < 0 || (perm) > 0777 || ((perm) & 2)); \ static const char __param_str_##name[] = prefix #name; \ - static struct kernel_param const __param_##name \ + static struct kernel_param __moduleparam_const __param_##name \ __used \ __attribute__ ((unused,__section__ ("__param"),aligned(sizeof(void *)))) \ = { __param_str_##name, perm, set, get, { arg } } diff --git a/include/linux/mutex-debug.h b/include/linux/mutex-debug.h index 2537285e106..731d77d6e15 100644 --- a/include/linux/mutex-debug.h +++ b/include/linux/mutex-debug.h @@ -18,6 +18,6 @@ do { \ __mutex_init((mutex), #mutex, &__key); \ } while (0) -extern void FASTCALL(mutex_destroy(struct mutex *lock)); +extern void mutex_destroy(struct mutex *lock); #endif diff --git a/include/linux/namei.h b/include/linux/namei.h index 4cb4f8d2f78..24d88e98a62 100644 --- a/include/linux/namei.h +++ b/include/linux/namei.h @@ -3,6 +3,7 @@ #include <linux/dcache.h> #include <linux/linkage.h> +#include <linux/path.h> struct vfsmount; @@ -15,8 +16,7 @@ struct open_intent { enum { MAX_NESTED_LINKS = 8 }; struct nameidata { - struct dentry *dentry; - struct vfsmount *mnt; + struct path path; struct qstr last; unsigned int flags; int last_type; @@ -29,11 +29,6 @@ struct nameidata { } intent; }; -struct path { - struct vfsmount *mnt; - struct dentry *dentry; -}; - /* * Type of the last component on LOOKUP_PARENT */ @@ -62,17 +57,15 @@ enum {LAST_NORM, LAST_ROOT, LAST_DOT, LAST_DOTDOT, LAST_BIND}; #define LOOKUP_ACCESS (0x0400) #define LOOKUP_CHDIR (0x0800) -extern int FASTCALL(__user_walk(const char __user *, unsigned, struct nameidata *)); -extern int FASTCALL(__user_walk_fd(int dfd, const char __user *, unsigned, struct nameidata *)); +extern int __user_walk(const char __user *, unsigned, struct nameidata *); +extern int __user_walk_fd(int dfd, const char __user *, unsigned, struct nameidata *); #define user_path_walk(name,nd) \ __user_walk_fd(AT_FDCWD, name, LOOKUP_FOLLOW, nd) #define user_path_walk_link(name,nd) \ __user_walk_fd(AT_FDCWD, name, 0, nd) -extern int FASTCALL(path_lookup(const char *, unsigned, struct nameidata *)); +extern int path_lookup(const char *, unsigned, struct nameidata *); extern int vfs_path_lookup(struct dentry *, struct vfsmount *, const char *, unsigned int, struct nameidata *); -extern void path_release(struct nameidata *); -extern void path_release_on_umount(struct nameidata *); extern int __user_path_lookup_open(const char __user *, unsigned lookup_flags, struct nameidata *nd, int open_flags); extern int path_lookup_open(int dfd, const char *name, unsigned lookup_flags, struct nameidata *, int open_flags); diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index 047d432bde5..a2f003239c8 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -322,7 +322,7 @@ enum NAPI_STATE_DISABLE, /* Disable pending */ }; -extern void FASTCALL(__napi_schedule(struct napi_struct *n)); +extern void __napi_schedule(struct napi_struct *n); static inline int napi_disable_pending(struct napi_struct *n) { @@ -604,6 +604,10 @@ struct net_device unsigned char broadcast[MAX_ADDR_LEN]; /* hw bcast add */ + /* ingress path synchronizer */ + spinlock_t ingress_lock; + struct Qdisc *qdisc_ingress; + /* * Cache line mostly used on queue transmit path (qdisc) */ @@ -617,10 +621,6 @@ struct net_device /* Partially transmitted GSO packet. */ struct sk_buff *gso_skb; - /* ingress path synchronizer */ - spinlock_t ingress_lock; - struct Qdisc *qdisc_ingress; - /* * One part is mostly used on xmit path (device) */ diff --git a/include/linux/nfsd/export.h b/include/linux/nfsd/export.h index 3a168725136..5431512b275 100644 --- a/include/linux/nfsd/export.h +++ b/include/linux/nfsd/export.h @@ -84,9 +84,8 @@ struct svc_export { struct cache_head h; struct auth_domain * ex_client; int ex_flags; - struct vfsmount * ex_mnt; - struct dentry * ex_dentry; - char * ex_path; + struct path ex_path; + char *ex_pathname; uid_t ex_anon_uid; gid_t ex_anon_gid; int ex_fsid; @@ -107,8 +106,7 @@ struct svc_expkey { int ek_fsidtype; u32 ek_fsid[6]; - struct vfsmount * ek_mnt; - struct dentry * ek_dentry; + struct path ek_path; }; #define EX_SECURE(exp) (!((exp)->ex_flags & NFSEXP_INSECURE_PORT)) diff --git a/include/linux/pagemap.h b/include/linux/pagemap.h index 4b62a105622..d2fca802f80 100644 --- a/include/linux/pagemap.h +++ b/include/linux/pagemap.h @@ -156,10 +156,10 @@ static inline pgoff_t linear_page_index(struct vm_area_struct *vma, return pgoff >> (PAGE_CACHE_SHIFT - PAGE_SHIFT); } -extern void FASTCALL(__lock_page(struct page *page)); -extern int FASTCALL(__lock_page_killable(struct page *page)); -extern void FASTCALL(__lock_page_nosync(struct page *page)); -extern void FASTCALL(unlock_page(struct page *page)); +extern void __lock_page(struct page *page); +extern int __lock_page_killable(struct page *page); +extern void __lock_page_nosync(struct page *page); +extern void unlock_page(struct page *page); /* * lock_page may only be called if we have the page's inode pinned. @@ -199,7 +199,7 @@ static inline void lock_page_nosync(struct page *page) * This is exported only for wait_on_page_locked/wait_on_page_writeback. * Never use this directly! */ -extern void FASTCALL(wait_on_page_bit(struct page *page, int bit_nr)); +extern void wait_on_page_bit(struct page *page, int bit_nr); /* * Wait for a page to be unlocked. diff --git a/include/linux/path.h b/include/linux/path.h new file mode 100644 index 00000000000..915e0c382a5 --- /dev/null +++ b/include/linux/path.h @@ -0,0 +1,15 @@ +#ifndef _LINUX_PATH_H +#define _LINUX_PATH_H + +struct dentry; +struct vfsmount; + +struct path { + struct vfsmount *mnt; + struct dentry *dentry; +}; + +extern void path_get(struct path *); +extern void path_put(struct path *); + +#endif /* _LINUX_PATH_H */ diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h index df6dd79a0d3..0519e53d5eb 100644 --- a/include/linux/pci_ids.h +++ b/include/linux/pci_ids.h @@ -1351,6 +1351,7 @@ #define PCI_DEVICE_ID_VIA_8231_4 0x8235 #define PCI_DEVICE_ID_VIA_8365_1 0x8305 #define PCI_DEVICE_ID_VIA_CX700 0x8324 +#define PCI_DEVICE_ID_VIA_CX700_IDE 0x0581 #define PCI_DEVICE_ID_VIA_VX800 0x8353 #define PCI_DEVICE_ID_VIA_8371_1 0x8391 #define PCI_DEVICE_ID_VIA_82C598_1 0x8598 diff --git a/include/linux/pid.h b/include/linux/pid.h index f84d532b5d2..c7980810eb0 100644 --- a/include/linux/pid.h +++ b/include/linux/pid.h @@ -79,10 +79,9 @@ static inline struct pid *get_pid(struct pid *pid) return pid; } -extern void FASTCALL(put_pid(struct pid *pid)); -extern struct task_struct *FASTCALL(pid_task(struct pid *pid, enum pid_type)); -extern struct task_struct *FASTCALL(get_pid_task(struct pid *pid, - enum pid_type)); +extern void put_pid(struct pid *pid); +extern struct task_struct *pid_task(struct pid *pid, enum pid_type); +extern struct task_struct *get_pid_task(struct pid *pid, enum pid_type); extern struct pid *get_task_pid(struct task_struct *task, enum pid_type type); @@ -90,11 +89,11 @@ extern struct pid *get_task_pid(struct task_struct *task, enum pid_type type); * attach_pid() and detach_pid() must be called with the tasklist_lock * write-held. */ -extern int FASTCALL(attach_pid(struct task_struct *task, - enum pid_type type, struct pid *pid)); -extern void FASTCALL(detach_pid(struct task_struct *task, enum pid_type)); -extern void FASTCALL(transfer_pid(struct task_struct *old, - struct task_struct *new, enum pid_type)); +extern int attach_pid(struct task_struct *task, enum pid_type type, + struct pid *pid); +extern void detach_pid(struct task_struct *task, enum pid_type); +extern void transfer_pid(struct task_struct *old, struct task_struct *new, + enum pid_type); struct pid_namespace; extern struct pid_namespace init_pid_ns; @@ -109,7 +108,7 @@ extern struct pid_namespace init_pid_ns; * * see also find_task_by_pid() set in include/linux/sched.h */ -extern struct pid *FASTCALL(find_pid_ns(int nr, struct pid_namespace *ns)); +extern struct pid *find_pid_ns(int nr, struct pid_namespace *ns); extern struct pid *find_vpid(int nr); extern struct pid *find_pid(int nr); @@ -121,7 +120,7 @@ extern struct pid *find_ge_pid(int nr, struct pid_namespace *); int next_pidmap(struct pid_namespace *pid_ns, int last); extern struct pid *alloc_pid(struct pid_namespace *ns); -extern void FASTCALL(free_pid(struct pid *pid)); +extern void free_pid(struct pid *pid); /* * the helpers to get the pid's id seen from different namespaces diff --git a/include/linux/proc_fs.h b/include/linux/proc_fs.h index d6a4f69bdc9..d9a9e718ad1 100644 --- a/include/linux/proc_fs.h +++ b/include/linux/proc_fs.h @@ -269,7 +269,7 @@ extern void kclist_add(struct kcore_list *, void *, size_t); #endif union proc_op { - int (*proc_get_link)(struct inode *, struct dentry **, struct vfsmount **); + int (*proc_get_link)(struct inode *, struct path *); int (*proc_read)(struct task_struct *task, char *page); int (*proc_show)(struct seq_file *m, struct pid_namespace *ns, struct pid *pid, diff --git a/include/linux/rwsem-spinlock.h b/include/linux/rwsem-spinlock.h index 813cee13da0..6c3c0f6c261 100644 --- a/include/linux/rwsem-spinlock.h +++ b/include/linux/rwsem-spinlock.h @@ -60,14 +60,14 @@ do { \ __init_rwsem((sem), #sem, &__key); \ } while (0) -extern void FASTCALL(__down_read(struct rw_semaphore *sem)); -extern int FASTCALL(__down_read_trylock(struct rw_semaphore *sem)); -extern void FASTCALL(__down_write(struct rw_semaphore *sem)); -extern void FASTCALL(__down_write_nested(struct rw_semaphore *sem, int subclass)); -extern int FASTCALL(__down_write_trylock(struct rw_semaphore *sem)); -extern void FASTCALL(__up_read(struct rw_semaphore *sem)); -extern void FASTCALL(__up_write(struct rw_semaphore *sem)); -extern void FASTCALL(__downgrade_write(struct rw_semaphore *sem)); +extern void __down_read(struct rw_semaphore *sem); +extern int __down_read_trylock(struct rw_semaphore *sem); +extern void __down_write(struct rw_semaphore *sem); +extern void __down_write_nested(struct rw_semaphore *sem, int subclass); +extern int __down_write_trylock(struct rw_semaphore *sem); +extern void __up_read(struct rw_semaphore *sem); +extern void __up_write(struct rw_semaphore *sem); +extern void __downgrade_write(struct rw_semaphore *sem); static inline int rwsem_is_locked(struct rw_semaphore *sem) { diff --git a/include/linux/sched.h b/include/linux/sched.h index 00e14411732..e217d188a10 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h @@ -323,7 +323,7 @@ extern char __sched_text_start[], __sched_text_end[]; extern int in_sched_functions(unsigned long addr); #define MAX_SCHEDULE_TIMEOUT LONG_MAX -extern signed long FASTCALL(schedule_timeout(signed long timeout)); +extern signed long schedule_timeout(signed long timeout); extern signed long schedule_timeout_interruptible(signed long timeout); extern signed long schedule_timeout_killable(signed long timeout); extern signed long schedule_timeout_uninterruptible(signed long timeout); @@ -590,7 +590,7 @@ struct user_struct { struct hlist_node uidhash_node; uid_t uid; -#ifdef CONFIG_FAIR_USER_SCHED +#ifdef CONFIG_USER_SCHED struct task_group *tg; #ifdef CONFIG_SYSFS struct kobject kobj; @@ -973,7 +973,7 @@ struct sched_rt_entity { unsigned long timeout; int nr_cpus_allowed; -#ifdef CONFIG_FAIR_GROUP_SCHED +#ifdef CONFIG_RT_GROUP_SCHED struct sched_rt_entity *parent; /* rq on which this entity is (to be) queued: */ struct rt_rq *rt_rq; @@ -1541,8 +1541,6 @@ extern unsigned int sysctl_sched_child_runs_first; extern unsigned int sysctl_sched_features; extern unsigned int sysctl_sched_migration_cost; extern unsigned int sysctl_sched_nr_migrate; -extern unsigned int sysctl_sched_rt_period; -extern unsigned int sysctl_sched_rt_ratio; #if defined(CONFIG_FAIR_GROUP_SCHED) && defined(CONFIG_SMP) extern unsigned int sysctl_sched_min_bal_int_shares; extern unsigned int sysctl_sched_max_bal_int_shares; @@ -1552,6 +1550,8 @@ int sched_nr_latency_handler(struct ctl_table *table, int write, struct file *file, void __user *buffer, size_t *length, loff_t *ppos); #endif +extern unsigned int sysctl_sched_rt_period; +extern int sysctl_sched_rt_runtime; extern unsigned int sysctl_sched_compat_yield; @@ -1648,10 +1648,10 @@ extern void release_uids(struct user_namespace *ns); extern void do_timer(unsigned long ticks); -extern int FASTCALL(wake_up_state(struct task_struct * tsk, unsigned int state)); -extern int FASTCALL(wake_up_process(struct task_struct * tsk)); -extern void FASTCALL(wake_up_new_task(struct task_struct * tsk, - unsigned long clone_flags)); +extern int wake_up_state(struct task_struct *tsk, unsigned int state); +extern int wake_up_process(struct task_struct *tsk); +extern void wake_up_new_task(struct task_struct *tsk, + unsigned long clone_flags); #ifdef CONFIG_SMP extern void kick_process(struct task_struct *tsk); #else @@ -1741,7 +1741,7 @@ static inline int sas_ss_flags(unsigned long sp) extern struct mm_struct * mm_alloc(void); /* mmdrop drops the mm and the page tables */ -extern void FASTCALL(__mmdrop(struct mm_struct *)); +extern void __mmdrop(struct mm_struct *); static inline void mmdrop(struct mm_struct * mm) { if (unlikely(atomic_dec_and_test(&mm->mm_count))) @@ -1925,7 +1925,7 @@ static inline int signal_pending(struct task_struct *p) return unlikely(test_tsk_thread_flag(p,TIF_SIGPENDING)); } -extern int FASTCALL(__fatal_signal_pending(struct task_struct *p)); +extern int __fatal_signal_pending(struct task_struct *p); static inline int fatal_signal_pending(struct task_struct *p) { @@ -2027,16 +2027,22 @@ extern int sched_mc_power_savings, sched_smt_power_savings; extern void normalize_rt_tasks(void); -#ifdef CONFIG_FAIR_GROUP_SCHED +#ifdef CONFIG_GROUP_SCHED extern struct task_group init_task_group; extern struct task_group *sched_create_group(void); extern void sched_destroy_group(struct task_group *tg); extern void sched_move_task(struct task_struct *tsk); +#ifdef CONFIG_FAIR_GROUP_SCHED extern int sched_group_set_shares(struct task_group *tg, unsigned long shares); extern unsigned long sched_group_shares(struct task_group *tg); - +#endif +#ifdef CONFIG_RT_GROUP_SCHED +extern int sched_group_set_rt_runtime(struct task_group *tg, + long rt_runtime_us); +extern long sched_group_rt_runtime(struct task_group *tg); +#endif #endif #ifdef CONFIG_TASK_XACCT diff --git a/include/linux/seq_file.h b/include/linux/seq_file.h index 648dfeb444d..67c2563961f 100644 --- a/include/linux/seq_file.h +++ b/include/linux/seq_file.h @@ -8,8 +8,7 @@ struct seq_operations; struct file; -struct vfsmount; -struct dentry; +struct path; struct inode; struct seq_file { @@ -42,7 +41,7 @@ int seq_puts(struct seq_file *m, const char *s); int seq_printf(struct seq_file *, const char *, ...) __attribute__ ((format (printf,2,3))); -int seq_path(struct seq_file *, struct vfsmount *, struct dentry *, char *); +int seq_path(struct seq_file *, struct path *, char *); int single_open(struct file *, int (*)(struct seq_file *, void *), void *); int single_release(struct inode *, struct file *); diff --git a/include/linux/serial_core.h b/include/linux/serial_core.h index 1a0b6cf83ff..289942fc665 100644 --- a/include/linux/serial_core.h +++ b/include/linux/serial_core.h @@ -149,6 +149,8 @@ /* Freescale ColdFire */ #define PORT_MCF 78 +#define PORT_SC26XX 79 + /* MN10300 on-chip UART numbers */ #define PORT_MN10300 80 diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h index 412672a79e8..bbd8d0027e2 100644 --- a/include/linux/skbuff.h +++ b/include/linux/skbuff.h @@ -232,6 +232,8 @@ typedef unsigned char *sk_buff_data_t; * @mark: Generic packet mark * @nfct: Associated connection, if any * @ipvs_property: skbuff is owned by ipvs + * @peeked: this packet has been seen already, so stats have been + * done for it, don't do them again * @nf_trace: netfilter packet trace flag * @nfctinfo: Relationship of this skb to the connection * @nfct_reasm: netfilter conntrack re-assembly pointer diff --git a/include/linux/slub_def.h b/include/linux/slub_def.h index 5e6d3d634d5..57deecc79d5 100644 --- a/include/linux/slub_def.h +++ b/include/linux/slub_def.h @@ -71,6 +71,7 @@ struct kmem_cache { /* Allocation and freeing of slabs */ int objects; /* Number of objects in slab */ + gfp_t allocflags; /* gfp flags to use on each alloc */ int refcount; /* Refcount for slab cache destroy */ void (*ctor)(struct kmem_cache *, void *); int inuse; /* Offset to metadata */ @@ -110,7 +111,7 @@ struct kmem_cache { * We keep the general caches in an array of slab caches that are used for * 2^x bytes of allocations. */ -extern struct kmem_cache kmalloc_caches[PAGE_SHIFT]; +extern struct kmem_cache kmalloc_caches[PAGE_SHIFT + 1]; /* * Sorry that the following has to be that ugly but some versions of GCC @@ -188,12 +189,16 @@ static __always_inline struct kmem_cache *kmalloc_slab(size_t size) void *kmem_cache_alloc(struct kmem_cache *, gfp_t); void *__kmalloc(size_t size, gfp_t flags); +static __always_inline void *kmalloc_large(size_t size, gfp_t flags) +{ + return (void *)__get_free_pages(flags | __GFP_COMP, get_order(size)); +} + static __always_inline void *kmalloc(size_t size, gfp_t flags) { if (__builtin_constant_p(size)) { - if (size > PAGE_SIZE / 2) - return (void *)__get_free_pages(flags | __GFP_COMP, - get_order(size)); + if (size > PAGE_SIZE) + return kmalloc_large(size, flags); if (!(flags & SLUB_DMA)) { struct kmem_cache *s = kmalloc_slab(size); @@ -214,7 +219,7 @@ void *kmem_cache_alloc_node(struct kmem_cache *, gfp_t flags, int node); static __always_inline void *kmalloc_node(size_t size, gfp_t flags, int node) { if (__builtin_constant_p(size) && - size <= PAGE_SIZE / 2 && !(flags & SLUB_DMA)) { + size <= PAGE_SIZE && !(flags & SLUB_DMA)) { struct kmem_cache *s = kmalloc_slab(size); if (!s) diff --git a/include/linux/swap.h b/include/linux/swap.h index 3ca5c4bd6d3..878459ae045 100644 --- a/include/linux/swap.h +++ b/include/linux/swap.h @@ -171,10 +171,10 @@ extern unsigned int nr_free_pagecache_pages(void); /* linux/mm/swap.c */ -extern void FASTCALL(lru_cache_add(struct page *)); -extern void FASTCALL(lru_cache_add_active(struct page *)); -extern void FASTCALL(activate_page(struct page *)); -extern void FASTCALL(mark_page_accessed(struct page *)); +extern void lru_cache_add(struct page *); +extern void lru_cache_add_active(struct page *); +extern void activate_page(struct page *); +extern void mark_page_accessed(struct page *); extern void lru_add_drain(void); extern int lru_add_drain_all(void); extern int rotate_reclaimable_page(struct page *page); diff --git a/include/linux/videodev.h b/include/linux/videodev.h index 52e3d5fd5be..9385a566aed 100644 --- a/include/linux/videodev.h +++ b/include/linux/videodev.h @@ -12,6 +12,7 @@ #ifndef __LINUX_VIDEODEV_H #define __LINUX_VIDEODEV_H +#include <linux/ioctl.h> #include <linux/videodev2.h> #if defined(CONFIG_VIDEO_V4L1_COMPAT) || !defined (__KERNEL__) diff --git a/include/linux/videodev2.h b/include/linux/videodev2.h index 439474f24e3..17a80177a67 100644 --- a/include/linux/videodev2.h +++ b/include/linux/videodev2.h @@ -62,6 +62,7 @@ #define __user #include <sys/time.h> #endif +#include <linux/ioctl.h> #include <linux/types.h> /* diff --git a/include/linux/wait.h b/include/linux/wait.h index 33a2aa9e02f..0081147a9fe 100644 --- a/include/linux/wait.h +++ b/include/linux/wait.h @@ -117,9 +117,9 @@ static inline int waitqueue_active(wait_queue_head_t *q) */ #define is_sync_wait(wait) (!(wait) || ((wait)->private)) -extern void FASTCALL(add_wait_queue(wait_queue_head_t *q, wait_queue_t * wait)); -extern void FASTCALL(add_wait_queue_exclusive(wait_queue_head_t *q, wait_queue_t * wait)); -extern void FASTCALL(remove_wait_queue(wait_queue_head_t *q, wait_queue_t * wait)); +extern void add_wait_queue(wait_queue_head_t *q, wait_queue_t *wait); +extern void add_wait_queue_exclusive(wait_queue_head_t *q, wait_queue_t *wait); +extern void remove_wait_queue(wait_queue_head_t *q, wait_queue_t *wait); static inline void __add_wait_queue(wait_queue_head_t *head, wait_queue_t *new) { @@ -141,16 +141,16 @@ static inline void __remove_wait_queue(wait_queue_head_t *head, list_del(&old->task_list); } -void FASTCALL(__wake_up(wait_queue_head_t *q, unsigned int mode, int nr, void *key)); -extern void FASTCALL(__wake_up_locked(wait_queue_head_t *q, unsigned int mode)); -extern void FASTCALL(__wake_up_sync(wait_queue_head_t *q, unsigned int mode, int nr)); -void FASTCALL(__wake_up_bit(wait_queue_head_t *, void *, int)); -int FASTCALL(__wait_on_bit(wait_queue_head_t *, struct wait_bit_queue *, int (*)(void *), unsigned)); -int FASTCALL(__wait_on_bit_lock(wait_queue_head_t *, struct wait_bit_queue *, int (*)(void *), unsigned)); -void FASTCALL(wake_up_bit(void *, int)); -int FASTCALL(out_of_line_wait_on_bit(void *, int, int (*)(void *), unsigned)); -int FASTCALL(out_of_line_wait_on_bit_lock(void *, int, int (*)(void *), unsigned)); -wait_queue_head_t *FASTCALL(bit_waitqueue(void *, int)); +void __wake_up(wait_queue_head_t *q, unsigned int mode, int nr, void *key); +extern void __wake_up_locked(wait_queue_head_t *q, unsigned int mode); +extern void __wake_up_sync(wait_queue_head_t *q, unsigned int mode, int nr); +void __wake_up_bit(wait_queue_head_t *, void *, int); +int __wait_on_bit(wait_queue_head_t *, struct wait_bit_queue *, int (*)(void *), unsigned); +int __wait_on_bit_lock(wait_queue_head_t *, struct wait_bit_queue *, int (*)(void *), unsigned); +void wake_up_bit(void *, int); +int out_of_line_wait_on_bit(void *, int, int (*)(void *), unsigned); +int out_of_line_wait_on_bit_lock(void *, int, int (*)(void *), unsigned); +wait_queue_head_t *bit_waitqueue(void *, int); #define wake_up(x) __wake_up(x, TASK_NORMAL, 1, NULL) #define wake_up_nr(x, nr) __wake_up(x, TASK_NORMAL, nr, NULL) @@ -437,11 +437,9 @@ extern long interruptible_sleep_on_timeout(wait_queue_head_t *q, /* * Waitqueues which are removed from the waitqueue_head at wakeup time */ -void FASTCALL(prepare_to_wait(wait_queue_head_t *q, - wait_queue_t *wait, int state)); -void FASTCALL(prepare_to_wait_exclusive(wait_queue_head_t *q, - wait_queue_t *wait, int state)); -void FASTCALL(finish_wait(wait_queue_head_t *q, wait_queue_t *wait)); +void prepare_to_wait(wait_queue_head_t *q, wait_queue_t *wait, int state); +void prepare_to_wait_exclusive(wait_queue_head_t *q, wait_queue_t *wait, int state); +void finish_wait(wait_queue_head_t *q, wait_queue_t *wait); int autoremove_wake_function(wait_queue_t *wait, unsigned mode, int sync, void *key); int wake_bit_function(wait_queue_t *wait, unsigned mode, int sync, void *key); diff --git a/include/linux/workqueue.h b/include/linux/workqueue.h index 7f28c32d9ac..542526c6e8e 100644 --- a/include/linux/workqueue.h +++ b/include/linux/workqueue.h @@ -178,18 +178,17 @@ __create_workqueue_key(const char *name, int singlethread, extern void destroy_workqueue(struct workqueue_struct *wq); -extern int FASTCALL(queue_work(struct workqueue_struct *wq, struct work_struct *work)); -extern int FASTCALL(queue_delayed_work(struct workqueue_struct *wq, - struct delayed_work *work, unsigned long delay)); +extern int queue_work(struct workqueue_struct *wq, struct work_struct *work); +extern int queue_delayed_work(struct workqueue_struct *wq, + struct delayed_work *work, unsigned long delay); extern int queue_delayed_work_on(int cpu, struct workqueue_struct *wq, struct delayed_work *work, unsigned long delay); -extern void FASTCALL(flush_workqueue(struct workqueue_struct *wq)); +extern void flush_workqueue(struct workqueue_struct *wq); extern void flush_scheduled_work(void); -extern int FASTCALL(schedule_work(struct work_struct *work)); -extern int FASTCALL(schedule_delayed_work(struct delayed_work *work, - unsigned long delay)); +extern int schedule_work(struct work_struct *work); +extern int schedule_delayed_work(struct delayed_work *work, unsigned long delay); extern int schedule_delayed_work_on(int cpu, struct delayed_work *work, unsigned long delay); extern int schedule_on_each_cpu(work_func_t func); diff --git a/include/media/ir-common.h b/include/media/ir-common.h index 831547d7968..a4274203f25 100644 --- a/include/media/ir-common.h +++ b/include/media/ir-common.h @@ -142,6 +142,7 @@ extern IR_KEYTAB_TYPE ir_codes_tt_1500[IR_KEYTAB_SIZE]; extern IR_KEYTAB_TYPE ir_codes_fusionhdtv_mce[IR_KEYTAB_SIZE]; extern IR_KEYTAB_TYPE ir_codes_behold[IR_KEYTAB_SIZE]; extern IR_KEYTAB_TYPE ir_codes_pinnacle_pctv_hd[IR_KEYTAB_SIZE]; +extern IR_KEYTAB_TYPE ir_codes_genius_tvgo_a11mce[IR_KEYTAB_SIZE]; #endif diff --git a/include/media/v4l2-common.h b/include/media/v4l2-common.h index 475d0d8275e..316a5845313 100644 --- a/include/media/v4l2-common.h +++ b/include/media/v4l2-common.h @@ -61,8 +61,6 @@ v4l_client_printk(KERN_DEBUG, client, fmt , ## arg); \ } while (0) -/* Prints the ioctl in a human-readable format */ -extern void v4l_printk_ioctl(unsigned int cmd); /* Use this macro for non-I2C drivers. Pass the driver name as the first arg. */ #define v4l_print_ioctl(name, cmd) \ diff --git a/include/media/v4l2-dev.h b/include/media/v4l2-dev.h index c544c6f9089..f2114459995 100644 --- a/include/media/v4l2-dev.h +++ b/include/media/v4l2-dev.h @@ -44,6 +44,8 @@ extern unsigned int v4l2_video_std_fps(struct v4l2_standard *vs); extern char *v4l2_norm_to_name(v4l2_std_id id); extern int v4l2_video_std_construct(struct v4l2_standard *vs, int id, char *name); +/* Prints the ioctl in a human-readable format */ +extern void v4l_printk_ioctl(unsigned int cmd); /* prority handling */ struct v4l2_prio_state { diff --git a/include/media/videobuf-core.h b/include/media/videobuf-core.h index 97f14d46959..99033945cde 100644 --- a/include/media/videobuf-core.h +++ b/include/media/videobuf-core.h @@ -149,7 +149,7 @@ struct videobuf_qtype_ops { }; struct videobuf_queue { - struct mutex lock; + struct mutex vb_lock; spinlock_t *irqlock; void *dev; /* on pci, points to struct pci_dev */ diff --git a/include/media/videobuf-vmalloc.h b/include/media/videobuf-vmalloc.h index 26a8958d23d..ec63ab0fab9 100644 --- a/include/media/videobuf-vmalloc.h +++ b/include/media/videobuf-vmalloc.h @@ -17,7 +17,7 @@ /* --------------------------------------------------------------------- */ -struct videbuf_vmalloc_memory +struct videobuf_vmalloc_memory { u32 magic; diff --git a/include/net/ax25.h b/include/net/ax25.h index 32a57e1dee3..717e2192d52 100644 --- a/include/net/ax25.h +++ b/include/net/ax25.h @@ -324,6 +324,7 @@ extern void ax25_dama_on(ax25_cb *); extern void ax25_dama_off(ax25_cb *); /* ax25_ds_timer.c */ +extern void ax25_ds_setup_timer(ax25_dev *); extern void ax25_ds_set_timer(ax25_dev *); extern void ax25_ds_del_timer(ax25_dev *); extern void ax25_ds_timer(ax25_cb *); @@ -416,6 +417,7 @@ extern void ax25_calculate_rtt(ax25_cb *); extern void ax25_disconnect(ax25_cb *, int); /* ax25_timer.c */ +extern void ax25_setup_timers(ax25_cb *); extern void ax25_start_heartbeat(ax25_cb *); extern void ax25_start_t1timer(ax25_cb *); extern void ax25_start_t2timer(ax25_cb *); diff --git a/include/net/ndisc.h b/include/net/ndisc.h index 6684f7efbee..59b70624b05 100644 --- a/include/net/ndisc.h +++ b/include/net/ndisc.h @@ -103,7 +103,6 @@ extern void ndisc_send_redirect(struct sk_buff *skb, extern int ndisc_mc_map(struct in6_addr *addr, char *buf, struct net_device *dev, int dir); -struct rt6_info * dflt_rt_lookup(void); /* * IGMP diff --git a/include/net/sock.h b/include/net/sock.h index 8a7889b3581..fd987608765 100644 --- a/include/net/sock.h +++ b/include/net/sock.h @@ -180,6 +180,7 @@ struct sock_common { * @sk_sndmsg_off: cached offset for sendmsg * @sk_send_head: front of stuff to transmit * @sk_security: used by security modules + * @sk_mark: generic packet mark * @sk_write_pending: a write to stream socket waits to start * @sk_state_change: callback to indicate change in the state of the sock * @sk_data_ready: callback to indicate there is data to be processed diff --git a/include/net/xfrm.h b/include/net/xfrm.h index ac72116636c..eea7785cc75 100644 --- a/include/net/xfrm.h +++ b/include/net/xfrm.h @@ -508,7 +508,10 @@ struct xfrm_skb_cb { } header; /* Sequence number for replay protection. */ - u64 seq; + union { + u64 output; + __be32 input; + } seq; }; #define XFRM_SKB_CB(__skb) ((struct xfrm_skb_cb *)&((__skb)->cb[0])) diff --git a/include/scsi/scsi_host.h b/include/scsi/scsi_host.h index d1299e99972..530ff4c553f 100644 --- a/include/scsi/scsi_host.h +++ b/include/scsi/scsi_host.h @@ -6,6 +6,7 @@ #include <linux/types.h> #include <linux/workqueue.h> #include <linux/mutex.h> +#include <scsi/scsi.h> struct request_queue; struct block_device; @@ -25,12 +26,15 @@ struct blk_queue_tags; * NONE: Self evident. Host adapter is not capable of scatter-gather. * ALL: Means that the host adapter module can do scatter-gather, * and that there is no limit to the size of the table to which - * we scatter/gather data. + * we scatter/gather data. The value we set here is the maximum + * single element sglist. To use chained sglists, the adapter + * has to set a value beyond ALL (and correctly use the chain + * handling API. * Anything else: Indicates the maximum number of chains that can be * used in one scatter-gather request. */ #define SG_NONE 0 -#define SG_ALL 0xff +#define SG_ALL SCSI_MAX_SG_SEGMENTS #define MODE_UNKNOWN 0x00 #define MODE_INITIATOR 0x01 diff --git a/init/Kconfig b/init/Kconfig index 824d48cb67b..dcef8b55011 100644 --- a/init/Kconfig +++ b/init/Kconfig @@ -311,25 +311,36 @@ config CPUSETS Say N if unsure. -config FAIR_GROUP_SCHED - bool "Fair group CPU scheduler" +config GROUP_SCHED + bool "Group CPU scheduler" default y help This feature lets CPU scheduler recognize task groups and control CPU bandwidth allocation to such task groups. +config FAIR_GROUP_SCHED + bool "Group scheduling for SCHED_OTHER" + depends on GROUP_SCHED + default y + +config RT_GROUP_SCHED + bool "Group scheduling for SCHED_RR/FIFO" + depends on EXPERIMENTAL + depends on GROUP_SCHED + default n + choice - depends on FAIR_GROUP_SCHED + depends on GROUP_SCHED prompt "Basis for grouping tasks" - default FAIR_USER_SCHED + default USER_SCHED -config FAIR_USER_SCHED +config USER_SCHED bool "user id" help This option will choose userid as the basis for grouping tasks, thus providing equal CPU bandwidth to each user. -config FAIR_CGROUP_SCHED +config CGROUP_SCHED bool "Control groups" depends on CGROUPS help diff --git a/init/do_mounts.c b/init/do_mounts.c index f86573126f8..3885e70e775 100644 --- a/init/do_mounts.c +++ b/init/do_mounts.c @@ -193,10 +193,10 @@ static int __init do_mount_root(char *name, char *fs, int flags, void *data) return err; sys_chdir("/root"); - ROOT_DEV = current->fs->pwdmnt->mnt_sb->s_dev; + ROOT_DEV = current->fs->pwd.mnt->mnt_sb->s_dev; printk("VFS: Mounted root (%s filesystem)%s.\n", - current->fs->pwdmnt->mnt_sb->s_type->name, - current->fs->pwdmnt->mnt_sb->s_flags & MS_RDONLY ? + current->fs->pwd.mnt->mnt_sb->s_type->name, + current->fs->pwd.mnt->mnt_sb->s_flags & MS_RDONLY ? " readonly" : ""); return 0; } diff --git a/kernel/audit.c b/kernel/audit.c index c8555b18021..2eeea9a1424 100644 --- a/kernel/audit.c +++ b/kernel/audit.c @@ -1312,26 +1312,26 @@ void audit_log_untrustedstring(struct audit_buffer *ab, const char *string) /* This is a helper-function to print the escaped d_path */ void audit_log_d_path(struct audit_buffer *ab, const char *prefix, - struct dentry *dentry, struct vfsmount *vfsmnt) + struct path *path) { - char *p, *path; + char *p, *pathname; if (prefix) audit_log_format(ab, " %s", prefix); /* We will allow 11 spaces for ' (deleted)' to be appended */ - path = kmalloc(PATH_MAX+11, ab->gfp_mask); - if (!path) { + pathname = kmalloc(PATH_MAX+11, ab->gfp_mask); + if (!pathname) { audit_log_format(ab, "<no memory>"); return; } - p = d_path(dentry, vfsmnt, path, PATH_MAX+11); + p = d_path(path, pathname, PATH_MAX+11); if (IS_ERR(p)) { /* Should never happen since we send PATH_MAX */ /* FIXME: can we save some information here? */ audit_log_format(ab, "<too long>"); } else audit_log_untrustedstring(ab, p); - kfree(path); + kfree(pathname); } /** diff --git a/kernel/audit_tree.c b/kernel/audit_tree.c index f4fcf58f20f..9ef5e0aacc3 100644 --- a/kernel/audit_tree.c +++ b/kernel/audit_tree.c @@ -549,8 +549,8 @@ void audit_trim_trees(void) if (err) goto skip_it; - root_mnt = collect_mounts(nd.mnt, nd.dentry); - path_release(&nd); + root_mnt = collect_mounts(nd.path.mnt, nd.path.dentry); + path_put(&nd.path); if (!root_mnt) goto skip_it; @@ -583,17 +583,17 @@ skip_it: static int is_under(struct vfsmount *mnt, struct dentry *dentry, struct nameidata *nd) { - if (mnt != nd->mnt) { + if (mnt != nd->path.mnt) { for (;;) { if (mnt->mnt_parent == mnt) return 0; - if (mnt->mnt_parent == nd->mnt) + if (mnt->mnt_parent == nd->path.mnt) break; mnt = mnt->mnt_parent; } dentry = mnt->mnt_mountpoint; } - return is_subdir(dentry, nd->dentry); + return is_subdir(dentry, nd->path.dentry); } int audit_make_tree(struct audit_krule *rule, char *pathname, u32 op) @@ -641,8 +641,8 @@ int audit_add_tree_rule(struct audit_krule *rule) err = path_lookup(tree->pathname, 0, &nd); if (err) goto Err; - mnt = collect_mounts(nd.mnt, nd.dentry); - path_release(&nd); + mnt = collect_mounts(nd.path.mnt, nd.path.dentry); + path_put(&nd.path); if (!mnt) { err = -ENOMEM; goto Err; @@ -701,8 +701,8 @@ int audit_tag_tree(char *old, char *new) err = path_lookup(new, 0, &nd); if (err) return err; - tagged = collect_mounts(nd.mnt, nd.dentry); - path_release(&nd); + tagged = collect_mounts(nd.path.mnt, nd.path.dentry); + path_put(&nd.path); if (!tagged) return -ENOMEM; @@ -711,9 +711,9 @@ int audit_tag_tree(char *old, char *new) drop_collected_mounts(tagged); return err; } - mnt = mntget(nd.mnt); - dentry = dget(nd.dentry); - path_release(&nd); + mnt = mntget(nd.path.mnt); + dentry = dget(nd.path.dentry); + path_put(&nd.path); if (dentry == tagged->mnt_root && dentry == mnt->mnt_root) follow_up(&mnt, &dentry); @@ -744,13 +744,13 @@ int audit_tag_tree(char *old, char *new) spin_lock(&vfsmount_lock); if (!is_under(mnt, dentry, &nd)) { spin_unlock(&vfsmount_lock); - path_release(&nd); + path_put(&nd.path); put_tree(tree); mutex_lock(&audit_filter_mutex); continue; } spin_unlock(&vfsmount_lock); - path_release(&nd); + path_put(&nd.path); list_for_each_entry(p, &list, mnt_list) { failed = tag_chunk(p->mnt_root->d_inode, tree); diff --git a/kernel/auditfilter.c b/kernel/auditfilter.c index 6f19fd477aa..2f2914b7cc3 100644 --- a/kernel/auditfilter.c +++ b/kernel/auditfilter.c @@ -169,8 +169,8 @@ static struct audit_parent *audit_init_parent(struct nameidata *ndp) inotify_init_watch(&parent->wdata); /* grab a ref so inotify watch hangs around until we take audit_filter_mutex */ get_inotify_watch(&parent->wdata); - wd = inotify_add_watch(audit_ih, &parent->wdata, ndp->dentry->d_inode, - AUDIT_IN_WATCH); + wd = inotify_add_watch(audit_ih, &parent->wdata, + ndp->path.dentry->d_inode, AUDIT_IN_WATCH); if (wd < 0) { audit_free_parent(&parent->wdata); return ERR_PTR(wd); @@ -1161,11 +1161,11 @@ static int audit_get_nd(char *path, struct nameidata **ndp, static void audit_put_nd(struct nameidata *ndp, struct nameidata *ndw) { if (ndp) { - path_release(ndp); + path_put(&ndp->path); kfree(ndp); } if (ndw) { - path_release(ndw); + path_put(&ndw->path); kfree(ndw); } } @@ -1214,8 +1214,8 @@ static int audit_add_watch(struct audit_krule *krule, struct nameidata *ndp, /* update watch filter fields */ if (ndw) { - watch->dev = ndw->dentry->d_inode->i_sb->s_dev; - watch->ino = ndw->dentry->d_inode->i_ino; + watch->dev = ndw->path.dentry->d_inode->i_sb->s_dev; + watch->ino = ndw->path.dentry->d_inode->i_ino; } /* The audit_filter_mutex must not be held during inotify calls because @@ -1225,7 +1225,8 @@ static int audit_add_watch(struct audit_krule *krule, struct nameidata *ndp, */ mutex_unlock(&audit_filter_mutex); - if (inotify_find_watch(audit_ih, ndp->dentry->d_inode, &i_watch) < 0) { + if (inotify_find_watch(audit_ih, ndp->path.dentry->d_inode, + &i_watch) < 0) { parent = audit_init_parent(ndp); if (IS_ERR(parent)) { /* caller expects mutex locked */ diff --git a/kernel/auditsc.c b/kernel/auditsc.c index 1c06ecf38d7..2087d6de67e 100644 --- a/kernel/auditsc.c +++ b/kernel/auditsc.c @@ -208,8 +208,7 @@ struct audit_context { int name_count; struct audit_names names[AUDIT_NAMES]; char * filterkey; /* key for rule that triggered record */ - struct dentry * pwd; - struct vfsmount * pwdmnt; + struct path pwd; struct audit_context *previous; /* For nested syscalls */ struct audit_aux_data *aux; struct audit_aux_data *aux_pids; @@ -786,12 +785,9 @@ static inline void audit_free_names(struct audit_context *context) __putname(context->names[i].name); } context->name_count = 0; - if (context->pwd) - dput(context->pwd); - if (context->pwdmnt) - mntput(context->pwdmnt); - context->pwd = NULL; - context->pwdmnt = NULL; + path_put(&context->pwd); + context->pwd.dentry = NULL; + context->pwd.mnt = NULL; } static inline void audit_free_aux(struct audit_context *context) @@ -930,8 +926,7 @@ static void audit_log_task_info(struct audit_buffer *ab, struct task_struct *tsk if ((vma->vm_flags & VM_EXECUTABLE) && vma->vm_file) { audit_log_d_path(ab, "exe=", - vma->vm_file->f_path.dentry, - vma->vm_file->f_path.mnt); + &vma->vm_file->f_path); break; } vma = vma->vm_next; @@ -1005,9 +1000,10 @@ static int audit_log_single_execve_arg(struct audit_context *context, * for strings that are too long, we should not have created * any. */ - if (unlikely((len = -1) || len > MAX_ARG_STRLEN - 1)) { + if (unlikely((len == -1) || len > MAX_ARG_STRLEN - 1)) { WARN_ON(1); send_sig(SIGKILL, current, 0); + return -1; } /* walk the whole argument looking for non-ascii chars */ @@ -1025,6 +1021,7 @@ static int audit_log_single_execve_arg(struct audit_context *context, if (ret) { WARN_ON(1); send_sig(SIGKILL, current, 0); + return -1; } buf[to_send] = '\0'; has_cntl = audit_string_contains_control(buf, to_send); @@ -1088,6 +1085,7 @@ static int audit_log_single_execve_arg(struct audit_context *context, if (ret) { WARN_ON(1); send_sig(SIGKILL, current, 0); + return -1; } buf[to_send] = '\0'; @@ -1341,10 +1339,10 @@ static void audit_log_exit(struct audit_context *context, struct task_struct *ts context->target_sid, context->target_comm)) call_panic = 1; - if (context->pwd && context->pwdmnt) { + if (context->pwd.dentry && context->pwd.mnt) { ab = audit_log_start(context, GFP_KERNEL, AUDIT_CWD); if (ab) { - audit_log_d_path(ab, "cwd=", context->pwd, context->pwdmnt); + audit_log_d_path(ab, "cwd=", &context->pwd); audit_log_end(ab); } } @@ -1367,8 +1365,7 @@ static void audit_log_exit(struct audit_context *context, struct task_struct *ts case 0: /* name was specified as a relative path and the * directory component is the cwd */ - audit_log_d_path(ab, " name=", context->pwd, - context->pwdmnt); + audit_log_d_path(ab, " name=", &context->pwd); break; default: /* log the name's directory component */ @@ -1695,10 +1692,10 @@ void __audit_getname(const char *name) context->names[context->name_count].ino = (unsigned long)-1; context->names[context->name_count].osid = 0; ++context->name_count; - if (!context->pwd) { + if (!context->pwd.dentry) { read_lock(¤t->fs->lock); - context->pwd = dget(current->fs->pwd); - context->pwdmnt = mntget(current->fs->pwdmnt); + context->pwd = current->fs->pwd; + path_get(¤t->fs->pwd); read_unlock(¤t->fs->lock); } diff --git a/kernel/exit.c b/kernel/exit.c index 3b893e78ce6..506a957b665 100644 --- a/kernel/exit.c +++ b/kernel/exit.c @@ -512,14 +512,10 @@ static void __put_fs_struct(struct fs_struct *fs) { /* No need to hold fs->lock if we are killing it */ if (atomic_dec_and_test(&fs->count)) { - dput(fs->root); - mntput(fs->rootmnt); - dput(fs->pwd); - mntput(fs->pwdmnt); - if (fs->altroot) { - dput(fs->altroot); - mntput(fs->altrootmnt); - } + path_put(&fs->root); + path_put(&fs->pwd); + if (fs->altroot.dentry) + path_put(&fs->altroot); kmem_cache_free(fs_cachep, fs); } } diff --git a/kernel/fork.c b/kernel/fork.c index 4363a4eb84e..dd249c37b3a 100644 --- a/kernel/fork.c +++ b/kernel/fork.c @@ -600,16 +600,16 @@ static struct fs_struct *__copy_fs_struct(struct fs_struct *old) rwlock_init(&fs->lock); fs->umask = old->umask; read_lock(&old->lock); - fs->rootmnt = mntget(old->rootmnt); - fs->root = dget(old->root); - fs->pwdmnt = mntget(old->pwdmnt); - fs->pwd = dget(old->pwd); - if (old->altroot) { - fs->altrootmnt = mntget(old->altrootmnt); - fs->altroot = dget(old->altroot); + fs->root = old->root; + path_get(&old->root); + fs->pwd = old->pwd; + path_get(&old->pwd); + if (old->altroot.dentry) { + fs->altroot = old->altroot; + path_get(&old->altroot); } else { - fs->altrootmnt = NULL; - fs->altroot = NULL; + fs->altroot.mnt = NULL; + fs->altroot.dentry = NULL; } read_unlock(&old->lock); } diff --git a/kernel/futex.c b/kernel/futex.c index a6baaec44b8..221f2128a43 100644 --- a/kernel/futex.c +++ b/kernel/futex.c @@ -2116,7 +2116,7 @@ asmlinkage long sys_futex(u32 __user *uaddr, int op, u32 val, t = timespec_to_ktime(ts); if (cmd == FUTEX_WAIT) - t = ktime_add(ktime_get(), t); + t = ktime_add_safe(ktime_get(), t); tp = &t; } /* diff --git a/kernel/futex_compat.c b/kernel/futex_compat.c index 133d558db45..7d5e4b016f3 100644 --- a/kernel/futex_compat.c +++ b/kernel/futex_compat.c @@ -176,7 +176,7 @@ asmlinkage long compat_sys_futex(u32 __user *uaddr, int op, u32 val, t = timespec_to_ktime(ts); if (cmd == FUTEX_WAIT) - t = ktime_add(ktime_get(), t); + t = ktime_add_safe(ktime_get(), t); tp = &t; } if (cmd == FUTEX_REQUEUE || cmd == FUTEX_CMP_REQUEUE) diff --git a/kernel/hrtimer.c b/kernel/hrtimer.c index 3f4a57c7895..98bee013f71 100644 --- a/kernel/hrtimer.c +++ b/kernel/hrtimer.c @@ -326,6 +326,23 @@ u64 ktime_divns(const ktime_t kt, s64 div) #endif /* BITS_PER_LONG >= 64 */ /* + * Add two ktime values and do a safety check for overflow: + */ +ktime_t ktime_add_safe(const ktime_t lhs, const ktime_t rhs) +{ + ktime_t res = ktime_add(lhs, rhs); + + /* + * We use KTIME_SEC_MAX here, the maximum timeout which we can + * return to user space in a timespec: + */ + if (res.tv64 < 0 || res.tv64 < lhs.tv64 || res.tv64 < rhs.tv64) + res = ktime_set(KTIME_SEC_MAX, 0); + + return res; +} + +/* * Check, whether the timer is on the callback pending list */ static inline int hrtimer_cb_pending(const struct hrtimer *timer) @@ -425,6 +442,8 @@ static int hrtimer_reprogram(struct hrtimer *timer, ktime_t expires = ktime_sub(timer->expires, base->offset); int res; + WARN_ON_ONCE(timer->expires.tv64 < 0); + /* * When the callback is running, we do not reprogram the clock event * device. The timer callback is either running on a different CPU or @@ -435,6 +454,15 @@ static int hrtimer_reprogram(struct hrtimer *timer, if (hrtimer_callback_running(timer)) return 0; + /* + * CLOCK_REALTIME timer might be requested with an absolute + * expiry time which is less than base->offset. Nothing wrong + * about that, just avoid to call into the tick code, which + * has now objections against negative expiry values. + */ + if (expires.tv64 < 0) + return -ETIME; + if (expires.tv64 >= expires_next->tv64) return 0; @@ -682,13 +710,7 @@ u64 hrtimer_forward(struct hrtimer *timer, ktime_t now, ktime_t interval) */ orun++; } - timer->expires = ktime_add(timer->expires, interval); - /* - * Make sure, that the result did not wrap with a very large - * interval. - */ - if (timer->expires.tv64 < 0) - timer->expires = ktime_set(KTIME_SEC_MAX, 0); + timer->expires = ktime_add_safe(timer->expires, interval); return orun; } @@ -839,7 +861,7 @@ hrtimer_start(struct hrtimer *timer, ktime_t tim, const enum hrtimer_mode mode) new_base = switch_hrtimer_base(timer, base); if (mode == HRTIMER_MODE_REL) { - tim = ktime_add(tim, new_base->get_time()); + tim = ktime_add_safe(tim, new_base->get_time()); /* * CONFIG_TIME_LOW_RES is a temporary way for architectures * to signal that they simply return xtime in @@ -848,16 +870,8 @@ hrtimer_start(struct hrtimer *timer, ktime_t tim, const enum hrtimer_mode mode) * timeouts. This will go away with the GTOD framework. */ #ifdef CONFIG_TIME_LOW_RES - tim = ktime_add(tim, base->resolution); + tim = ktime_add_safe(tim, base->resolution); #endif - /* - * Careful here: User space might have asked for a - * very long sleep, so the add above might result in a - * negative number, which enqueues the timer in front - * of the queue. - */ - if (tim.tv64 < 0) - tim.tv64 = KTIME_MAX; } timer->expires = tim; diff --git a/kernel/kmod.c b/kernel/kmod.c index bb7df2a28bd..22be3ff3f36 100644 --- a/kernel/kmod.c +++ b/kernel/kmod.c @@ -173,10 +173,7 @@ static int ____call_usermodehelper(void *data) */ set_user_nice(current, 0); - retval = -EPERM; - if (current->fs->root) - retval = kernel_execve(sub_info->path, - sub_info->argv, sub_info->envp); + retval = kernel_execve(sub_info->path, sub_info->argv, sub_info->envp); /* Exec failed? */ sub_info->retval = retval; diff --git a/kernel/marker.c b/kernel/marker.c index 5323cfaedbc..c4c2cd8b61f 100644 --- a/kernel/marker.c +++ b/kernel/marker.c @@ -27,35 +27,42 @@ extern struct marker __start___markers[]; extern struct marker __stop___markers[]; +/* Set to 1 to enable marker debug output */ +const int marker_debug; + /* * markers_mutex nests inside module_mutex. Markers mutex protects the builtin - * and module markers, the hash table and deferred_sync. + * and module markers and the hash table. */ static DEFINE_MUTEX(markers_mutex); /* - * Marker deferred synchronization. - * Upon marker probe_unregister, we delay call to synchronize_sched() to - * accelerate mass unregistration (only when there is no more reference to a - * given module do we call synchronize_sched()). However, we need to make sure - * every critical region has ended before we re-arm a marker that has been - * unregistered and then registered back with a different probe data. - */ -static int deferred_sync; - -/* * Marker hash table, containing the active markers. * Protected by module_mutex. */ #define MARKER_HASH_BITS 6 #define MARKER_TABLE_SIZE (1 << MARKER_HASH_BITS) +/* + * Note about RCU : + * It is used to make sure every handler has finished using its private data + * between two consecutive operation (add or remove) on a given marker. It is + * also used to delay the free of multiple probes array until a quiescent state + * is reached. + * marker entries modifications are protected by the markers_mutex. + */ struct marker_entry { struct hlist_node hlist; char *format; - marker_probe_func *probe; - void *private; + void (*call)(const struct marker *mdata, /* Probe wrapper */ + void *call_private, const char *fmt, ...); + struct marker_probe_closure single; + struct marker_probe_closure *multi; int refcount; /* Number of times armed. 0 if disarmed. */ + struct rcu_head rcu; + void *oldptr; + char rcu_pending:1; + char ptype:1; char name[0]; /* Contains name'\0'format'\0' */ }; @@ -63,7 +70,8 @@ static struct hlist_head marker_table[MARKER_TABLE_SIZE]; /** * __mark_empty_function - Empty probe callback - * @mdata: pointer of type const struct marker + * @probe_private: probe private data + * @call_private: call site private data * @fmt: format string * @...: variable argument list * @@ -72,13 +80,267 @@ static struct hlist_head marker_table[MARKER_TABLE_SIZE]; * though the function pointer change and the marker enabling are two distinct * operations that modifies the execution flow of preemptible code. */ -void __mark_empty_function(const struct marker *mdata, void *private, - const char *fmt, ...) +void __mark_empty_function(void *probe_private, void *call_private, + const char *fmt, va_list *args) { } EXPORT_SYMBOL_GPL(__mark_empty_function); /* + * marker_probe_cb Callback that prepares the variable argument list for probes. + * @mdata: pointer of type struct marker + * @call_private: caller site private data + * @fmt: format string + * @...: Variable argument list. + * + * Since we do not use "typical" pointer based RCU in the 1 argument case, we + * need to put a full smp_rmb() in this branch. This is why we do not use + * rcu_dereference() for the pointer read. + */ +void marker_probe_cb(const struct marker *mdata, void *call_private, + const char *fmt, ...) +{ + va_list args; + char ptype; + + /* + * disabling preemption to make sure the teardown of the callbacks can + * be done correctly when they are in modules and they insure RCU read + * coherency. + */ + preempt_disable(); + ptype = ACCESS_ONCE(mdata->ptype); + if (likely(!ptype)) { + marker_probe_func *func; + /* Must read the ptype before ptr. They are not data dependant, + * so we put an explicit smp_rmb() here. */ + smp_rmb(); + func = ACCESS_ONCE(mdata->single.func); + /* Must read the ptr before private data. They are not data + * dependant, so we put an explicit smp_rmb() here. */ + smp_rmb(); + va_start(args, fmt); + func(mdata->single.probe_private, call_private, fmt, &args); + va_end(args); + } else { + struct marker_probe_closure *multi; + int i; + /* + * multi points to an array, therefore accessing the array + * depends on reading multi. However, even in this case, + * we must insure that the pointer is read _before_ the array + * data. Same as rcu_dereference, but we need a full smp_rmb() + * in the fast path, so put the explicit barrier here. + */ + smp_read_barrier_depends(); + multi = ACCESS_ONCE(mdata->multi); + for (i = 0; multi[i].func; i++) { + va_start(args, fmt); + multi[i].func(multi[i].probe_private, call_private, fmt, + &args); + va_end(args); + } + } + preempt_enable(); +} +EXPORT_SYMBOL_GPL(marker_probe_cb); + +/* + * marker_probe_cb Callback that does not prepare the variable argument list. + * @mdata: pointer of type struct marker + * @call_private: caller site private data + * @fmt: format string + * @...: Variable argument list. + * + * Should be connected to markers "MARK_NOARGS". + */ +void marker_probe_cb_noarg(const struct marker *mdata, + void *call_private, const char *fmt, ...) +{ + va_list args; /* not initialized */ + char ptype; + + preempt_disable(); + ptype = ACCESS_ONCE(mdata->ptype); + if (likely(!ptype)) { + marker_probe_func *func; + /* Must read the ptype before ptr. They are not data dependant, + * so we put an explicit smp_rmb() here. */ + smp_rmb(); + func = ACCESS_ONCE(mdata->single.func); + /* Must read the ptr before private data. They are not data + * dependant, so we put an explicit smp_rmb() here. */ + smp_rmb(); + func(mdata->single.probe_private, call_private, fmt, &args); + } else { + struct marker_probe_closure *multi; + int i; + /* + * multi points to an array, therefore accessing the array + * depends on reading multi. However, even in this case, + * we must insure that the pointer is read _before_ the array + * data. Same as rcu_dereference, but we need a full smp_rmb() + * in the fast path, so put the explicit barrier here. + */ + smp_read_barrier_depends(); + multi = ACCESS_ONCE(mdata->multi); + for (i = 0; multi[i].func; i++) + multi[i].func(multi[i].probe_private, call_private, fmt, + &args); + } + preempt_enable(); +} +EXPORT_SYMBOL_GPL(marker_probe_cb_noarg); + +static void free_old_closure(struct rcu_head *head) +{ + struct marker_entry *entry = container_of(head, + struct marker_entry, rcu); + kfree(entry->oldptr); + /* Make sure we free the data before setting the pending flag to 0 */ + smp_wmb(); + entry->rcu_pending = 0; +} + +static void debug_print_probes(struct marker_entry *entry) +{ + int i; + + if (!marker_debug) + return; + + if (!entry->ptype) { + printk(KERN_DEBUG "Single probe : %p %p\n", + entry->single.func, + entry->single.probe_private); + } else { + for (i = 0; entry->multi[i].func; i++) + printk(KERN_DEBUG "Multi probe %d : %p %p\n", i, + entry->multi[i].func, + entry->multi[i].probe_private); + } +} + +static struct marker_probe_closure * +marker_entry_add_probe(struct marker_entry *entry, + marker_probe_func *probe, void *probe_private) +{ + int nr_probes = 0; + struct marker_probe_closure *old, *new; + + WARN_ON(!probe); + + debug_print_probes(entry); + old = entry->multi; + if (!entry->ptype) { + if (entry->single.func == probe && + entry->single.probe_private == probe_private) + return ERR_PTR(-EBUSY); + if (entry->single.func == __mark_empty_function) { + /* 0 -> 1 probes */ + entry->single.func = probe; + entry->single.probe_private = probe_private; + entry->refcount = 1; + entry->ptype = 0; + debug_print_probes(entry); + return NULL; + } else { + /* 1 -> 2 probes */ + nr_probes = 1; + old = NULL; + } + } else { + /* (N -> N+1), (N != 0, 1) probes */ + for (nr_probes = 0; old[nr_probes].func; nr_probes++) + if (old[nr_probes].func == probe + && old[nr_probes].probe_private + == probe_private) + return ERR_PTR(-EBUSY); + } + /* + 2 : one for new probe, one for NULL func */ + new = kzalloc((nr_probes + 2) * sizeof(struct marker_probe_closure), + GFP_KERNEL); + if (new == NULL) + return ERR_PTR(-ENOMEM); + if (!old) + new[0] = entry->single; + else + memcpy(new, old, + nr_probes * sizeof(struct marker_probe_closure)); + new[nr_probes].func = probe; + new[nr_probes].probe_private = probe_private; + entry->refcount = nr_probes + 1; + entry->multi = new; + entry->ptype = 1; + debug_print_probes(entry); + return old; +} + +static struct marker_probe_closure * +marker_entry_remove_probe(struct marker_entry *entry, + marker_probe_func *probe, void *probe_private) +{ + int nr_probes = 0, nr_del = 0, i; + struct marker_probe_closure *old, *new; + + old = entry->multi; + + debug_print_probes(entry); + if (!entry->ptype) { + /* 0 -> N is an error */ + WARN_ON(entry->single.func == __mark_empty_function); + /* 1 -> 0 probes */ + WARN_ON(probe && entry->single.func != probe); + WARN_ON(entry->single.probe_private != probe_private); + entry->single.func = __mark_empty_function; + entry->refcount = 0; + entry->ptype = 0; + debug_print_probes(entry); + return NULL; + } else { + /* (N -> M), (N > 1, M >= 0) probes */ + for (nr_probes = 0; old[nr_probes].func; nr_probes++) { + if ((!probe || old[nr_probes].func == probe) + && old[nr_probes].probe_private + == probe_private) + nr_del++; + } + } + + if (nr_probes - nr_del == 0) { + /* N -> 0, (N > 1) */ + entry->single.func = __mark_empty_function; + entry->refcount = 0; + entry->ptype = 0; + } else if (nr_probes - nr_del == 1) { + /* N -> 1, (N > 1) */ + for (i = 0; old[i].func; i++) + if ((probe && old[i].func != probe) || + old[i].probe_private != probe_private) + entry->single = old[i]; + entry->refcount = 1; + entry->ptype = 0; + } else { + int j = 0; + /* N -> M, (N > 1, M > 1) */ + /* + 1 for NULL */ + new = kzalloc((nr_probes - nr_del + 1) + * sizeof(struct marker_probe_closure), GFP_KERNEL); + if (new == NULL) + return ERR_PTR(-ENOMEM); + for (i = 0; old[i].func; i++) + if ((probe && old[i].func != probe) || + old[i].probe_private != probe_private) + new[j++] = old[i]; + entry->refcount = nr_probes - nr_del; + entry->ptype = 1; + entry->multi = new; + } + debug_print_probes(entry); + return old; +} + +/* * Get marker if the marker is present in the marker hash table. * Must be called with markers_mutex held. * Returns NULL if not present. @@ -102,8 +364,7 @@ static struct marker_entry *get_marker(const char *name) * Add the marker to the marker hash table. Must be called with markers_mutex * held. */ -static int add_marker(const char *name, const char *format, - marker_probe_func *probe, void *private) +static struct marker_entry *add_marker(const char *name, const char *format) { struct hlist_head *head; struct hlist_node *node; @@ -118,9 +379,8 @@ static int add_marker(const char *name, const char *format, hlist_for_each_entry(e, node, head, hlist) { if (!strcmp(name, e->name)) { printk(KERN_NOTICE - "Marker %s busy, probe %p already installed\n", - name, e->probe); - return -EBUSY; /* Already there */ + "Marker %s busy\n", name); + return ERR_PTR(-EBUSY); /* Already there */ } } /* @@ -130,34 +390,42 @@ static int add_marker(const char *name, const char *format, e = kmalloc(sizeof(struct marker_entry) + name_len + format_len, GFP_KERNEL); if (!e) - return -ENOMEM; + return ERR_PTR(-ENOMEM); memcpy(&e->name[0], name, name_len); if (format) { e->format = &e->name[name_len]; memcpy(e->format, format, format_len); + if (strcmp(e->format, MARK_NOARGS) == 0) + e->call = marker_probe_cb_noarg; + else + e->call = marker_probe_cb; trace_mark(core_marker_format, "name %s format %s", e->name, e->format); - } else + } else { e->format = NULL; - e->probe = probe; - e->private = private; + e->call = marker_probe_cb; + } + e->single.func = __mark_empty_function; + e->single.probe_private = NULL; + e->multi = NULL; + e->ptype = 0; e->refcount = 0; + e->rcu_pending = 0; hlist_add_head(&e->hlist, head); - return 0; + return e; } /* * Remove the marker from the marker hash table. Must be called with mutex_lock * held. */ -static void *remove_marker(const char *name) +static int remove_marker(const char *name) { struct hlist_head *head; struct hlist_node *node; struct marker_entry *e; int found = 0; size_t len = strlen(name) + 1; - void *private = NULL; u32 hash = jhash(name, len-1, 0); head = &marker_table[hash & ((1 << MARKER_HASH_BITS)-1)]; @@ -167,12 +435,16 @@ static void *remove_marker(const char *name) break; } } - if (found) { - private = e->private; - hlist_del(&e->hlist); - kfree(e); - } - return private; + if (!found) + return -ENOENT; + if (e->single.func != __mark_empty_function) + return -EBUSY; + hlist_del(&e->hlist); + /* Make sure the call_rcu has been executed */ + if (e->rcu_pending) + rcu_barrier(); + kfree(e); + return 0; } /* @@ -184,6 +456,7 @@ static int marker_set_format(struct marker_entry **entry, const char *format) size_t name_len = strlen((*entry)->name) + 1; size_t format_len = strlen(format) + 1; + e = kmalloc(sizeof(struct marker_entry) + name_len + format_len, GFP_KERNEL); if (!e) @@ -191,11 +464,20 @@ static int marker_set_format(struct marker_entry **entry, const char *format) memcpy(&e->name[0], (*entry)->name, name_len); e->format = &e->name[name_len]; memcpy(e->format, format, format_len); - e->probe = (*entry)->probe; - e->private = (*entry)->private; + if (strcmp(e->format, MARK_NOARGS) == 0) + e->call = marker_probe_cb_noarg; + else + e->call = marker_probe_cb; + e->single = (*entry)->single; + e->multi = (*entry)->multi; + e->ptype = (*entry)->ptype; e->refcount = (*entry)->refcount; + e->rcu_pending = 0; hlist_add_before(&e->hlist, &(*entry)->hlist); hlist_del(&(*entry)->hlist); + /* Make sure the call_rcu has been executed */ + if ((*entry)->rcu_pending) + rcu_barrier(); kfree(*entry); *entry = e; trace_mark(core_marker_format, "name %s format %s", @@ -206,7 +488,8 @@ static int marker_set_format(struct marker_entry **entry, const char *format) /* * Sets the probe callback corresponding to one marker. */ -static int set_marker(struct marker_entry **entry, struct marker *elem) +static int set_marker(struct marker_entry **entry, struct marker *elem, + int active) { int ret; WARN_ON(strcmp((*entry)->name, elem->name) != 0); @@ -226,9 +509,43 @@ static int set_marker(struct marker_entry **entry, struct marker *elem) if (ret) return ret; } - elem->call = (*entry)->probe; - elem->private = (*entry)->private; - elem->state = 1; + + /* + * probe_cb setup (statically known) is done here. It is + * asynchronous with the rest of execution, therefore we only + * pass from a "safe" callback (with argument) to an "unsafe" + * callback (does not set arguments). + */ + elem->call = (*entry)->call; + /* + * Sanity check : + * We only update the single probe private data when the ptr is + * set to a _non_ single probe! (0 -> 1 and N -> 1, N != 1) + */ + WARN_ON(elem->single.func != __mark_empty_function + && elem->single.probe_private + != (*entry)->single.probe_private && + !elem->ptype); + elem->single.probe_private = (*entry)->single.probe_private; + /* + * Make sure the private data is valid when we update the + * single probe ptr. + */ + smp_wmb(); + elem->single.func = (*entry)->single.func; + /* + * We also make sure that the new probe callbacks array is consistent + * before setting a pointer to it. + */ + rcu_assign_pointer(elem->multi, (*entry)->multi); + /* + * Update the function or multi probe array pointer before setting the + * ptype. + */ + smp_wmb(); + elem->ptype = (*entry)->ptype; + elem->state = active; + return 0; } @@ -240,8 +557,12 @@ static int set_marker(struct marker_entry **entry, struct marker *elem) */ static void disable_marker(struct marker *elem) { + /* leave "call" as is. It is known statically. */ elem->state = 0; - elem->call = __mark_empty_function; + elem->single.func = __mark_empty_function; + /* Update the function before setting the ptype */ + smp_wmb(); + elem->ptype = 0; /* single probe */ /* * Leave the private data and id there, because removal is racy and * should be done only after a synchronize_sched(). These are never used @@ -253,14 +574,11 @@ static void disable_marker(struct marker *elem) * marker_update_probe_range - Update a probe range * @begin: beginning of the range * @end: end of the range - * @probe_module: module address of the probe being updated - * @refcount: number of references left to the given probe_module (out) * * Updates the probe callback corresponding to a range of markers. */ void marker_update_probe_range(struct marker *begin, - struct marker *end, struct module *probe_module, - int *refcount) + struct marker *end) { struct marker *iter; struct marker_entry *mark_entry; @@ -268,15 +586,12 @@ void marker_update_probe_range(struct marker *begin, mutex_lock(&markers_mutex); for (iter = begin; iter < end; iter++) { mark_entry = get_marker(iter->name); - if (mark_entry && mark_entry->refcount) { - set_marker(&mark_entry, iter); + if (mark_entry) { + set_marker(&mark_entry, iter, + !!mark_entry->refcount); /* * ignore error, continue */ - if (probe_module) - if (probe_module == - __module_text_address((unsigned long)mark_entry->probe)) - (*refcount)++; } else { disable_marker(iter); } @@ -289,20 +604,27 @@ void marker_update_probe_range(struct marker *begin, * Issues a synchronize_sched() when no reference to the module passed * as parameter is found in the probes so the probe module can be * safely unloaded from now on. + * + * Internal callback only changed before the first probe is connected to it. + * Single probe private data can only be changed on 0 -> 1 and 2 -> 1 + * transitions. All other transitions will leave the old private data valid. + * This makes the non-atomicity of the callback/private data updates valid. + * + * "special case" updates : + * 0 -> 1 callback + * 1 -> 0 callback + * 1 -> 2 callbacks + * 2 -> 1 callbacks + * Other updates all behave the same, just like the 2 -> 3 or 3 -> 2 updates. + * Site effect : marker_set_format may delete the marker entry (creating a + * replacement). */ -static void marker_update_probes(struct module *probe_module) +static void marker_update_probes(void) { - int refcount = 0; - /* Core kernel markers */ - marker_update_probe_range(__start___markers, - __stop___markers, probe_module, &refcount); + marker_update_probe_range(__start___markers, __stop___markers); /* Markers in modules. */ - module_update_markers(probe_module, &refcount); - if (probe_module && refcount == 0) { - synchronize_sched(); - deferred_sync = 0; - } + module_update_markers(); } /** @@ -310,33 +632,49 @@ static void marker_update_probes(struct module *probe_module) * @name: marker name * @format: format string * @probe: probe handler - * @private: probe private data + * @probe_private: probe private data * * private data must be a valid allocated memory address, or NULL. * Returns 0 if ok, error value on error. + * The probe address must at least be aligned on the architecture pointer size. */ int marker_probe_register(const char *name, const char *format, - marker_probe_func *probe, void *private) + marker_probe_func *probe, void *probe_private) { struct marker_entry *entry; int ret = 0; + struct marker_probe_closure *old; mutex_lock(&markers_mutex); entry = get_marker(name); - if (entry && entry->refcount) { - ret = -EBUSY; - goto end; - } - if (deferred_sync) { - synchronize_sched(); - deferred_sync = 0; + if (!entry) { + entry = add_marker(name, format); + if (IS_ERR(entry)) { + ret = PTR_ERR(entry); + goto end; + } } - ret = add_marker(name, format, probe, private); - if (ret) + /* + * If we detect that a call_rcu is pending for this marker, + * make sure it's executed now. + */ + if (entry->rcu_pending) + rcu_barrier(); + old = marker_entry_add_probe(entry, probe, probe_private); + if (IS_ERR(old)) { + ret = PTR_ERR(old); goto end; + } mutex_unlock(&markers_mutex); - marker_update_probes(NULL); - return ret; + marker_update_probes(); /* may update entry */ + mutex_lock(&markers_mutex); + entry = get_marker(name); + WARN_ON(!entry); + entry->oldptr = old; + entry->rcu_pending = 1; + /* write rcu_pending before calling the RCU callback */ + smp_wmb(); + call_rcu(&entry->rcu, free_old_closure); end: mutex_unlock(&markers_mutex); return ret; @@ -346,171 +684,166 @@ EXPORT_SYMBOL_GPL(marker_probe_register); /** * marker_probe_unregister - Disconnect a probe from a marker * @name: marker name + * @probe: probe function pointer + * @probe_private: probe private data * * Returns the private data given to marker_probe_register, or an ERR_PTR(). + * We do not need to call a synchronize_sched to make sure the probes have + * finished running before doing a module unload, because the module unload + * itself uses stop_machine(), which insures that every preempt disabled section + * have finished. */ -void *marker_probe_unregister(const char *name) +int marker_probe_unregister(const char *name, + marker_probe_func *probe, void *probe_private) { - struct module *probe_module; struct marker_entry *entry; - void *private; + struct marker_probe_closure *old; + int ret = 0; mutex_lock(&markers_mutex); entry = get_marker(name); if (!entry) { - private = ERR_PTR(-ENOENT); + ret = -ENOENT; goto end; } - entry->refcount = 0; - /* In what module is the probe handler ? */ - probe_module = __module_text_address((unsigned long)entry->probe); - private = remove_marker(name); - deferred_sync = 1; + if (entry->rcu_pending) + rcu_barrier(); + old = marker_entry_remove_probe(entry, probe, probe_private); mutex_unlock(&markers_mutex); - marker_update_probes(probe_module); - return private; + marker_update_probes(); /* may update entry */ + mutex_lock(&markers_mutex); + entry = get_marker(name); + entry->oldptr = old; + entry->rcu_pending = 1; + /* write rcu_pending before calling the RCU callback */ + smp_wmb(); + call_rcu(&entry->rcu, free_old_closure); + remove_marker(name); /* Ignore busy error message */ end: mutex_unlock(&markers_mutex); - return private; + return ret; } EXPORT_SYMBOL_GPL(marker_probe_unregister); -/** - * marker_probe_unregister_private_data - Disconnect a probe from a marker - * @private: probe private data - * - * Unregister a marker by providing the registered private data. - * Returns the private data given to marker_probe_register, or an ERR_PTR(). - */ -void *marker_probe_unregister_private_data(void *private) +static struct marker_entry * +get_marker_from_private_data(marker_probe_func *probe, void *probe_private) { - struct module *probe_module; - struct hlist_head *head; - struct hlist_node *node; struct marker_entry *entry; - int found = 0; unsigned int i; + struct hlist_head *head; + struct hlist_node *node; - mutex_lock(&markers_mutex); for (i = 0; i < MARKER_TABLE_SIZE; i++) { head = &marker_table[i]; hlist_for_each_entry(entry, node, head, hlist) { - if (entry->private == private) { - found = 1; - goto iter_end; + if (!entry->ptype) { + if (entry->single.func == probe + && entry->single.probe_private + == probe_private) + return entry; + } else { + struct marker_probe_closure *closure; + closure = entry->multi; + for (i = 0; closure[i].func; i++) { + if (closure[i].func == probe && + closure[i].probe_private + == probe_private) + return entry; + } } } } -iter_end: - if (!found) { - private = ERR_PTR(-ENOENT); - goto end; - } - entry->refcount = 0; - /* In what module is the probe handler ? */ - probe_module = __module_text_address((unsigned long)entry->probe); - private = remove_marker(entry->name); - deferred_sync = 1; - mutex_unlock(&markers_mutex); - marker_update_probes(probe_module); - return private; -end: - mutex_unlock(&markers_mutex); - return private; + return NULL; } -EXPORT_SYMBOL_GPL(marker_probe_unregister_private_data); /** - * marker_arm - Arm a marker - * @name: marker name + * marker_probe_unregister_private_data - Disconnect a probe from a marker + * @probe: probe function + * @probe_private: probe private data * - * Activate a marker. It keeps a reference count of the number of - * arming/disarming done. - * Returns 0 if ok, error value on error. + * Unregister a probe by providing the registered private data. + * Only removes the first marker found in hash table. + * Return 0 on success or error value. + * We do not need to call a synchronize_sched to make sure the probes have + * finished running before doing a module unload, because the module unload + * itself uses stop_machine(), which insures that every preempt disabled section + * have finished. */ -int marker_arm(const char *name) +int marker_probe_unregister_private_data(marker_probe_func *probe, + void *probe_private) { struct marker_entry *entry; int ret = 0; + struct marker_probe_closure *old; mutex_lock(&markers_mutex); - entry = get_marker(name); + entry = get_marker_from_private_data(probe, probe_private); if (!entry) { ret = -ENOENT; goto end; } - /* - * Only need to update probes when refcount passes from 0 to 1. - */ - if (entry->refcount++) - goto end; -end: + if (entry->rcu_pending) + rcu_barrier(); + old = marker_entry_remove_probe(entry, NULL, probe_private); mutex_unlock(&markers_mutex); - marker_update_probes(NULL); - return ret; -} -EXPORT_SYMBOL_GPL(marker_arm); - -/** - * marker_disarm - Disarm a marker - * @name: marker name - * - * Disarm a marker. It keeps a reference count of the number of arming/disarming - * done. - * Returns 0 if ok, error value on error. - */ -int marker_disarm(const char *name) -{ - struct marker_entry *entry; - int ret = 0; - + marker_update_probes(); /* may update entry */ mutex_lock(&markers_mutex); - entry = get_marker(name); - if (!entry) { - ret = -ENOENT; - goto end; - } - /* - * Only permit decrement refcount if higher than 0. - * Do probe update only on 1 -> 0 transition. - */ - if (entry->refcount) { - if (--entry->refcount) - goto end; - } else { - ret = -EPERM; - goto end; - } + entry = get_marker_from_private_data(probe, probe_private); + WARN_ON(!entry); + entry->oldptr = old; + entry->rcu_pending = 1; + /* write rcu_pending before calling the RCU callback */ + smp_wmb(); + call_rcu(&entry->rcu, free_old_closure); + remove_marker(entry->name); /* Ignore busy error message */ end: mutex_unlock(&markers_mutex); - marker_update_probes(NULL); return ret; } -EXPORT_SYMBOL_GPL(marker_disarm); +EXPORT_SYMBOL_GPL(marker_probe_unregister_private_data); /** * marker_get_private_data - Get a marker's probe private data * @name: marker name + * @probe: probe to match + * @num: get the nth matching probe's private data * + * Returns the nth private data pointer (starting from 0) matching, or an + * ERR_PTR. * Returns the private data pointer, or an ERR_PTR. * The private data pointer should _only_ be dereferenced if the caller is the * owner of the data, or its content could vanish. This is mostly used to * confirm that a caller is the owner of a registered probe. */ -void *marker_get_private_data(const char *name) +void *marker_get_private_data(const char *name, marker_probe_func *probe, + int num) { struct hlist_head *head; struct hlist_node *node; struct marker_entry *e; size_t name_len = strlen(name) + 1; u32 hash = jhash(name, name_len-1, 0); - int found = 0; + int i; head = &marker_table[hash & ((1 << MARKER_HASH_BITS)-1)]; hlist_for_each_entry(e, node, head, hlist) { if (!strcmp(name, e->name)) { - found = 1; - return e->private; + if (!e->ptype) { + if (num == 0 && e->single.func == probe) + return e->single.probe_private; + else + break; + } else { + struct marker_probe_closure *closure; + int match = 0; + closure = e->multi; + for (i = 0; closure[i].func; i++) { + if (closure[i].func != probe) + continue; + if (match++ == num) + return closure[i].probe_private; + } + } } } return ERR_PTR(-ENOENT); diff --git a/kernel/module.c b/kernel/module.c index 4202da97a1d..92595bad381 100644 --- a/kernel/module.c +++ b/kernel/module.c @@ -2038,7 +2038,7 @@ static struct module *load_module(void __user *umod, #ifdef CONFIG_MARKERS if (!mod->taints) marker_update_probe_range(mod->markers, - mod->markers + mod->num_markers, NULL, NULL); + mod->markers + mod->num_markers); #endif err = module_finalize(hdr, sechdrs, mod); if (err < 0) @@ -2564,7 +2564,7 @@ EXPORT_SYMBOL(struct_module); #endif #ifdef CONFIG_MARKERS -void module_update_markers(struct module *probe_module, int *refcount) +void module_update_markers(void) { struct module *mod; @@ -2572,8 +2572,7 @@ void module_update_markers(struct module *probe_module, int *refcount) list_for_each_entry(mod, &modules, list) if (!mod->taints) marker_update_probe_range(mod->markers, - mod->markers + mod->num_markers, - probe_module, refcount); + mod->markers + mod->num_markers); mutex_unlock(&module_mutex); } #endif diff --git a/kernel/posix-timers.c b/kernel/posix-timers.c index 022c9c3cee6..a9b04203a66 100644 --- a/kernel/posix-timers.c +++ b/kernel/posix-timers.c @@ -767,9 +767,11 @@ common_timer_set(struct k_itimer *timr, int flags, /* SIGEV_NONE timers are not queued ! See common_timer_get */ if (((timr->it_sigev_notify & ~SIGEV_THREAD_ID) == SIGEV_NONE)) { /* Setup correct expiry time for relative timers */ - if (mode == HRTIMER_MODE_REL) - timer->expires = ktime_add(timer->expires, - timer->base->get_time()); + if (mode == HRTIMER_MODE_REL) { + timer->expires = + ktime_add_safe(timer->expires, + timer->base->get_time()); + } return 0; } diff --git a/kernel/rcupdate.c b/kernel/rcupdate.c index 760dfc233a0..c09605f8d16 100644 --- a/kernel/rcupdate.c +++ b/kernel/rcupdate.c @@ -56,7 +56,10 @@ static atomic_t rcu_barrier_cpu_count; static DEFINE_MUTEX(rcu_barrier_mutex); static struct completion rcu_barrier_completion; -/* Because of FASTCALL declaration of complete, we use this wrapper */ +/* + * Awaken the corresponding synchronize_rcu() instance now that a + * grace period has elapsed. + */ static void wakeme_after_rcu(struct rcu_head *head) { struct rcu_synchronize *rcu; diff --git a/kernel/rtmutex.c b/kernel/rtmutex.c index 0deef71ff8d..6522ae5b14a 100644 --- a/kernel/rtmutex.c +++ b/kernel/rtmutex.c @@ -630,9 +630,12 @@ rt_mutex_slowlock(struct rt_mutex *lock, int state, set_current_state(state); /* Setup the timer, when timeout != NULL */ - if (unlikely(timeout)) + if (unlikely(timeout)) { hrtimer_start(&timeout->timer, timeout->timer.expires, HRTIMER_MODE_ABS); + if (!hrtimer_active(&timeout->timer)) + timeout->task = NULL; + } for (;;) { /* Try to acquire the lock: */ diff --git a/kernel/sched.c b/kernel/sched.c index 3eedd526090..f28f19e65b5 100644 --- a/kernel/sched.c +++ b/kernel/sched.c @@ -155,7 +155,7 @@ struct rt_prio_array { struct list_head queue[MAX_RT_PRIO]; }; -#ifdef CONFIG_FAIR_GROUP_SCHED +#ifdef CONFIG_GROUP_SCHED #include <linux/cgroup.h> @@ -165,19 +165,16 @@ static LIST_HEAD(task_groups); /* task group related information */ struct task_group { -#ifdef CONFIG_FAIR_CGROUP_SCHED +#ifdef CONFIG_CGROUP_SCHED struct cgroup_subsys_state css; #endif + +#ifdef CONFIG_FAIR_GROUP_SCHED /* schedulable entities of this group on each cpu */ struct sched_entity **se; /* runqueue "owned" by this group on each cpu */ struct cfs_rq **cfs_rq; - struct sched_rt_entity **rt_se; - struct rt_rq **rt_rq; - - unsigned int rt_ratio; - /* * shares assigned to a task group governs how much of cpu bandwidth * is allocated to the group. The more shares a group has, the more is @@ -213,33 +210,46 @@ struct task_group { * */ unsigned long shares; +#endif + +#ifdef CONFIG_RT_GROUP_SCHED + struct sched_rt_entity **rt_se; + struct rt_rq **rt_rq; + + u64 rt_runtime; +#endif struct rcu_head rcu; struct list_head list; }; +#ifdef CONFIG_FAIR_GROUP_SCHED /* Default task group's sched entity on each cpu */ static DEFINE_PER_CPU(struct sched_entity, init_sched_entity); /* Default task group's cfs_rq on each cpu */ static DEFINE_PER_CPU(struct cfs_rq, init_cfs_rq) ____cacheline_aligned_in_smp; -static DEFINE_PER_CPU(struct sched_rt_entity, init_sched_rt_entity); -static DEFINE_PER_CPU(struct rt_rq, init_rt_rq) ____cacheline_aligned_in_smp; - static struct sched_entity *init_sched_entity_p[NR_CPUS]; static struct cfs_rq *init_cfs_rq_p[NR_CPUS]; +#endif + +#ifdef CONFIG_RT_GROUP_SCHED +static DEFINE_PER_CPU(struct sched_rt_entity, init_sched_rt_entity); +static DEFINE_PER_CPU(struct rt_rq, init_rt_rq) ____cacheline_aligned_in_smp; static struct sched_rt_entity *init_sched_rt_entity_p[NR_CPUS]; static struct rt_rq *init_rt_rq_p[NR_CPUS]; +#endif -/* task_group_mutex serializes add/remove of task groups and also changes to +/* task_group_lock serializes add/remove of task groups and also changes to * a task group's cpu shares. */ -static DEFINE_MUTEX(task_group_mutex); +static DEFINE_SPINLOCK(task_group_lock); /* doms_cur_mutex serializes access to doms_cur[] array */ static DEFINE_MUTEX(doms_cur_mutex); +#ifdef CONFIG_FAIR_GROUP_SCHED #ifdef CONFIG_SMP /* kernel thread that runs rebalance_shares() periodically */ static struct task_struct *lb_monitor_task; @@ -248,35 +258,40 @@ static int load_balance_monitor(void *unused); static void set_se_shares(struct sched_entity *se, unsigned long shares); +#ifdef CONFIG_USER_SCHED +# define INIT_TASK_GROUP_LOAD (2*NICE_0_LOAD) +#else +# define INIT_TASK_GROUP_LOAD NICE_0_LOAD +#endif + +#define MIN_GROUP_SHARES 2 + +static int init_task_group_load = INIT_TASK_GROUP_LOAD; +#endif + /* Default task group. * Every task in system belong to this group at bootup. */ struct task_group init_task_group = { +#ifdef CONFIG_FAIR_GROUP_SCHED .se = init_sched_entity_p, .cfs_rq = init_cfs_rq_p, +#endif +#ifdef CONFIG_RT_GROUP_SCHED .rt_se = init_sched_rt_entity_p, .rt_rq = init_rt_rq_p, -}; - -#ifdef CONFIG_FAIR_USER_SCHED -# define INIT_TASK_GROUP_LOAD (2*NICE_0_LOAD) -#else -# define INIT_TASK_GROUP_LOAD NICE_0_LOAD #endif - -#define MIN_GROUP_SHARES 2 - -static int init_task_group_load = INIT_TASK_GROUP_LOAD; +}; /* return group to which a task belongs */ static inline struct task_group *task_group(struct task_struct *p) { struct task_group *tg; -#ifdef CONFIG_FAIR_USER_SCHED +#ifdef CONFIG_USER_SCHED tg = p->user->tg; -#elif defined(CONFIG_FAIR_CGROUP_SCHED) +#elif defined(CONFIG_CGROUP_SCHED) tg = container_of(task_subsys_state(p, cpu_cgroup_subsys_id), struct task_group, css); #else @@ -288,21 +303,15 @@ static inline struct task_group *task_group(struct task_struct *p) /* Change a task's cfs_rq and parent entity if it moves across CPUs/groups */ static inline void set_task_rq(struct task_struct *p, unsigned int cpu) { +#ifdef CONFIG_FAIR_GROUP_SCHED p->se.cfs_rq = task_group(p)->cfs_rq[cpu]; p->se.parent = task_group(p)->se[cpu]; +#endif +#ifdef CONFIG_RT_GROUP_SCHED p->rt.rt_rq = task_group(p)->rt_rq[cpu]; p->rt.parent = task_group(p)->rt_se[cpu]; -} - -static inline void lock_task_group_list(void) -{ - mutex_lock(&task_group_mutex); -} - -static inline void unlock_task_group_list(void) -{ - mutex_unlock(&task_group_mutex); +#endif } static inline void lock_doms_cur(void) @@ -318,12 +327,10 @@ static inline void unlock_doms_cur(void) #else static inline void set_task_rq(struct task_struct *p, unsigned int cpu) { } -static inline void lock_task_group_list(void) { } -static inline void unlock_task_group_list(void) { } static inline void lock_doms_cur(void) { } static inline void unlock_doms_cur(void) { } -#endif /* CONFIG_FAIR_GROUP_SCHED */ +#endif /* CONFIG_GROUP_SCHED */ /* CFS-related fields in a runqueue */ struct cfs_rq { @@ -363,7 +370,7 @@ struct cfs_rq { struct rt_rq { struct rt_prio_array active; unsigned long rt_nr_running; -#if defined CONFIG_SMP || defined CONFIG_FAIR_GROUP_SCHED +#if defined CONFIG_SMP || defined CONFIG_RT_GROUP_SCHED int highest_prio; /* highest queued rt task prio */ #endif #ifdef CONFIG_SMP @@ -373,7 +380,9 @@ struct rt_rq { int rt_throttled; u64 rt_time; -#ifdef CONFIG_FAIR_GROUP_SCHED +#ifdef CONFIG_RT_GROUP_SCHED + unsigned long rt_nr_boosted; + struct rq *rq; struct list_head leaf_rt_rq_list; struct task_group *tg; @@ -447,6 +456,8 @@ struct rq { #ifdef CONFIG_FAIR_GROUP_SCHED /* list of leaf cfs_rq on this cpu: */ struct list_head leaf_cfs_rq_list; +#endif +#ifdef CONFIG_RT_GROUP_SCHED struct list_head leaf_rt_rq_list; #endif @@ -652,19 +663,21 @@ const_debug unsigned int sysctl_sched_features = const_debug unsigned int sysctl_sched_nr_migrate = 32; /* - * period over which we measure -rt task cpu usage in ms. + * period over which we measure -rt task cpu usage in us. * default: 1s */ -const_debug unsigned int sysctl_sched_rt_period = 1000; +unsigned int sysctl_sched_rt_period = 1000000; -#define SCHED_RT_FRAC_SHIFT 16 -#define SCHED_RT_FRAC (1UL << SCHED_RT_FRAC_SHIFT) +/* + * part of the period that we allow rt tasks to run in us. + * default: 0.95s + */ +int sysctl_sched_rt_runtime = 950000; /* - * ratio of time -rt tasks may consume. - * default: 95% + * single value that denotes runtime == period, ie unlimited time. */ -const_debug unsigned int sysctl_sched_rt_ratio = 62259; +#define RUNTIME_INF ((u64)~0ULL) /* * For kernel-internal use: high-speed (but slightly incorrect) per-cpu @@ -4571,6 +4584,15 @@ recheck: return -EPERM; } +#ifdef CONFIG_RT_GROUP_SCHED + /* + * Do not allow realtime tasks into groups that have no runtime + * assigned. + */ + if (rt_policy(policy) && task_group(p)->rt_runtime == 0) + return -EPERM; +#endif + retval = security_task_setscheduler(p, policy, param); if (retval) return retval; @@ -7112,7 +7134,7 @@ static void init_rt_rq(struct rt_rq *rt_rq, struct rq *rq) /* delimiter for bitsearch: */ __set_bit(MAX_RT_PRIO, array->bitmap); -#if defined CONFIG_SMP || defined CONFIG_FAIR_GROUP_SCHED +#if defined CONFIG_SMP || defined CONFIG_RT_GROUP_SCHED rt_rq->highest_prio = MAX_RT_PRIO; #endif #ifdef CONFIG_SMP @@ -7123,7 +7145,8 @@ static void init_rt_rq(struct rt_rq *rt_rq, struct rq *rq) rt_rq->rt_time = 0; rt_rq->rt_throttled = 0; -#ifdef CONFIG_FAIR_GROUP_SCHED +#ifdef CONFIG_RT_GROUP_SCHED + rt_rq->rt_nr_boosted = 0; rt_rq->rq = rq; #endif } @@ -7146,7 +7169,9 @@ static void init_tg_cfs_entry(struct rq *rq, struct task_group *tg, se->load.inv_weight = div64_64(1ULL<<32, se->load.weight); se->parent = NULL; } +#endif +#ifdef CONFIG_RT_GROUP_SCHED static void init_tg_rt_entry(struct rq *rq, struct task_group *tg, struct rt_rq *rt_rq, struct sched_rt_entity *rt_se, int cpu, int add) @@ -7175,7 +7200,7 @@ void __init sched_init(void) init_defrootdomain(); #endif -#ifdef CONFIG_FAIR_GROUP_SCHED +#ifdef CONFIG_GROUP_SCHED list_add(&init_task_group.list, &task_groups); #endif @@ -7196,7 +7221,10 @@ void __init sched_init(void) &per_cpu(init_cfs_rq, i), &per_cpu(init_sched_entity, i), i, 1); - init_task_group.rt_ratio = sysctl_sched_rt_ratio; /* XXX */ +#endif +#ifdef CONFIG_RT_GROUP_SCHED + init_task_group.rt_runtime = + sysctl_sched_rt_runtime * NSEC_PER_USEC; INIT_LIST_HEAD(&rq->leaf_rt_rq_list); init_tg_rt_entry(rq, &init_task_group, &per_cpu(init_rt_rq, i), @@ -7303,7 +7331,7 @@ void normalize_rt_tasks(void) unsigned long flags; struct rq *rq; - read_lock_irq(&tasklist_lock); + read_lock_irqsave(&tasklist_lock, flags); do_each_thread(g, p) { /* * Only normalize user tasks: @@ -7329,16 +7357,16 @@ void normalize_rt_tasks(void) continue; } - spin_lock_irqsave(&p->pi_lock, flags); + spin_lock(&p->pi_lock); rq = __task_rq_lock(p); normalize_task(rq, p); __task_rq_unlock(rq); - spin_unlock_irqrestore(&p->pi_lock, flags); + spin_unlock(&p->pi_lock); } while_each_thread(g, p); - read_unlock_irq(&tasklist_lock); + read_unlock_irqrestore(&tasklist_lock, flags); } #endif /* CONFIG_MAGIC_SYSRQ */ @@ -7387,9 +7415,9 @@ void set_curr_task(int cpu, struct task_struct *p) #endif -#ifdef CONFIG_FAIR_GROUP_SCHED +#ifdef CONFIG_GROUP_SCHED -#ifdef CONFIG_SMP +#if defined CONFIG_FAIR_GROUP_SCHED && defined CONFIG_SMP /* * distribute shares of all task groups among their schedulable entities, * to reflect load distribution across cpus. @@ -7540,7 +7568,8 @@ static int load_balance_monitor(void *unused) } #endif /* CONFIG_SMP */ -static void free_sched_group(struct task_group *tg) +#ifdef CONFIG_FAIR_GROUP_SCHED +static void free_fair_sched_group(struct task_group *tg) { int i; @@ -7549,49 +7578,27 @@ static void free_sched_group(struct task_group *tg) kfree(tg->cfs_rq[i]); if (tg->se) kfree(tg->se[i]); - if (tg->rt_rq) - kfree(tg->rt_rq[i]); - if (tg->rt_se) - kfree(tg->rt_se[i]); } kfree(tg->cfs_rq); kfree(tg->se); - kfree(tg->rt_rq); - kfree(tg->rt_se); - kfree(tg); } -/* allocate runqueue etc for a new task group */ -struct task_group *sched_create_group(void) +static int alloc_fair_sched_group(struct task_group *tg) { - struct task_group *tg; struct cfs_rq *cfs_rq; struct sched_entity *se; - struct rt_rq *rt_rq; - struct sched_rt_entity *rt_se; struct rq *rq; int i; - tg = kzalloc(sizeof(*tg), GFP_KERNEL); - if (!tg) - return ERR_PTR(-ENOMEM); - tg->cfs_rq = kzalloc(sizeof(cfs_rq) * NR_CPUS, GFP_KERNEL); if (!tg->cfs_rq) goto err; tg->se = kzalloc(sizeof(se) * NR_CPUS, GFP_KERNEL); if (!tg->se) goto err; - tg->rt_rq = kzalloc(sizeof(rt_rq) * NR_CPUS, GFP_KERNEL); - if (!tg->rt_rq) - goto err; - tg->rt_se = kzalloc(sizeof(rt_se) * NR_CPUS, GFP_KERNEL); - if (!tg->rt_se) - goto err; tg->shares = NICE_0_LOAD; - tg->rt_ratio = 0; /* XXX */ for_each_possible_cpu(i) { rq = cpu_rq(i); @@ -7606,6 +7613,79 @@ struct task_group *sched_create_group(void) if (!se) goto err; + init_tg_cfs_entry(rq, tg, cfs_rq, se, i, 0); + } + + return 1; + + err: + return 0; +} + +static inline void register_fair_sched_group(struct task_group *tg, int cpu) +{ + list_add_rcu(&tg->cfs_rq[cpu]->leaf_cfs_rq_list, + &cpu_rq(cpu)->leaf_cfs_rq_list); +} + +static inline void unregister_fair_sched_group(struct task_group *tg, int cpu) +{ + list_del_rcu(&tg->cfs_rq[cpu]->leaf_cfs_rq_list); +} +#else +static inline void free_fair_sched_group(struct task_group *tg) +{ +} + +static inline int alloc_fair_sched_group(struct task_group *tg) +{ + return 1; +} + +static inline void register_fair_sched_group(struct task_group *tg, int cpu) +{ +} + +static inline void unregister_fair_sched_group(struct task_group *tg, int cpu) +{ +} +#endif + +#ifdef CONFIG_RT_GROUP_SCHED +static void free_rt_sched_group(struct task_group *tg) +{ + int i; + + for_each_possible_cpu(i) { + if (tg->rt_rq) + kfree(tg->rt_rq[i]); + if (tg->rt_se) + kfree(tg->rt_se[i]); + } + + kfree(tg->rt_rq); + kfree(tg->rt_se); +} + +static int alloc_rt_sched_group(struct task_group *tg) +{ + struct rt_rq *rt_rq; + struct sched_rt_entity *rt_se; + struct rq *rq; + int i; + + tg->rt_rq = kzalloc(sizeof(rt_rq) * NR_CPUS, GFP_KERNEL); + if (!tg->rt_rq) + goto err; + tg->rt_se = kzalloc(sizeof(rt_se) * NR_CPUS, GFP_KERNEL); + if (!tg->rt_se) + goto err; + + tg->rt_runtime = 0; + + for_each_possible_cpu(i) { + rq = cpu_rq(i); + rt_rq = kmalloc_node(sizeof(struct rt_rq), GFP_KERNEL|__GFP_ZERO, cpu_to_node(i)); if (!rt_rq) @@ -7616,20 +7696,75 @@ struct task_group *sched_create_group(void) if (!rt_se) goto err; - init_tg_cfs_entry(rq, tg, cfs_rq, se, i, 0); init_tg_rt_entry(rq, tg, rt_rq, rt_se, i, 0); } - lock_task_group_list(); + return 1; + + err: + return 0; +} + +static inline void register_rt_sched_group(struct task_group *tg, int cpu) +{ + list_add_rcu(&tg->rt_rq[cpu]->leaf_rt_rq_list, + &cpu_rq(cpu)->leaf_rt_rq_list); +} + +static inline void unregister_rt_sched_group(struct task_group *tg, int cpu) +{ + list_del_rcu(&tg->rt_rq[cpu]->leaf_rt_rq_list); +} +#else +static inline void free_rt_sched_group(struct task_group *tg) +{ +} + +static inline int alloc_rt_sched_group(struct task_group *tg) +{ + return 1; +} + +static inline void register_rt_sched_group(struct task_group *tg, int cpu) +{ +} + +static inline void unregister_rt_sched_group(struct task_group *tg, int cpu) +{ +} +#endif + +static void free_sched_group(struct task_group *tg) +{ + free_fair_sched_group(tg); + free_rt_sched_group(tg); + kfree(tg); +} + +/* allocate runqueue etc for a new task group */ +struct task_group *sched_create_group(void) +{ + struct task_group *tg; + unsigned long flags; + int i; + + tg = kzalloc(sizeof(*tg), GFP_KERNEL); + if (!tg) + return ERR_PTR(-ENOMEM); + + if (!alloc_fair_sched_group(tg)) + goto err; + + if (!alloc_rt_sched_group(tg)) + goto err; + + spin_lock_irqsave(&task_group_lock, flags); for_each_possible_cpu(i) { - rq = cpu_rq(i); - cfs_rq = tg->cfs_rq[i]; - list_add_rcu(&cfs_rq->leaf_cfs_rq_list, &rq->leaf_cfs_rq_list); - rt_rq = tg->rt_rq[i]; - list_add_rcu(&rt_rq->leaf_rt_rq_list, &rq->leaf_rt_rq_list); + register_fair_sched_group(tg, i); + register_rt_sched_group(tg, i); } list_add_rcu(&tg->list, &task_groups); - unlock_task_group_list(); + spin_unlock_irqrestore(&task_group_lock, flags); return tg; @@ -7648,21 +7783,16 @@ static void free_sched_group_rcu(struct rcu_head *rhp) /* Destroy runqueue etc associated with a task group */ void sched_destroy_group(struct task_group *tg) { - struct cfs_rq *cfs_rq = NULL; - struct rt_rq *rt_rq = NULL; + unsigned long flags; int i; - lock_task_group_list(); + spin_lock_irqsave(&task_group_lock, flags); for_each_possible_cpu(i) { - cfs_rq = tg->cfs_rq[i]; - list_del_rcu(&cfs_rq->leaf_cfs_rq_list); - rt_rq = tg->rt_rq[i]; - list_del_rcu(&rt_rq->leaf_rt_rq_list); + unregister_fair_sched_group(tg, i); + unregister_rt_sched_group(tg, i); } list_del_rcu(&tg->list); - unlock_task_group_list(); - - BUG_ON(!cfs_rq); + spin_unlock_irqrestore(&task_group_lock, flags); /* wait for possible concurrent references to cfs_rqs complete */ call_rcu(&tg->rcu, free_sched_group_rcu); @@ -7703,6 +7833,7 @@ void sched_move_task(struct task_struct *tsk) task_rq_unlock(rq, &flags); } +#ifdef CONFIG_FAIR_GROUP_SCHED /* rq->lock to be locked by caller */ static void set_se_shares(struct sched_entity *se, unsigned long shares) { @@ -7728,13 +7859,14 @@ static void set_se_shares(struct sched_entity *se, unsigned long shares) } } +static DEFINE_MUTEX(shares_mutex); + int sched_group_set_shares(struct task_group *tg, unsigned long shares) { int i; - struct cfs_rq *cfs_rq; - struct rq *rq; + unsigned long flags; - lock_task_group_list(); + mutex_lock(&shares_mutex); if (tg->shares == shares) goto done; @@ -7746,10 +7878,10 @@ int sched_group_set_shares(struct task_group *tg, unsigned long shares) * load_balance_fair) from referring to this group first, * by taking it off the rq->leaf_cfs_rq_list on each cpu. */ - for_each_possible_cpu(i) { - cfs_rq = tg->cfs_rq[i]; - list_del_rcu(&cfs_rq->leaf_cfs_rq_list); - } + spin_lock_irqsave(&task_group_lock, flags); + for_each_possible_cpu(i) + unregister_fair_sched_group(tg, i); + spin_unlock_irqrestore(&task_group_lock, flags); /* wait for any ongoing reference to this group to finish */ synchronize_sched(); @@ -7769,13 +7901,12 @@ int sched_group_set_shares(struct task_group *tg, unsigned long shares) * Enable load balance activity on this group, by inserting it back on * each cpu's rq->leaf_cfs_rq_list. */ - for_each_possible_cpu(i) { - rq = cpu_rq(i); - cfs_rq = tg->cfs_rq[i]; - list_add_rcu(&cfs_rq->leaf_cfs_rq_list, &rq->leaf_cfs_rq_list); - } + spin_lock_irqsave(&task_group_lock, flags); + for_each_possible_cpu(i) + register_fair_sched_group(tg, i); + spin_unlock_irqrestore(&task_group_lock, flags); done: - unlock_task_group_list(); + mutex_unlock(&shares_mutex); return 0; } @@ -7783,35 +7914,84 @@ unsigned long sched_group_shares(struct task_group *tg) { return tg->shares; } +#endif +#ifdef CONFIG_RT_GROUP_SCHED /* - * Ensure the total rt_ratio <= sysctl_sched_rt_ratio + * Ensure that the real time constraints are schedulable. */ -int sched_group_set_rt_ratio(struct task_group *tg, unsigned long rt_ratio) +static DEFINE_MUTEX(rt_constraints_mutex); + +static unsigned long to_ratio(u64 period, u64 runtime) +{ + if (runtime == RUNTIME_INF) + return 1ULL << 16; + + runtime *= (1ULL << 16); + div64_64(runtime, period); + return runtime; +} + +static int __rt_schedulable(struct task_group *tg, u64 period, u64 runtime) { struct task_group *tgi; unsigned long total = 0; + unsigned long global_ratio = + to_ratio(sysctl_sched_rt_period, + sysctl_sched_rt_runtime < 0 ? + RUNTIME_INF : sysctl_sched_rt_runtime); rcu_read_lock(); - list_for_each_entry_rcu(tgi, &task_groups, list) - total += tgi->rt_ratio; - rcu_read_unlock(); + list_for_each_entry_rcu(tgi, &task_groups, list) { + if (tgi == tg) + continue; - if (total + rt_ratio - tg->rt_ratio > sysctl_sched_rt_ratio) - return -EINVAL; + total += to_ratio(period, tgi->rt_runtime); + } + rcu_read_unlock(); - tg->rt_ratio = rt_ratio; - return 0; + return total + to_ratio(period, runtime) < global_ratio; } -unsigned long sched_group_rt_ratio(struct task_group *tg) +int sched_group_set_rt_runtime(struct task_group *tg, long rt_runtime_us) { - return tg->rt_ratio; + u64 rt_runtime, rt_period; + int err = 0; + + rt_period = sysctl_sched_rt_period * NSEC_PER_USEC; + rt_runtime = (u64)rt_runtime_us * NSEC_PER_USEC; + if (rt_runtime_us == -1) + rt_runtime = rt_period; + + mutex_lock(&rt_constraints_mutex); + if (!__rt_schedulable(tg, rt_period, rt_runtime)) { + err = -EINVAL; + goto unlock; + } + if (rt_runtime_us == -1) + rt_runtime = RUNTIME_INF; + tg->rt_runtime = rt_runtime; + unlock: + mutex_unlock(&rt_constraints_mutex); + + return err; } -#endif /* CONFIG_FAIR_GROUP_SCHED */ +long sched_group_rt_runtime(struct task_group *tg) +{ + u64 rt_runtime_us; + + if (tg->rt_runtime == RUNTIME_INF) + return -1; + + rt_runtime_us = tg->rt_runtime; + do_div(rt_runtime_us, NSEC_PER_USEC); + return rt_runtime_us; +} +#endif +#endif /* CONFIG_GROUP_SCHED */ -#ifdef CONFIG_FAIR_CGROUP_SCHED +#ifdef CONFIG_CGROUP_SCHED /* return corresponding task_group object of a cgroup */ static inline struct task_group *cgroup_tg(struct cgroup *cgrp) @@ -7857,9 +8037,15 @@ static int cpu_cgroup_can_attach(struct cgroup_subsys *ss, struct cgroup *cgrp, struct task_struct *tsk) { +#ifdef CONFIG_RT_GROUP_SCHED + /* Don't accept realtime tasks when there is no way for them to run */ + if (rt_task(tsk) && cgroup_tg(cgrp)->rt_runtime == 0) + return -EINVAL; +#else /* We don't support RT-tasks being in separate groups */ if (tsk->sched_class != &fair_sched_class) return -EINVAL; +#endif return 0; } @@ -7871,6 +8057,7 @@ cpu_cgroup_attach(struct cgroup_subsys *ss, struct cgroup *cgrp, sched_move_task(tsk); } +#ifdef CONFIG_FAIR_GROUP_SCHED static int cpu_shares_write_uint(struct cgroup *cgrp, struct cftype *cftype, u64 shareval) { @@ -7883,31 +8070,70 @@ static u64 cpu_shares_read_uint(struct cgroup *cgrp, struct cftype *cft) return (u64) tg->shares; } +#endif -static int cpu_rt_ratio_write_uint(struct cgroup *cgrp, struct cftype *cftype, - u64 rt_ratio_val) +#ifdef CONFIG_RT_GROUP_SCHED +static int cpu_rt_runtime_write(struct cgroup *cgrp, struct cftype *cft, + struct file *file, + const char __user *userbuf, + size_t nbytes, loff_t *unused_ppos) { - return sched_group_set_rt_ratio(cgroup_tg(cgrp), rt_ratio_val); + char buffer[64]; + int retval = 0; + s64 val; + char *end; + + if (!nbytes) + return -EINVAL; + if (nbytes >= sizeof(buffer)) + return -E2BIG; + if (copy_from_user(buffer, userbuf, nbytes)) + return -EFAULT; + + buffer[nbytes] = 0; /* nul-terminate */ + + /* strip newline if necessary */ + if (nbytes && (buffer[nbytes-1] == '\n')) + buffer[nbytes-1] = 0; + val = simple_strtoll(buffer, &end, 0); + if (*end) + return -EINVAL; + + /* Pass to subsystem */ + retval = sched_group_set_rt_runtime(cgroup_tg(cgrp), val); + if (!retval) + retval = nbytes; + return retval; } -static u64 cpu_rt_ratio_read_uint(struct cgroup *cgrp, struct cftype *cft) +static ssize_t cpu_rt_runtime_read(struct cgroup *cgrp, struct cftype *cft, + struct file *file, + char __user *buf, size_t nbytes, + loff_t *ppos) { - struct task_group *tg = cgroup_tg(cgrp); + char tmp[64]; + long val = sched_group_rt_runtime(cgroup_tg(cgrp)); + int len = sprintf(tmp, "%ld\n", val); - return (u64) tg->rt_ratio; + return simple_read_from_buffer(buf, nbytes, ppos, tmp, len); } +#endif static struct cftype cpu_files[] = { +#ifdef CONFIG_FAIR_GROUP_SCHED { .name = "shares", .read_uint = cpu_shares_read_uint, .write_uint = cpu_shares_write_uint, }, +#endif +#ifdef CONFIG_RT_GROUP_SCHED { - .name = "rt_ratio", - .read_uint = cpu_rt_ratio_read_uint, - .write_uint = cpu_rt_ratio_write_uint, + .name = "rt_runtime_us", + .read = cpu_rt_runtime_read, + .write = cpu_rt_runtime_write, }, +#endif }; static int cpu_cgroup_populate(struct cgroup_subsys *ss, struct cgroup *cont) @@ -7926,7 +8152,7 @@ struct cgroup_subsys cpu_cgroup_subsys = { .early_init = 1, }; -#endif /* CONFIG_FAIR_CGROUP_SCHED */ +#endif /* CONFIG_CGROUP_SCHED */ #ifdef CONFIG_CGROUP_CPUACCT diff --git a/kernel/sched_rt.c b/kernel/sched_rt.c index 274b40d7bef..f54792b175b 100644 --- a/kernel/sched_rt.c +++ b/kernel/sched_rt.c @@ -55,14 +55,14 @@ static inline int on_rt_rq(struct sched_rt_entity *rt_se) return !list_empty(&rt_se->run_list); } -#ifdef CONFIG_FAIR_GROUP_SCHED +#ifdef CONFIG_RT_GROUP_SCHED -static inline unsigned int sched_rt_ratio(struct rt_rq *rt_rq) +static inline u64 sched_rt_runtime(struct rt_rq *rt_rq) { if (!rt_rq->tg) - return SCHED_RT_FRAC; + return RUNTIME_INF; - return rt_rq->tg->rt_ratio; + return rt_rq->tg->rt_runtime; } #define for_each_leaf_rt_rq(rt_rq, rq) \ @@ -89,7 +89,7 @@ static inline struct rt_rq *group_rt_rq(struct sched_rt_entity *rt_se) static void enqueue_rt_entity(struct sched_rt_entity *rt_se); static void dequeue_rt_entity(struct sched_rt_entity *rt_se); -static void sched_rt_ratio_enqueue(struct rt_rq *rt_rq) +static void sched_rt_rq_enqueue(struct rt_rq *rt_rq) { struct sched_rt_entity *rt_se = rt_rq->rt_se; @@ -102,7 +102,7 @@ static void sched_rt_ratio_enqueue(struct rt_rq *rt_rq) } } -static void sched_rt_ratio_dequeue(struct rt_rq *rt_rq) +static void sched_rt_rq_dequeue(struct rt_rq *rt_rq) { struct sched_rt_entity *rt_se = rt_rq->rt_se; @@ -110,11 +110,31 @@ static void sched_rt_ratio_dequeue(struct rt_rq *rt_rq) dequeue_rt_entity(rt_se); } +static inline int rt_rq_throttled(struct rt_rq *rt_rq) +{ + return rt_rq->rt_throttled && !rt_rq->rt_nr_boosted; +} + +static int rt_se_boosted(struct sched_rt_entity *rt_se) +{ + struct rt_rq *rt_rq = group_rt_rq(rt_se); + struct task_struct *p; + + if (rt_rq) + return !!rt_rq->rt_nr_boosted; + + p = rt_task_of(rt_se); + return p->prio != p->normal_prio; +} + #else -static inline unsigned int sched_rt_ratio(struct rt_rq *rt_rq) +static inline u64 sched_rt_runtime(struct rt_rq *rt_rq) { - return sysctl_sched_rt_ratio; + if (sysctl_sched_rt_runtime == -1) + return RUNTIME_INF; + + return (u64)sysctl_sched_rt_runtime * NSEC_PER_USEC; } #define for_each_leaf_rt_rq(rt_rq, rq) \ @@ -141,19 +161,23 @@ static inline struct rt_rq *group_rt_rq(struct sched_rt_entity *rt_se) return NULL; } -static inline void sched_rt_ratio_enqueue(struct rt_rq *rt_rq) +static inline void sched_rt_rq_enqueue(struct rt_rq *rt_rq) { } -static inline void sched_rt_ratio_dequeue(struct rt_rq *rt_rq) +static inline void sched_rt_rq_dequeue(struct rt_rq *rt_rq) { } +static inline int rt_rq_throttled(struct rt_rq *rt_rq) +{ + return rt_rq->rt_throttled; +} #endif static inline int rt_se_prio(struct sched_rt_entity *rt_se) { -#ifdef CONFIG_FAIR_GROUP_SCHED +#ifdef CONFIG_RT_GROUP_SCHED struct rt_rq *rt_rq = group_rt_rq(rt_se); if (rt_rq) @@ -163,28 +187,26 @@ static inline int rt_se_prio(struct sched_rt_entity *rt_se) return rt_task_of(rt_se)->prio; } -static int sched_rt_ratio_exceeded(struct rt_rq *rt_rq) +static int sched_rt_runtime_exceeded(struct rt_rq *rt_rq) { - unsigned int rt_ratio = sched_rt_ratio(rt_rq); - u64 period, ratio; + u64 runtime = sched_rt_runtime(rt_rq); - if (rt_ratio == SCHED_RT_FRAC) + if (runtime == RUNTIME_INF) return 0; if (rt_rq->rt_throttled) - return 1; - - period = (u64)sysctl_sched_rt_period * NSEC_PER_MSEC; - ratio = (period * rt_ratio) >> SCHED_RT_FRAC_SHIFT; + return rt_rq_throttled(rt_rq); - if (rt_rq->rt_time > ratio) { + if (rt_rq->rt_time > runtime) { struct rq *rq = rq_of_rt_rq(rt_rq); rq->rt_throttled = 1; rt_rq->rt_throttled = 1; - sched_rt_ratio_dequeue(rt_rq); - return 1; + if (rt_rq_throttled(rt_rq)) { + sched_rt_rq_dequeue(rt_rq); + return 1; + } } return 0; @@ -196,17 +218,16 @@ static void update_sched_rt_period(struct rq *rq) u64 period; while (rq->clock > rq->rt_period_expire) { - period = (u64)sysctl_sched_rt_period * NSEC_PER_MSEC; + period = (u64)sysctl_sched_rt_period * NSEC_PER_USEC; rq->rt_period_expire += period; for_each_leaf_rt_rq(rt_rq, rq) { - unsigned long rt_ratio = sched_rt_ratio(rt_rq); - u64 ratio = (period * rt_ratio) >> SCHED_RT_FRAC_SHIFT; + u64 runtime = sched_rt_runtime(rt_rq); - rt_rq->rt_time -= min(rt_rq->rt_time, ratio); - if (rt_rq->rt_throttled) { + rt_rq->rt_time -= min(rt_rq->rt_time, runtime); + if (rt_rq->rt_throttled && rt_rq->rt_time < runtime) { rt_rq->rt_throttled = 0; - sched_rt_ratio_enqueue(rt_rq); + sched_rt_rq_enqueue(rt_rq); } } @@ -239,12 +260,7 @@ static void update_curr_rt(struct rq *rq) cpuacct_charge(curr, delta_exec); rt_rq->rt_time += delta_exec; - /* - * might make it a tad more accurate: - * - * update_sched_rt_period(rq); - */ - if (sched_rt_ratio_exceeded(rt_rq)) + if (sched_rt_runtime_exceeded(rt_rq)) resched_task(curr); } @@ -253,7 +269,7 @@ void inc_rt_tasks(struct sched_rt_entity *rt_se, struct rt_rq *rt_rq) { WARN_ON(!rt_prio(rt_se_prio(rt_se))); rt_rq->rt_nr_running++; -#if defined CONFIG_SMP || defined CONFIG_FAIR_GROUP_SCHED +#if defined CONFIG_SMP || defined CONFIG_RT_GROUP_SCHED if (rt_se_prio(rt_se) < rt_rq->highest_prio) rt_rq->highest_prio = rt_se_prio(rt_se); #endif @@ -265,6 +281,10 @@ void inc_rt_tasks(struct sched_rt_entity *rt_se, struct rt_rq *rt_rq) update_rt_migration(rq_of_rt_rq(rt_rq)); #endif +#ifdef CONFIG_RT_GROUP_SCHED + if (rt_se_boosted(rt_se)) + rt_rq->rt_nr_boosted++; +#endif } static inline @@ -273,7 +293,7 @@ void dec_rt_tasks(struct sched_rt_entity *rt_se, struct rt_rq *rt_rq) WARN_ON(!rt_prio(rt_se_prio(rt_se))); WARN_ON(!rt_rq->rt_nr_running); rt_rq->rt_nr_running--; -#if defined CONFIG_SMP || defined CONFIG_FAIR_GROUP_SCHED +#if defined CONFIG_SMP || defined CONFIG_RT_GROUP_SCHED if (rt_rq->rt_nr_running) { struct rt_prio_array *array; @@ -295,6 +315,12 @@ void dec_rt_tasks(struct sched_rt_entity *rt_se, struct rt_rq *rt_rq) update_rt_migration(rq_of_rt_rq(rt_rq)); #endif /* CONFIG_SMP */ +#ifdef CONFIG_RT_GROUP_SCHED + if (rt_se_boosted(rt_se)) + rt_rq->rt_nr_boosted--; + + WARN_ON(!rt_rq->rt_nr_running && rt_rq->rt_nr_boosted); +#endif } static void enqueue_rt_entity(struct sched_rt_entity *rt_se) @@ -303,7 +329,7 @@ static void enqueue_rt_entity(struct sched_rt_entity *rt_se) struct rt_prio_array *array = &rt_rq->active; struct rt_rq *group_rq = group_rt_rq(rt_se); - if (group_rq && group_rq->rt_throttled) + if (group_rq && rt_rq_throttled(group_rq)) return; list_add_tail(&rt_se->run_list, array->queue + rt_se_prio(rt_se)); @@ -496,7 +522,7 @@ static struct task_struct *pick_next_task_rt(struct rq *rq) if (unlikely(!rt_rq->rt_nr_running)) return NULL; - if (sched_rt_ratio_exceeded(rt_rq)) + if (rt_rq_throttled(rt_rq)) return NULL; do { diff --git a/kernel/signal.c b/kernel/signal.c index 2c1f08defac..84917fe507f 100644 --- a/kernel/signal.c +++ b/kernel/signal.c @@ -972,7 +972,7 @@ void zap_other_threads(struct task_struct *p) } } -int fastcall __fatal_signal_pending(struct task_struct *tsk) +int __fatal_signal_pending(struct task_struct *tsk) { return sigismember(&tsk->pending.signal, SIGKILL); } diff --git a/kernel/sysctl.c b/kernel/sysctl.c index d41ef6b4cf7..8b7e9541179 100644 --- a/kernel/sysctl.c +++ b/kernel/sysctl.c @@ -311,22 +311,6 @@ static struct ctl_table kern_table[] = { .mode = 0644, .proc_handler = &proc_dointvec, }, - { - .ctl_name = CTL_UNNUMBERED, - .procname = "sched_rt_period_ms", - .data = &sysctl_sched_rt_period, - .maxlen = sizeof(unsigned int), - .mode = 0644, - .proc_handler = &proc_dointvec, - }, - { - .ctl_name = CTL_UNNUMBERED, - .procname = "sched_rt_ratio", - .data = &sysctl_sched_rt_ratio, - .maxlen = sizeof(unsigned int), - .mode = 0644, - .proc_handler = &proc_dointvec, - }, #if defined(CONFIG_FAIR_GROUP_SCHED) && defined(CONFIG_SMP) { .ctl_name = CTL_UNNUMBERED, @@ -348,6 +332,22 @@ static struct ctl_table kern_table[] = { #endif { .ctl_name = CTL_UNNUMBERED, + .procname = "sched_rt_period_us", + .data = &sysctl_sched_rt_period, + .maxlen = sizeof(unsigned int), + .mode = 0644, + .proc_handler = &proc_dointvec, + }, + { + .ctl_name = CTL_UNNUMBERED, + .procname = "sched_rt_runtime_us", + .data = &sysctl_sched_rt_runtime, + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = &proc_dointvec, + }, + { + .ctl_name = CTL_UNNUMBERED, .procname = "sched_compat_yield", .data = &sysctl_sched_compat_yield, .maxlen = sizeof(unsigned int), @@ -978,8 +978,8 @@ static struct ctl_table vm_table[] = { { .ctl_name = CTL_UNNUMBERED, .procname = "nr_overcommit_hugepages", - .data = &nr_overcommit_huge_pages, - .maxlen = sizeof(nr_overcommit_huge_pages), + .data = &sysctl_overcommit_huge_pages, + .maxlen = sizeof(sysctl_overcommit_huge_pages), .mode = 0644, .proc_handler = &hugetlb_overcommit_handler, }, diff --git a/kernel/time/timer_list.c b/kernel/time/timer_list.c index d3d94c1a0fd..67fe8fc21fb 100644 --- a/kernel/time/timer_list.c +++ b/kernel/time/timer_list.c @@ -65,9 +65,9 @@ print_timer(struct seq_file *m, struct hrtimer *timer, int idx, u64 now) SEQ_printf(m, ", %s/%d", tmp, timer->start_pid); #endif SEQ_printf(m, "\n"); - SEQ_printf(m, " # expires at %Lu nsecs [in %Lu nsecs]\n", + SEQ_printf(m, " # expires at %Lu nsecs [in %Ld nsecs]\n", (unsigned long long)ktime_to_ns(timer->expires), - (unsigned long long)(ktime_to_ns(timer->expires) - now)); + (long long)(ktime_to_ns(timer->expires) - now)); } static void diff --git a/kernel/timeconst.pl b/kernel/timeconst.pl index 62b1287932e..41468035473 100644 --- a/kernel/timeconst.pl +++ b/kernel/timeconst.pl @@ -339,7 +339,7 @@ sub output($@) print "\n"; foreach $pfx ('HZ_TO_MSEC','MSEC_TO_HZ', - 'USEC_TO_HZ','HZ_TO_USEC') { + 'HZ_TO_USEC','USEC_TO_HZ') { foreach $bit (32, 64) { foreach $suf ('MUL', 'ADJ', 'SHR') { printf "#define %-23s %s\n", diff --git a/kernel/user.c b/kernel/user.c index 7d7900c5a1f..7132022a040 100644 --- a/kernel/user.c +++ b/kernel/user.c @@ -57,7 +57,7 @@ struct user_struct root_user = { .uid_keyring = &root_user_keyring, .session_keyring = &root_session_keyring, #endif -#ifdef CONFIG_FAIR_USER_SCHED +#ifdef CONFIG_USER_SCHED .tg = &init_task_group, #endif }; @@ -90,7 +90,7 @@ static struct user_struct *uid_hash_find(uid_t uid, struct hlist_head *hashent) return NULL; } -#ifdef CONFIG_FAIR_USER_SCHED +#ifdef CONFIG_USER_SCHED static void sched_destroy_user(struct user_struct *up) { @@ -113,15 +113,15 @@ static void sched_switch_user(struct task_struct *p) sched_move_task(p); } -#else /* CONFIG_FAIR_USER_SCHED */ +#else /* CONFIG_USER_SCHED */ static void sched_destroy_user(struct user_struct *up) { } static int sched_create_user(struct user_struct *up) { return 0; } static void sched_switch_user(struct task_struct *p) { } -#endif /* CONFIG_FAIR_USER_SCHED */ +#endif /* CONFIG_USER_SCHED */ -#if defined(CONFIG_FAIR_USER_SCHED) && defined(CONFIG_SYSFS) +#if defined(CONFIG_USER_SCHED) && defined(CONFIG_SYSFS) static struct kset *uids_kset; /* represents the /sys/kernel/uids/ directory */ static DEFINE_MUTEX(uids_mutex); @@ -137,6 +137,7 @@ static inline void uids_mutex_unlock(void) } /* uid directory attributes */ +#ifdef CONFIG_FAIR_GROUP_SCHED static ssize_t cpu_shares_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf) @@ -163,10 +164,45 @@ static ssize_t cpu_shares_store(struct kobject *kobj, static struct kobj_attribute cpu_share_attr = __ATTR(cpu_share, 0644, cpu_shares_show, cpu_shares_store); +#endif + +#ifdef CONFIG_RT_GROUP_SCHED +static ssize_t cpu_rt_runtime_show(struct kobject *kobj, + struct kobj_attribute *attr, + char *buf) +{ + struct user_struct *up = container_of(kobj, struct user_struct, kobj); + + return sprintf(buf, "%lu\n", sched_group_rt_runtime(up->tg)); +} + +static ssize_t cpu_rt_runtime_store(struct kobject *kobj, + struct kobj_attribute *attr, + const char *buf, size_t size) +{ + struct user_struct *up = container_of(kobj, struct user_struct, kobj); + unsigned long rt_runtime; + int rc; + + sscanf(buf, "%lu", &rt_runtime); + + rc = sched_group_set_rt_runtime(up->tg, rt_runtime); + + return (rc ? rc : size); +} + +static struct kobj_attribute cpu_rt_runtime_attr = + __ATTR(cpu_rt_runtime, 0644, cpu_rt_runtime_show, cpu_rt_runtime_store); +#endif /* default attributes per uid directory */ static struct attribute *uids_attributes[] = { +#ifdef CONFIG_FAIR_GROUP_SCHED &cpu_share_attr.attr, +#endif +#ifdef CONFIG_RT_GROUP_SCHED + &cpu_rt_runtime_attr.attr, +#endif NULL }; @@ -269,7 +305,7 @@ static inline void free_user(struct user_struct *up, unsigned long flags) schedule_work(&up->work); } -#else /* CONFIG_FAIR_USER_SCHED && CONFIG_SYSFS */ +#else /* CONFIG_USER_SCHED && CONFIG_SYSFS */ int uids_sysfs_init(void) { return 0; } static inline int uids_user_create(struct user_struct *up) { return 0; } @@ -373,7 +409,7 @@ struct user_struct * alloc_uid(struct user_namespace *ns, uid_t uid) spin_lock_irq(&uidhash_lock); up = uid_hash_find(uid, hashent); if (up) { - /* This case is not possible when CONFIG_FAIR_USER_SCHED + /* This case is not possible when CONFIG_USER_SCHED * is defined, since we serialize alloc_uid() using * uids_mutex. Hence no need to call * sched_destroy_user() or remove_user_sysfs_dir(). diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug index a370fe828a7..ab408aa9b6d 100644 --- a/lib/Kconfig.debug +++ b/lib/Kconfig.debug @@ -82,6 +82,9 @@ config HEADERS_CHECK config DEBUG_SECTION_MISMATCH bool "Enable full Section mismatch analysis" depends on UNDEFINED + # This option is on purpose disabled for now. + # It will be enabled when we are down to a resonable number + # of section mismatch warnings (< 10 for an allyesconfig build) help The section mismatch analysis checks if there are illegal references from one section to another section. diff --git a/mm/filemap.c b/mm/filemap.c index b7b1be6dbd8..5c74b68935a 100644 --- a/mm/filemap.c +++ b/mm/filemap.c @@ -604,7 +604,7 @@ void __lock_page(struct page *page) } EXPORT_SYMBOL(__lock_page); -int fastcall __lock_page_killable(struct page *page) +int __lock_page_killable(struct page *page) { DEFINE_WAIT_BIT(wait, &page->flags, PG_locked); diff --git a/mm/hugetlb.c b/mm/hugetlb.c index d9a38031246..cb1b3a7ecdf 100644 --- a/mm/hugetlb.c +++ b/mm/hugetlb.c @@ -24,14 +24,15 @@ const unsigned long hugetlb_zero = 0, hugetlb_infinity = ~0UL; static unsigned long nr_huge_pages, free_huge_pages, resv_huge_pages; static unsigned long surplus_huge_pages; +static unsigned long nr_overcommit_huge_pages; unsigned long max_huge_pages; +unsigned long sysctl_overcommit_huge_pages; static struct list_head hugepage_freelists[MAX_NUMNODES]; static unsigned int nr_huge_pages_node[MAX_NUMNODES]; static unsigned int free_huge_pages_node[MAX_NUMNODES]; static unsigned int surplus_huge_pages_node[MAX_NUMNODES]; static gfp_t htlb_alloc_mask = GFP_HIGHUSER; unsigned long hugepages_treat_as_movable; -unsigned long nr_overcommit_huge_pages; static int hugetlb_next_nid; /* @@ -609,8 +610,9 @@ int hugetlb_overcommit_handler(struct ctl_table *table, int write, struct file *file, void __user *buffer, size_t *length, loff_t *ppos) { - spin_lock(&hugetlb_lock); proc_doulongvec_minmax(table, write, file, buffer, length, ppos); + spin_lock(&hugetlb_lock); + nr_overcommit_huge_pages = sysctl_overcommit_huge_pages; spin_unlock(&hugetlb_lock); return 0; } diff --git a/mm/memory.c b/mm/memory.c index 717aa0e3be2..ce3c9e4492d 100644 --- a/mm/memory.c +++ b/mm/memory.c @@ -2711,6 +2711,13 @@ void print_vma_addr(char *prefix, unsigned long ip) struct mm_struct *mm = current->mm; struct vm_area_struct *vma; + /* + * Do not print if we are in atomic + * contexts (in exception stacks, etc.): + */ + if (preempt_count()) + return; + down_read(&mm->mmap_sem); vma = find_vma(mm, ip); if (vma && vma->vm_file) { @@ -2719,7 +2726,7 @@ void print_vma_addr(char *prefix, unsigned long ip) if (buf) { char *p, *s; - p = d_path(f->f_dentry, f->f_vfsmnt, buf, PAGE_SIZE); + p = d_path(&f->f_path, buf, PAGE_SIZE); if (IS_ERR(p)) p = "?"; s = strrchr(p, '/'); diff --git a/mm/mempolicy.c b/mm/mempolicy.c index 8d246c3b340..6c7ba1a63d2 100644 --- a/mm/mempolicy.c +++ b/mm/mempolicy.c @@ -1996,7 +1996,7 @@ int show_numa_map(struct seq_file *m, void *v) if (file) { seq_printf(m, " file="); - seq_path(m, file->f_path.mnt, file->f_path.dentry, "\n\t= "); + seq_path(m, &file->f_path, "\n\t= "); } else if (vma->vm_start <= mm->brk && vma->vm_end >= mm->start_brk) { seq_printf(m, " heap"); } else if (vma->vm_start <= mm->start_stack && diff --git a/mm/slab.c b/mm/slab.c index 40c00dacbe4..473e6c2eaef 100644 --- a/mm/slab.c +++ b/mm/slab.c @@ -2630,6 +2630,7 @@ static struct slab *alloc_slabmgmt(struct kmem_cache *cachep, void *objp, slabp->colouroff = colour_off; slabp->s_mem = objp + colour_off; slabp->nodeid = nodeid; + slabp->free = 0; return slabp; } @@ -2683,7 +2684,6 @@ static void cache_init_objs(struct kmem_cache *cachep, slab_bufctl(slabp)[i] = i + 1; } slab_bufctl(slabp)[i - 1] = BUFCTL_END; - slabp->free = 0; } static void kmem_flagcheck(struct kmem_cache *cachep, gfp_t flags) @@ -2816,7 +2816,6 @@ static int cache_grow(struct kmem_cache *cachep, if (!slabp) goto opps1; - slabp->nodeid = nodeid; slab_map_pages(cachep, slabp, objp); cache_init_objs(cachep, slabp); diff --git a/mm/slub.c b/mm/slub.c index e2989ae243b..4b3895cb90e 100644 --- a/mm/slub.c +++ b/mm/slub.c @@ -211,6 +211,8 @@ static inline void ClearSlabDebug(struct page *page) /* Internal SLUB flags */ #define __OBJECT_POISON 0x80000000 /* Poison object */ #define __SYSFS_ADD_DEFERRED 0x40000000 /* Not yet visible via sysfs */ +#define __KMALLOC_CACHE 0x20000000 /* objects freed using kfree */ +#define __PAGE_ALLOC_FALLBACK 0x10000000 /* Allow fallback to page alloc */ /* Not all arches define cache_line_size */ #ifndef cache_line_size @@ -308,7 +310,7 @@ static inline int is_end(void *addr) return (unsigned long)addr & PAGE_MAPPING_ANON; } -void *slab_address(struct page *page) +static void *slab_address(struct page *page) { return page->end - PAGE_MAPPING_ANON; } @@ -1078,14 +1080,7 @@ static struct page *allocate_slab(struct kmem_cache *s, gfp_t flags, int node) struct page *page; int pages = 1 << s->order; - if (s->order) - flags |= __GFP_COMP; - - if (s->flags & SLAB_CACHE_DMA) - flags |= SLUB_DMA; - - if (s->flags & SLAB_RECLAIM_ACCOUNT) - flags |= __GFP_RECLAIMABLE; + flags |= s->allocflags; if (node == -1) page = alloc_pages(flags, s->order); @@ -1546,7 +1541,6 @@ load_freelist: unlock_out: slab_unlock(c->page); stat(c, ALLOC_SLOWPATH); -out: #ifdef SLUB_FASTPATH local_irq_restore(flags); #endif @@ -1581,8 +1575,24 @@ new_slab: c->page = new; goto load_freelist; } - object = NULL; - goto out; +#ifdef SLUB_FASTPATH + local_irq_restore(flags); +#endif + /* + * No memory available. + * + * If the slab uses higher order allocs but the object is + * smaller than a page size then we can fallback in emergencies + * to the page allocator via kmalloc_large. The page allocator may + * have failed to obtain a higher order page and we can try to + * allocate a single page if the object fits into a single page. + * That is only possible if certain conditions are met that are being + * checked when a slab is created. + */ + if (!(gfpflags & __GFP_NORETRY) && (s->flags & __PAGE_ALLOC_FALLBACK)) + return kmalloc_large(s->objsize, gfpflags); + + return NULL; debug: object = c->page->freelist; if (!alloc_debug_processing(s, c->page, object, addr)) @@ -2329,10 +2339,33 @@ static int calculate_sizes(struct kmem_cache *s) size = ALIGN(size, align); s->size = size; - s->order = calculate_order(size); + if ((flags & __KMALLOC_CACHE) && + PAGE_SIZE / size < slub_min_objects) { + /* + * Kmalloc cache that would not have enough objects in + * an order 0 page. Kmalloc slabs can fallback to + * page allocator order 0 allocs so take a reasonably large + * order that will allows us a good number of objects. + */ + s->order = max(slub_max_order, PAGE_ALLOC_COSTLY_ORDER); + s->flags |= __PAGE_ALLOC_FALLBACK; + s->allocflags |= __GFP_NOWARN; + } else + s->order = calculate_order(size); + if (s->order < 0) return 0; + s->allocflags = 0; + if (s->order) + s->allocflags |= __GFP_COMP; + + if (s->flags & SLAB_CACHE_DMA) + s->allocflags |= SLUB_DMA; + + if (s->flags & SLAB_RECLAIM_ACCOUNT) + s->allocflags |= __GFP_RECLAIMABLE; + /* * Determine the number of objects per slab */ @@ -2484,11 +2517,11 @@ EXPORT_SYMBOL(kmem_cache_destroy); * Kmalloc subsystem *******************************************************************/ -struct kmem_cache kmalloc_caches[PAGE_SHIFT] __cacheline_aligned; +struct kmem_cache kmalloc_caches[PAGE_SHIFT + 1] __cacheline_aligned; EXPORT_SYMBOL(kmalloc_caches); #ifdef CONFIG_ZONE_DMA -static struct kmem_cache *kmalloc_caches_dma[PAGE_SHIFT]; +static struct kmem_cache *kmalloc_caches_dma[PAGE_SHIFT + 1]; #endif static int __init setup_slub_min_order(char *str) @@ -2536,7 +2569,7 @@ static struct kmem_cache *create_kmalloc_cache(struct kmem_cache *s, down_write(&slub_lock); if (!kmem_cache_open(s, gfp_flags, name, size, ARCH_KMALLOC_MINALIGN, - flags, NULL)) + flags | __KMALLOC_CACHE, NULL)) goto panic; list_add(&s->list, &slab_caches); @@ -2670,9 +2703,8 @@ void *__kmalloc(size_t size, gfp_t flags) { struct kmem_cache *s; - if (unlikely(size > PAGE_SIZE / 2)) - return (void *)__get_free_pages(flags | __GFP_COMP, - get_order(size)); + if (unlikely(size > PAGE_SIZE)) + return kmalloc_large(size, flags); s = get_slab(size, flags); @@ -2688,9 +2720,8 @@ void *__kmalloc_node(size_t size, gfp_t flags, int node) { struct kmem_cache *s; - if (unlikely(size > PAGE_SIZE / 2)) - return (void *)__get_free_pages(flags | __GFP_COMP, - get_order(size)); + if (unlikely(size > PAGE_SIZE)) + return kmalloc_large(size, flags); s = get_slab(size, flags); @@ -3001,7 +3032,7 @@ void __init kmem_cache_init(void) caches++; } - for (i = KMALLOC_SHIFT_LOW; i < PAGE_SHIFT; i++) { + for (i = KMALLOC_SHIFT_LOW; i <= PAGE_SHIFT; i++) { create_kmalloc_cache(&kmalloc_caches[i], "kmalloc", 1 << i, GFP_KERNEL); caches++; @@ -3028,7 +3059,7 @@ void __init kmem_cache_init(void) slab_state = UP; /* Provide the correct kmalloc names now that the caches are up */ - for (i = KMALLOC_SHIFT_LOW; i < PAGE_SHIFT; i++) + for (i = KMALLOC_SHIFT_LOW; i <= PAGE_SHIFT; i++) kmalloc_caches[i]. name = kasprintf(GFP_KERNEL, "kmalloc-%d", 1 << i); @@ -3057,6 +3088,9 @@ static int slab_unmergeable(struct kmem_cache *s) if (slub_nomerge || (s->flags & SLUB_NEVER_MERGE)) return 1; + if ((s->flags & __PAGE_ALLOC_FALLBACK)) + return 1; + if (s->ctor) return 1; @@ -3218,9 +3252,9 @@ void *__kmalloc_track_caller(size_t size, gfp_t gfpflags, void *caller) { struct kmem_cache *s; - if (unlikely(size > PAGE_SIZE / 2)) - return (void *)__get_free_pages(gfpflags | __GFP_COMP, - get_order(size)); + if (unlikely(size > PAGE_SIZE)) + return kmalloc_large(size, gfpflags); + s = get_slab(size, gfpflags); if (unlikely(ZERO_OR_NULL_PTR(s))) @@ -3234,9 +3268,9 @@ void *__kmalloc_node_track_caller(size_t size, gfp_t gfpflags, { struct kmem_cache *s; - if (unlikely(size > PAGE_SIZE / 2)) - return (void *)__get_free_pages(gfpflags | __GFP_COMP, - get_order(size)); + if (unlikely(size > PAGE_SIZE)) + return kmalloc_large(size, gfpflags); + s = get_slab(size, gfpflags); if (unlikely(ZERO_OR_NULL_PTR(s))) diff --git a/mm/swapfile.c b/mm/swapfile.c index 02ccab5ad9d..2da149cfc9a 100644 --- a/mm/swapfile.c +++ b/mm/swapfile.c @@ -1394,7 +1394,7 @@ static int swap_show(struct seq_file *swap, void *v) } file = ptr->swap_file; - len = seq_path(swap, file->f_path.mnt, file->f_path.dentry, " \t\n\\"); + len = seq_path(swap, &file->f_path, " \t\n\\"); seq_printf(swap, "%*s%s\t%u\t%u\t%d\n", len < 40 ? 40 - len : 1, " ", S_ISBLK(file->f_path.dentry->d_inode->i_mode) ? diff --git a/net/8021q/vlan_dev.c b/net/8021q/vlan_dev.c index 77f04e49a1a..fc60c6d096b 100644 --- a/net/8021q/vlan_dev.c +++ b/net/8021q/vlan_dev.c @@ -366,7 +366,8 @@ static int vlan_dev_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) { struct net_device_stats *stats = &dev->stats; struct vlan_ethhdr *veth = (struct vlan_ethhdr *)(skb->data); - + DECLARE_MAC_BUF(mac); + DECLARE_MAC_BUF(mac2); /* Handle non-VLAN frames if they are sent to us, for example by DHCP. * * NOTE: THIS ASSUMES DIX ETHERNET, SPECIFICALLY NOT SUPPORTING @@ -404,11 +405,8 @@ static int vlan_dev_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) pr_debug("%s: about to send skb: %p to dev: %s\n", __FUNCTION__, skb, skb->dev->name); - pr_debug(" " MAC_FMT " " MAC_FMT " %4hx %4hx %4hx\n", - veth->h_dest[0], veth->h_dest[1], veth->h_dest[2], - veth->h_dest[3], veth->h_dest[4], veth->h_dest[5], - veth->h_source[0], veth->h_source[1], veth->h_source[2], - veth->h_source[3], veth->h_source[4], veth->h_source[5], + pr_debug(" %s %s %4hx %4hx %4hx\n", + print_mac(mac, veth->h_dest), print_mac(mac2, veth->h_source), veth->h_vlan_proto, veth->h_vlan_TCI, veth->h_vlan_encapsulated_proto); diff --git a/net/9p/trans_virtio.c b/net/9p/trans_virtio.c index 0117b9fb848..9e3d81cb9f0 100644 --- a/net/9p/trans_virtio.c +++ b/net/9p/trans_virtio.c @@ -183,8 +183,7 @@ pack_sg_list(struct scatterlist *sg, int start, int limit, char *data, sg_set_buf(&sg[index++], data, s); count -= s; data += s; - if (index > limit) - BUG(); + BUG_ON(index > limit); } return index-start; diff --git a/net/ax25/af_ax25.c b/net/ax25/af_ax25.c index 8fc64e3150a..48bfcc741f2 100644 --- a/net/ax25/af_ax25.c +++ b/net/ax25/af_ax25.c @@ -510,11 +510,7 @@ ax25_cb *ax25_create_cb(void) skb_queue_head_init(&ax25->ack_queue); skb_queue_head_init(&ax25->reseq_queue); - init_timer(&ax25->timer); - init_timer(&ax25->t1timer); - init_timer(&ax25->t2timer); - init_timer(&ax25->t3timer); - init_timer(&ax25->idletimer); + ax25_setup_timers(ax25); ax25_fillin_cb(ax25, NULL); @@ -1928,12 +1924,10 @@ static int ax25_info_show(struct seq_file *seq, void *v) ax25->paclen); if (ax25->sk != NULL) { - bh_lock_sock(ax25->sk); - seq_printf(seq," %d %d %ld\n", + seq_printf(seq, " %d %d %lu\n", atomic_read(&ax25->sk->sk_wmem_alloc), atomic_read(&ax25->sk->sk_rmem_alloc), - ax25->sk->sk_socket != NULL ? SOCK_INODE(ax25->sk->sk_socket)->i_ino : 0L); - bh_unlock_sock(ax25->sk); + sock_i_ino(ax25->sk)); } else { seq_puts(seq, " * * *\n"); } diff --git a/net/ax25/ax25_dev.c b/net/ax25/ax25_dev.c index 528c874d982..a7a0e0c9698 100644 --- a/net/ax25/ax25_dev.c +++ b/net/ax25/ax25_dev.c @@ -82,7 +82,7 @@ void ax25_dev_device_up(struct net_device *dev) ax25_dev->values[AX25_VALUES_DS_TIMEOUT]= AX25_DEF_DS_TIMEOUT; #if defined(CONFIG_AX25_DAMA_SLAVE) || defined(CONFIG_AX25_DAMA_MASTER) - init_timer(&ax25_dev->dama.slave_timer); + ax25_ds_setup_timer(ax25_dev); #endif spin_lock_bh(&ax25_dev_lock); diff --git a/net/ax25/ax25_ds_timer.c b/net/ax25/ax25_ds_timer.c index c4e3b025d21..2ce79df0068 100644 --- a/net/ax25/ax25_ds_timer.c +++ b/net/ax25/ax25_ds_timer.c @@ -40,13 +40,10 @@ static void ax25_ds_timeout(unsigned long); * 1/10th of a second. */ -static void ax25_ds_add_timer(ax25_dev *ax25_dev) +void ax25_ds_setup_timer(ax25_dev *ax25_dev) { - struct timer_list *t = &ax25_dev->dama.slave_timer; - t->data = (unsigned long) ax25_dev; - t->function = &ax25_ds_timeout; - t->expires = jiffies + HZ; - add_timer(t); + setup_timer(&ax25_dev->dama.slave_timer, ax25_ds_timeout, + (unsigned long)ax25_dev); } void ax25_ds_del_timer(ax25_dev *ax25_dev) @@ -60,10 +57,9 @@ void ax25_ds_set_timer(ax25_dev *ax25_dev) if (ax25_dev == NULL) /* paranoia */ return; - del_timer(&ax25_dev->dama.slave_timer); ax25_dev->dama.slave_timeout = msecs_to_jiffies(ax25_dev->values[AX25_VALUES_DS_TIMEOUT]) / 10; - ax25_ds_add_timer(ax25_dev); + mod_timer(&ax25_dev->dama.slave_timer, jiffies + HZ); } /* diff --git a/net/ax25/ax25_out.c b/net/ax25/ax25_out.c index 92b517af726..bf706f83a5c 100644 --- a/net/ax25/ax25_out.c +++ b/net/ax25/ax25_out.c @@ -117,6 +117,12 @@ void ax25_output(ax25_cb *ax25, int paclen, struct sk_buff *skb) unsigned char *p; int frontlen, len, fragno, ka9qfrag, first = 1; + if (paclen < 16) { + WARN_ON_ONCE(1); + kfree_skb(skb); + return; + } + if ((skb->len - 1) > paclen) { if (*skb->data == AX25_P_TEXT) { skb_pull(skb, 1); /* skip PID */ @@ -251,8 +257,6 @@ void ax25_kick(ax25_cb *ax25) if (start == end) return; - ax25->vs = start; - /* * Transmit data until either we're out of data to send or * the window is full. Send a poll on the final I frame if @@ -261,8 +265,13 @@ void ax25_kick(ax25_cb *ax25) /* * Dequeue the frame and copy it. + * Check for race with ax25_clear_queues(). */ skb = skb_dequeue(&ax25->write_queue); + if (!skb) + return; + + ax25->vs = start; do { if ((skbn = skb_clone(skb, GFP_ATOMIC)) == NULL) { diff --git a/net/ax25/ax25_route.c b/net/ax25/ax25_route.c index 38c7f3087ec..8672cd84fdf 100644 --- a/net/ax25/ax25_route.c +++ b/net/ax25/ax25_route.c @@ -45,7 +45,7 @@ void ax25_rt_device_down(struct net_device *dev) { ax25_route *s, *t, *ax25_rt; - write_lock(&ax25_route_lock); + write_lock_bh(&ax25_route_lock); ax25_rt = ax25_route_list; while (ax25_rt != NULL) { s = ax25_rt; @@ -68,7 +68,7 @@ void ax25_rt_device_down(struct net_device *dev) } } } - write_unlock(&ax25_route_lock); + write_unlock_bh(&ax25_route_lock); } static int __must_check ax25_rt_add(struct ax25_routes_struct *route) @@ -82,7 +82,7 @@ static int __must_check ax25_rt_add(struct ax25_routes_struct *route) if (route->digi_count > AX25_MAX_DIGIS) return -EINVAL; - write_lock(&ax25_route_lock); + write_lock_bh(&ax25_route_lock); ax25_rt = ax25_route_list; while (ax25_rt != NULL) { @@ -92,7 +92,7 @@ static int __must_check ax25_rt_add(struct ax25_routes_struct *route) ax25_rt->digipeat = NULL; if (route->digi_count != 0) { if ((ax25_rt->digipeat = kmalloc(sizeof(ax25_digi), GFP_ATOMIC)) == NULL) { - write_unlock(&ax25_route_lock); + write_unlock_bh(&ax25_route_lock); return -ENOMEM; } ax25_rt->digipeat->lastrepeat = -1; @@ -102,14 +102,14 @@ static int __must_check ax25_rt_add(struct ax25_routes_struct *route) ax25_rt->digipeat->calls[i] = route->digi_addr[i]; } } - write_unlock(&ax25_route_lock); + write_unlock_bh(&ax25_route_lock); return 0; } ax25_rt = ax25_rt->next; } if ((ax25_rt = kmalloc(sizeof(ax25_route), GFP_ATOMIC)) == NULL) { - write_unlock(&ax25_route_lock); + write_unlock_bh(&ax25_route_lock); return -ENOMEM; } @@ -120,7 +120,7 @@ static int __must_check ax25_rt_add(struct ax25_routes_struct *route) ax25_rt->ip_mode = ' '; if (route->digi_count != 0) { if ((ax25_rt->digipeat = kmalloc(sizeof(ax25_digi), GFP_ATOMIC)) == NULL) { - write_unlock(&ax25_route_lock); + write_unlock_bh(&ax25_route_lock); kfree(ax25_rt); return -ENOMEM; } @@ -133,7 +133,7 @@ static int __must_check ax25_rt_add(struct ax25_routes_struct *route) } ax25_rt->next = ax25_route_list; ax25_route_list = ax25_rt; - write_unlock(&ax25_route_lock); + write_unlock_bh(&ax25_route_lock); return 0; } @@ -152,7 +152,7 @@ static int ax25_rt_del(struct ax25_routes_struct *route) if ((ax25_dev = ax25_addr_ax25dev(&route->port_addr)) == NULL) return -EINVAL; - write_lock(&ax25_route_lock); + write_lock_bh(&ax25_route_lock); ax25_rt = ax25_route_list; while (ax25_rt != NULL) { @@ -174,7 +174,7 @@ static int ax25_rt_del(struct ax25_routes_struct *route) } } } - write_unlock(&ax25_route_lock); + write_unlock_bh(&ax25_route_lock); return 0; } @@ -188,7 +188,7 @@ static int ax25_rt_opt(struct ax25_route_opt_struct *rt_option) if ((ax25_dev = ax25_addr_ax25dev(&rt_option->port_addr)) == NULL) return -EINVAL; - write_lock(&ax25_route_lock); + write_lock_bh(&ax25_route_lock); ax25_rt = ax25_route_list; while (ax25_rt != NULL) { @@ -216,7 +216,7 @@ static int ax25_rt_opt(struct ax25_route_opt_struct *rt_option) } out: - write_unlock(&ax25_route_lock); + write_unlock_bh(&ax25_route_lock); return err; } @@ -492,7 +492,7 @@ void __exit ax25_rt_free(void) { ax25_route *s, *ax25_rt = ax25_route_list; - write_lock(&ax25_route_lock); + write_lock_bh(&ax25_route_lock); while (ax25_rt != NULL) { s = ax25_rt; ax25_rt = ax25_rt->next; @@ -500,5 +500,5 @@ void __exit ax25_rt_free(void) kfree(s->digipeat); kfree(s); } - write_unlock(&ax25_route_lock); + write_unlock_bh(&ax25_route_lock); } diff --git a/net/ax25/ax25_timer.c b/net/ax25/ax25_timer.c index 72594867fab..db29ea71e80 100644 --- a/net/ax25/ax25_timer.c +++ b/net/ax25/ax25_timer.c @@ -40,63 +40,45 @@ static void ax25_t2timer_expiry(unsigned long); static void ax25_t3timer_expiry(unsigned long); static void ax25_idletimer_expiry(unsigned long); -void ax25_start_heartbeat(ax25_cb *ax25) +void ax25_setup_timers(ax25_cb *ax25) { - del_timer(&ax25->timer); - - ax25->timer.data = (unsigned long)ax25; - ax25->timer.function = &ax25_heartbeat_expiry; - ax25->timer.expires = jiffies + 5 * HZ; + setup_timer(&ax25->timer, ax25_heartbeat_expiry, (unsigned long)ax25); + setup_timer(&ax25->t1timer, ax25_t1timer_expiry, (unsigned long)ax25); + setup_timer(&ax25->t2timer, ax25_t2timer_expiry, (unsigned long)ax25); + setup_timer(&ax25->t3timer, ax25_t3timer_expiry, (unsigned long)ax25); + setup_timer(&ax25->idletimer, ax25_idletimer_expiry, + (unsigned long)ax25); +} - add_timer(&ax25->timer); +void ax25_start_heartbeat(ax25_cb *ax25) +{ + mod_timer(&ax25->timer, jiffies + 5 * HZ); } void ax25_start_t1timer(ax25_cb *ax25) { - del_timer(&ax25->t1timer); - - ax25->t1timer.data = (unsigned long)ax25; - ax25->t1timer.function = &ax25_t1timer_expiry; - ax25->t1timer.expires = jiffies + ax25->t1; - - add_timer(&ax25->t1timer); + mod_timer(&ax25->t1timer, jiffies + ax25->t1); } void ax25_start_t2timer(ax25_cb *ax25) { - del_timer(&ax25->t2timer); - - ax25->t2timer.data = (unsigned long)ax25; - ax25->t2timer.function = &ax25_t2timer_expiry; - ax25->t2timer.expires = jiffies + ax25->t2; - - add_timer(&ax25->t2timer); + mod_timer(&ax25->t2timer, jiffies + ax25->t2); } void ax25_start_t3timer(ax25_cb *ax25) { - del_timer(&ax25->t3timer); - - if (ax25->t3 > 0) { - ax25->t3timer.data = (unsigned long)ax25; - ax25->t3timer.function = &ax25_t3timer_expiry; - ax25->t3timer.expires = jiffies + ax25->t3; - - add_timer(&ax25->t3timer); - } + if (ax25->t3 > 0) + mod_timer(&ax25->t3timer, jiffies + ax25->t3); + else + del_timer(&ax25->t3timer); } void ax25_start_idletimer(ax25_cb *ax25) { - del_timer(&ax25->idletimer); - - if (ax25->idle > 0) { - ax25->idletimer.data = (unsigned long)ax25; - ax25->idletimer.function = &ax25_idletimer_expiry; - ax25->idletimer.expires = jiffies + ax25->idle; - - add_timer(&ax25->idletimer); - } + if (ax25->idle > 0) + mod_timer(&ax25->idletimer, jiffies + ax25->idle); + else + del_timer(&ax25->idletimer); } void ax25_stop_heartbeat(ax25_cb *ax25) diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c index 5fc7be206f6..f8880261da0 100644 --- a/net/bluetooth/hci_conn.c +++ b/net/bluetooth/hci_conn.c @@ -260,7 +260,6 @@ int hci_conn_del(struct hci_conn *conn) tasklet_enable(&hdev->tx_task); skb_queue_purge(&conn->data_q); hci_conn_del_sysfs(conn); - hci_dev_put(hdev); return 0; } diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 372b0d3b75a..930b58e7149 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -24,6 +24,7 @@ /* Bluetooth HCI core. */ +#include <linux/jiffies.h> #include <linux/module.h> #include <linux/kmod.h> @@ -1321,7 +1322,7 @@ static inline void hci_sched_acl(struct hci_dev *hdev) if (!test_bit(HCI_RAW, &hdev->flags)) { /* ACL tx timeout must be longer than maximum * link supervision timeout (40.9 seconds) */ - if (!hdev->acl_cnt && (jiffies - hdev->acl_last_tx) > (HZ * 45)) + if (!hdev->acl_cnt && time_after(jiffies, hdev->acl_last_tx + HZ * 45)) hci_acl_tx_to(hdev); } @@ -1543,7 +1544,7 @@ static void hci_cmd_task(unsigned long arg) BT_DBG("%s cmd %d", hdev->name, atomic_read(&hdev->cmd_cnt)); - if (!atomic_read(&hdev->cmd_cnt) && (jiffies - hdev->cmd_last_tx) > HZ) { + if (!atomic_read(&hdev->cmd_cnt) && time_after(jiffies, hdev->cmd_last_tx + HZ)) { BT_ERR("%s command tx timeout", hdev->name); atomic_set(&hdev->cmd_cnt, 1); } diff --git a/net/bluetooth/hci_sysfs.c b/net/bluetooth/hci_sysfs.c index e13cf5ef144..84360c117d4 100644 --- a/net/bluetooth/hci_sysfs.c +++ b/net/bluetooth/hci_sysfs.c @@ -320,28 +320,34 @@ void hci_conn_add_sysfs(struct hci_conn *conn) queue_work(btaddconn, &conn->work); } +/* + * The rfcomm tty device will possibly retain even when conn + * is down, and sysfs doesn't support move zombie device, + * so we should move the device before conn device is destroyed. + */ static int __match_tty(struct device *dev, void *data) { - /* The rfcomm tty device will possibly retain even when conn - * is down, and sysfs doesn't support move zombie device, - * so we should move the device before conn device is destroyed. - * Due to the only child device of hci_conn dev is rfcomm - * tty_dev, here just return 1 - */ - return 1; + return !strncmp(dev->bus_id, "rfcomm", 6); } static void del_conn(struct work_struct *work) { - struct device *dev; struct hci_conn *conn = container_of(work, struct hci_conn, work); + struct hci_dev *hdev = conn->hdev; + + while (1) { + struct device *dev; - while (dev = device_find_child(&conn->dev, NULL, __match_tty)) { + dev = device_find_child(&conn->dev, NULL, __match_tty); + if (!dev) + break; device_move(dev, NULL); put_device(dev); } + device_del(&conn->dev); put_device(&conn->dev); + hci_dev_put(hdev); } void hci_conn_del_sysfs(struct hci_conn *conn) diff --git a/net/bluetooth/rfcomm/core.c b/net/bluetooth/rfcomm/core.c index d3e4e1877e6..0c2c93735e9 100644 --- a/net/bluetooth/rfcomm/core.c +++ b/net/bluetooth/rfcomm/core.c @@ -465,7 +465,7 @@ int rfcomm_dlc_send(struct rfcomm_dlc *d, struct sk_buff *skb) return len; } -void fastcall __rfcomm_dlc_throttle(struct rfcomm_dlc *d) +void __rfcomm_dlc_throttle(struct rfcomm_dlc *d) { BT_DBG("dlc %p state %ld", d, d->state); @@ -476,7 +476,7 @@ void fastcall __rfcomm_dlc_throttle(struct rfcomm_dlc *d) rfcomm_schedule(RFCOMM_SCHED_TX); } -void fastcall __rfcomm_dlc_unthrottle(struct rfcomm_dlc *d) +void __rfcomm_dlc_unthrottle(struct rfcomm_dlc *d) { BT_DBG("dlc %p state %ld", d, d->state); diff --git a/net/core/dev.c b/net/core/dev.c index 9549417250b..908f07c3bd7 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -1071,8 +1071,6 @@ int dev_close(struct net_device *dev) */ call_netdevice_notifiers(NETDEV_GOING_DOWN, dev); - dev_deactivate(dev); - clear_bit(__LINK_STATE_START, &dev->state); /* Synchronize to scheduled poll. We cannot touch poll list, @@ -1083,6 +1081,8 @@ int dev_close(struct net_device *dev) */ smp_mb__after_clear_bit(); /* Commit netif_running(). */ + dev_deactivate(dev); + /* * Call the device specific close. This cannot fail. * Only if device is UP @@ -2143,7 +2143,7 @@ static int process_backlog(struct napi_struct *napi, int quota) * * The entry's receive function will be scheduled to run */ -void fastcall __napi_schedule(struct napi_struct *n) +void __napi_schedule(struct napi_struct *n) { unsigned long flags; @@ -3038,8 +3038,7 @@ int dev_unicast_sync(struct net_device *to, struct net_device *from) EXPORT_SYMBOL(dev_unicast_sync); /** - * dev_unicast_unsync - Remove synchronized addresses from the destination - * device + * dev_unicast_unsync - Remove synchronized addresses from the destination device * @to: destination device * @from: source device * diff --git a/net/core/skbuff.c b/net/core/skbuff.c index 4e354221ec2..0d0fd28a904 100644 --- a/net/core/skbuff.c +++ b/net/core/skbuff.c @@ -1907,11 +1907,11 @@ void skb_prepare_seq_read(struct sk_buff *skb, unsigned int from, * of bytes already consumed and the next call to * skb_seq_read() will return the remaining part of the block. * - * Note: The size of each block of data returned can be arbitary, + * Note 1: The size of each block of data returned can be arbitary, * this limitation is the cost for zerocopy seqeuental * reads of potentially non linear data. * - * Note: Fragment lists within fragments are not implemented + * Note 2: Fragment lists within fragments are not implemented * at the moment, state->root_skb could be replaced with * a stack for this purpose. */ @@ -2106,11 +2106,10 @@ int skb_append_datato_frags(struct sock *sk, struct sk_buff *skb, /** * skb_pull_rcsum - pull skb and update receive checksum * @skb: buffer to update - * @start: start of data before pull * @len: length of data pulled * * This function performs an skb_pull on the packet and updates - * update the CHECKSUM_COMPLETE checksum. It should be used on + * the CHECKSUM_COMPLETE checksum. It should be used on * receive path processing instead of skb_pull unless you know * that the checksum difference is zero (e.g., a valid IP header) * or you are setting ip_summed to CHECKSUM_NONE. diff --git a/net/core/sock.c b/net/core/sock.c index 433715fb141..09cb3a74de7 100644 --- a/net/core/sock.c +++ b/net/core/sock.c @@ -1731,7 +1731,7 @@ void sock_init_data(struct socket *sock, struct sock *sk) atomic_set(&sk->sk_drops, 0); } -void fastcall lock_sock_nested(struct sock *sk, int subclass) +void lock_sock_nested(struct sock *sk, int subclass) { might_sleep(); spin_lock_bh(&sk->sk_lock.slock); @@ -1748,7 +1748,7 @@ void fastcall lock_sock_nested(struct sock *sk, int subclass) EXPORT_SYMBOL(lock_sock_nested); -void fastcall release_sock(struct sock *sk) +void release_sock(struct sock *sk) { /* * The sk_lock has mutex_unlock() semantics: diff --git a/net/ipv4/ah4.c b/net/ipv4/ah4.c index 9d4555ec0b5..8219b7e0968 100644 --- a/net/ipv4/ah4.c +++ b/net/ipv4/ah4.c @@ -96,7 +96,7 @@ static int ah_output(struct xfrm_state *x, struct sk_buff *skb) ah->reserved = 0; ah->spi = x->id.spi; - ah->seq_no = htonl(XFRM_SKB_CB(skb)->seq); + ah->seq_no = htonl(XFRM_SKB_CB(skb)->seq.output); spin_lock_bh(&x->lock); err = ah_mac_digest(ahp, skb, ah->auth_data); diff --git a/net/ipv4/esp4.c b/net/ipv4/esp4.c index 258d17631b4..091e6709f83 100644 --- a/net/ipv4/esp4.c +++ b/net/ipv4/esp4.c @@ -199,7 +199,7 @@ static int esp_output(struct xfrm_state *x, struct sk_buff *skb) } esph->spi = x->id.spi; - esph->seq_no = htonl(XFRM_SKB_CB(skb)->seq); + esph->seq_no = htonl(XFRM_SKB_CB(skb)->seq.output); sg_init_table(sg, nfrags); skb_to_sgvec(skb, sg, @@ -210,7 +210,8 @@ static int esp_output(struct xfrm_state *x, struct sk_buff *skb) aead_givcrypt_set_callback(req, 0, esp_output_done, skb); aead_givcrypt_set_crypt(req, sg, sg, clen, iv); aead_givcrypt_set_assoc(req, asg, sizeof(*esph)); - aead_givcrypt_set_giv(req, esph->enc_data, XFRM_SKB_CB(skb)->seq); + aead_givcrypt_set_giv(req, esph->enc_data, + XFRM_SKB_CB(skb)->seq.output); ESP_SKB_CB(skb)->tmp = tmp; err = crypto_aead_givencrypt(req); diff --git a/net/ipv4/fib_trie.c b/net/ipv4/fib_trie.c index f5fba3f71c0..1ff446d0fa8 100644 --- a/net/ipv4/fib_trie.c +++ b/net/ipv4/fib_trie.c @@ -1762,11 +1762,9 @@ static struct leaf *trie_leafindex(struct trie *t, int index) { struct leaf *l = trie_firstleaf(t); - while (index-- > 0) { + while (l && index-- > 0) l = trie_nextleaf(l); - if (!l) - break; - } + return l; } @@ -2461,6 +2459,84 @@ static const struct file_operations fib_trie_fops = { .release = seq_release_net, }; +struct fib_route_iter { + struct seq_net_private p; + struct trie *main_trie; + loff_t pos; + t_key key; +}; + +static struct leaf *fib_route_get_idx(struct fib_route_iter *iter, loff_t pos) +{ + struct leaf *l = NULL; + struct trie *t = iter->main_trie; + + /* use cache location of last found key */ + if (iter->pos > 0 && pos >= iter->pos && (l = fib_find_node(t, iter->key))) + pos -= iter->pos; + else { + iter->pos = 0; + l = trie_firstleaf(t); + } + + while (l && pos-- > 0) { + iter->pos++; + l = trie_nextleaf(l); + } + + if (l) + iter->key = pos; /* remember it */ + else + iter->pos = 0; /* forget it */ + + return l; +} + +static void *fib_route_seq_start(struct seq_file *seq, loff_t *pos) + __acquires(RCU) +{ + struct fib_route_iter *iter = seq->private; + struct fib_table *tb; + + rcu_read_lock(); + tb = fib_get_table(iter->p.net, RT_TABLE_MAIN); + if (!tb) + return NULL; + + iter->main_trie = (struct trie *) tb->tb_data; + if (*pos == 0) + return SEQ_START_TOKEN; + else + return fib_route_get_idx(iter, *pos - 1); +} + +static void *fib_route_seq_next(struct seq_file *seq, void *v, loff_t *pos) +{ + struct fib_route_iter *iter = seq->private; + struct leaf *l = v; + + ++*pos; + if (v == SEQ_START_TOKEN) { + iter->pos = 0; + l = trie_firstleaf(iter->main_trie); + } else { + iter->pos++; + l = trie_nextleaf(l); + } + + if (l) + iter->key = l->key; + else + iter->pos = 0; + return l; +} + +static void fib_route_seq_stop(struct seq_file *seq, void *v) + __releases(RCU) +{ + rcu_read_unlock(); +} + static unsigned fib_flag_trans(int type, __be32 mask, const struct fib_info *fi) { static unsigned type2flags[RTN_MAX + 1] = { @@ -2484,7 +2560,6 @@ static unsigned fib_flag_trans(int type, __be32 mask, const struct fib_info *fi) */ static int fib_route_seq_show(struct seq_file *seq, void *v) { - const struct fib_trie_iter *iter = seq->private; struct leaf *l = v; struct leaf_info *li; struct hlist_node *node; @@ -2496,12 +2571,6 @@ static int fib_route_seq_show(struct seq_file *seq, void *v) return 0; } - if (iter->trie == iter->trie_local) - return 0; - - if (IS_TNODE(l)) - return 0; - hlist_for_each_entry_rcu(li, node, &l->list, hlist) { struct fib_alias *fa; __be32 mask, prefix; @@ -2544,16 +2613,16 @@ static int fib_route_seq_show(struct seq_file *seq, void *v) } static const struct seq_operations fib_route_seq_ops = { - .start = fib_trie_seq_start, - .next = fib_trie_seq_next, - .stop = fib_trie_seq_stop, + .start = fib_route_seq_start, + .next = fib_route_seq_next, + .stop = fib_route_seq_stop, .show = fib_route_seq_show, }; static int fib_route_seq_open(struct inode *inode, struct file *file) { return seq_open_net(inode, file, &fib_route_seq_ops, - sizeof(struct fib_trie_iter)); + sizeof(struct fib_route_iter)); } static const struct file_operations fib_route_fops = { diff --git a/net/ipv4/inet_hashtables.c b/net/ipv4/inet_hashtables.c index 9cac6c034ab..1aba606f6bb 100644 --- a/net/ipv4/inet_hashtables.c +++ b/net/ipv4/inet_hashtables.c @@ -120,8 +120,6 @@ void inet_listen_wlock(struct inet_hashinfo *hashinfo) } } -EXPORT_SYMBOL(inet_listen_wlock); - /* * Don't inline this cruft. Here are some nice properties to exploit here. The * BSD API does not allow a listening sock to specify the remote port nor the @@ -494,7 +492,6 @@ out: return ret; } } -EXPORT_SYMBOL_GPL(__inet_hash_connect); /* * Bind a port for a connect operation and hash it. diff --git a/net/ipv4/ip_sockglue.c b/net/ipv4/ip_sockglue.c index 754b0a5bbfe..de0572c8885 100644 --- a/net/ipv4/ip_sockglue.c +++ b/net/ipv4/ip_sockglue.c @@ -514,11 +514,6 @@ static int do_ip_setsockopt(struct sock *sk, int level, val &= ~3; val |= inet->tos & 3; } - if (IPTOS_PREC(val) >= IPTOS_PREC_CRITIC_ECP && - !capable(CAP_NET_ADMIN)) { - err = -EPERM; - break; - } if (inet->tos != val) { inet->tos = val; sk->sk_priority = rt_tos2priority(val); diff --git a/net/ipv4/ipconfig.c b/net/ipv4/ipconfig.c index a52b5853aaa..10013ccee8d 100644 --- a/net/ipv4/ipconfig.c +++ b/net/ipv4/ipconfig.c @@ -1390,7 +1390,7 @@ static int __init ip_auto_config(void) * Clue in the operator. */ printk("IP-Config: Complete:"); - printk("\n device=%s", ic_dev->name); + printk("\n device=%s", ic_dev->name); printk(", addr=%u.%u.%u.%u", NIPQUAD(ic_myaddr)); printk(", mask=%u.%u.%u.%u", NIPQUAD(ic_netmask)); printk(", gw=%u.%u.%u.%u", NIPQUAD(ic_gateway)); diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c index 63414ea427c..00156bf421c 100644 --- a/net/ipv4/tcp_ipv4.c +++ b/net/ipv4/tcp_ipv4.c @@ -719,7 +719,7 @@ static void tcp_v4_reqsk_send_ack(struct sk_buff *skb, } /* - * Send a SYN-ACK after having received an ACK. + * Send a SYN-ACK after having received a SYN. * This still operates on a request_sock only, not on a big * socket. */ diff --git a/net/ipv6/af_inet6.c b/net/ipv6/af_inet6.c index bddac0e8780..f0aa9773874 100644 --- a/net/ipv6/af_inet6.c +++ b/net/ipv6/af_inet6.c @@ -752,14 +752,6 @@ static int __init inet6_init(void) BUILD_BUG_ON(sizeof(struct inet6_skb_parm) > sizeof(dummy_skb->cb)); -#ifdef MODULE -#if 0 /* FIXME --RR */ - if (!mod_member_present(&__this_module, can_unload)) - return -EINVAL; - - __this_module.can_unload = &ipv6_unload; -#endif -#endif err = proto_register(&tcpv6_prot, 1); if (err) goto out; diff --git a/net/ipv6/ah6.c b/net/ipv6/ah6.c index 379c8e04c36..2ff0c8233e4 100644 --- a/net/ipv6/ah6.c +++ b/net/ipv6/ah6.c @@ -283,7 +283,7 @@ static int ah6_output(struct xfrm_state *x, struct sk_buff *skb) ah->reserved = 0; ah->spi = x->id.spi; - ah->seq_no = htonl(XFRM_SKB_CB(skb)->seq); + ah->seq_no = htonl(XFRM_SKB_CB(skb)->seq.output); spin_lock_bh(&x->lock); err = ah_mac_digest(ahp, skb, ah->auth_data); diff --git a/net/ipv6/esp6.c b/net/ipv6/esp6.c index 8e0f1428c71..0ec1402320e 100644 --- a/net/ipv6/esp6.c +++ b/net/ipv6/esp6.c @@ -188,7 +188,7 @@ static int esp6_output(struct xfrm_state *x, struct sk_buff *skb) *skb_mac_header(skb) = IPPROTO_ESP; esph->spi = x->id.spi; - esph->seq_no = htonl(XFRM_SKB_CB(skb)->seq); + esph->seq_no = htonl(XFRM_SKB_CB(skb)->seq.output); sg_init_table(sg, nfrags); skb_to_sgvec(skb, sg, @@ -199,7 +199,8 @@ static int esp6_output(struct xfrm_state *x, struct sk_buff *skb) aead_givcrypt_set_callback(req, 0, esp_output_done, skb); aead_givcrypt_set_crypt(req, sg, sg, clen, iv); aead_givcrypt_set_assoc(req, asg, sizeof(*esph)); - aead_givcrypt_set_giv(req, esph->enc_data, XFRM_SKB_CB(skb)->seq); + aead_givcrypt_set_giv(req, esph->enc_data, + XFRM_SKB_CB(skb)->seq.output); ESP_SKB_CB(skb)->tmp = tmp; err = crypto_aead_givencrypt(req); diff --git a/net/ipv6/ip6_fib.c b/net/ipv6/ip6_fib.c index f93407cf651..bab72b6f144 100644 --- a/net/ipv6/ip6_fib.c +++ b/net/ipv6/ip6_fib.c @@ -1151,7 +1151,7 @@ static void fib6_del_route(struct fib6_node *fn, struct rt6_info **rtp, fn = fn->parent; } /* No more references are possible at this point. */ - if (atomic_read(&rt->rt6i_ref) != 1) BUG(); + BUG_ON(atomic_read(&rt->rt6i_ref) != 1); } inet6_rt_notify(RTM_DELROUTE, rt, info); diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c index 9ac6ca2521c..8b67ca07467 100644 --- a/net/ipv6/ip6_output.c +++ b/net/ipv6/ip6_output.c @@ -621,7 +621,7 @@ static int ip6_fragment(struct sk_buff *skb, int (*output)(struct sk_buff *)) * or if the skb it not generated by a local socket. (This last * check should be redundant, but it's free.) */ - if (!np || np->pmtudisc >= IPV6_PMTUDISC_DO) { + if (!skb->local_df) { skb->dev = skb->dst->dev; icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu, skb->dev); IP6_INC_STATS(ip6_dst_idev(skb->dst), IPSTATS_MIB_FRAGFAILS); @@ -1420,6 +1420,10 @@ int ip6_push_pending_frames(struct sock *sk) tmp_skb->sk = NULL; } + /* Allow local fragmentation. */ + if (np->pmtudisc < IPV6_PMTUDISC_DO) + skb->local_df = 1; + ipv6_addr_copy(final_dst, &fl->fl6_dst); __skb_pull(skb, skb_network_header_len(skb)); if (opt && opt->opt_flen) diff --git a/net/ipv6/ip6_tunnel.c b/net/ipv6/ip6_tunnel.c index 9031e521c1d..cd940647bd1 100644 --- a/net/ipv6/ip6_tunnel.c +++ b/net/ipv6/ip6_tunnel.c @@ -550,6 +550,7 @@ ip4ip6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, ip_rt_put(rt); goto out; } + skb2->dst = (struct dst_entry *)rt; } else { ip_rt_put(rt); if (ip_route_input(skb2, eiph->daddr, eiph->saddr, eiph->tos, diff --git a/net/ipv6/xfrm6_output.c b/net/ipv6/xfrm6_output.c index b34c58c6565..79ccfb08073 100644 --- a/net/ipv6/xfrm6_output.c +++ b/net/ipv6/xfrm6_output.c @@ -36,7 +36,7 @@ static int xfrm6_tunnel_check_size(struct sk_buff *skb) if (mtu < IPV6_MIN_MTU) mtu = IPV6_MIN_MTU; - if (skb->len > mtu) { + if (!skb->local_df && skb->len > mtu) { skb->dev = dst->dev; icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu, skb->dev); ret = -EMSGSIZE; diff --git a/net/key/af_key.c b/net/key/af_key.c index b3ac85e808a..1c853927810 100644 --- a/net/key/af_key.c +++ b/net/key/af_key.c @@ -2291,6 +2291,7 @@ static int pfkey_spdadd(struct sock *sk, struct sk_buff *skb, struct sadb_msg *h return 0; out: + xp->dead = 1; xfrm_policy_destroy(xp); return err; } diff --git a/net/mac80211/ieee80211.c b/net/mac80211/ieee80211.c index 67b7c75c430..28bcdf9fc3d 100644 --- a/net/mac80211/ieee80211.c +++ b/net/mac80211/ieee80211.c @@ -165,6 +165,7 @@ static int ieee80211_open(struct net_device *dev) struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); struct ieee80211_if_init_conf conf; int res; + bool need_hw_reconfig = 0; sdata = IEEE80211_DEV_TO_SUB_IF(dev); @@ -218,7 +219,7 @@ static int ieee80211_open(struct net_device *dev) res = local->ops->start(local_to_hw(local)); if (res) return res; - ieee80211_hw_config(local); + need_hw_reconfig = 1; ieee80211_led_radio(local, local->hw.conf.radio_enabled); } @@ -282,6 +283,8 @@ static int ieee80211_open(struct net_device *dev) atomic_inc(&local->iff_promiscs); local->open_count++; + if (need_hw_reconfig) + ieee80211_hw_config(local); netif_start_queue(dev); diff --git a/net/netfilter/nf_conntrack_proto_tcp.c b/net/netfilter/nf_conntrack_proto_tcp.c index 202d7fa0948..62567959b66 100644 --- a/net/netfilter/nf_conntrack_proto_tcp.c +++ b/net/netfilter/nf_conntrack_proto_tcp.c @@ -945,7 +945,7 @@ static int tcp_packet(struct nf_conn *ct, ct->proto.tcp.state = new_state; if (old_state != new_state - && new_state == TCP_CONNTRACK_CLOSE) + && new_state == TCP_CONNTRACK_FIN_WAIT) ct->proto.tcp.seen[dir].flags |= IP_CT_TCP_FLAG_CLOSE_INIT; timeout = ct->proto.tcp.retrans >= nf_ct_tcp_max_retrans && tcp_timeouts[new_state] > nf_ct_tcp_timeout_max_retrans diff --git a/net/netfilter/xt_SECMARK.c b/net/netfilter/xt_SECMARK.c index 7708e2084ce..c0284856ccd 100644 --- a/net/netfilter/xt_SECMARK.c +++ b/net/netfilter/xt_SECMARK.c @@ -111,7 +111,7 @@ secmark_tg_check(const char *tablename, const void *entry, return true; } -void secmark_tg_destroy(const struct xt_target *target, void *targinfo) +static void secmark_tg_destroy(const struct xt_target *target, void *targinfo) { switch (mode) { case SECMARK_MODE_SEL: diff --git a/net/netlabel/netlabel_cipso_v4.c b/net/netlabel/netlabel_cipso_v4.c index c7ad64d664a..fdc14a0d21a 100644 --- a/net/netlabel/netlabel_cipso_v4.c +++ b/net/netlabel/netlabel_cipso_v4.c @@ -718,36 +718,35 @@ static int netlbl_cipsov4_remove(struct sk_buff *skb, struct genl_info *info) * NetLabel Generic NETLINK Command Definitions */ -static struct genl_ops netlbl_cipsov4_genl_c_add = { +static struct genl_ops netlbl_cipsov4_ops[] = { + { .cmd = NLBL_CIPSOV4_C_ADD, .flags = GENL_ADMIN_PERM, .policy = netlbl_cipsov4_genl_policy, .doit = netlbl_cipsov4_add, .dumpit = NULL, -}; - -static struct genl_ops netlbl_cipsov4_genl_c_remove = { + }, + { .cmd = NLBL_CIPSOV4_C_REMOVE, .flags = GENL_ADMIN_PERM, .policy = netlbl_cipsov4_genl_policy, .doit = netlbl_cipsov4_remove, .dumpit = NULL, -}; - -static struct genl_ops netlbl_cipsov4_genl_c_list = { + }, + { .cmd = NLBL_CIPSOV4_C_LIST, .flags = 0, .policy = netlbl_cipsov4_genl_policy, .doit = netlbl_cipsov4_list, .dumpit = NULL, -}; - -static struct genl_ops netlbl_cipsov4_genl_c_listall = { + }, + { .cmd = NLBL_CIPSOV4_C_LISTALL, .flags = 0, .policy = netlbl_cipsov4_genl_policy, .doit = NULL, .dumpit = netlbl_cipsov4_listall, + }, }; /* @@ -762,30 +761,20 @@ static struct genl_ops netlbl_cipsov4_genl_c_listall = { * mechanism. Returns zero on success, negative values on failure. * */ -int netlbl_cipsov4_genl_init(void) +int __init netlbl_cipsov4_genl_init(void) { - int ret_val; + int ret_val, i; ret_val = genl_register_family(&netlbl_cipsov4_gnl_family); if (ret_val != 0) return ret_val; - ret_val = genl_register_ops(&netlbl_cipsov4_gnl_family, - &netlbl_cipsov4_genl_c_add); - if (ret_val != 0) - return ret_val; - ret_val = genl_register_ops(&netlbl_cipsov4_gnl_family, - &netlbl_cipsov4_genl_c_remove); - if (ret_val != 0) - return ret_val; - ret_val = genl_register_ops(&netlbl_cipsov4_gnl_family, - &netlbl_cipsov4_genl_c_list); - if (ret_val != 0) - return ret_val; - ret_val = genl_register_ops(&netlbl_cipsov4_gnl_family, - &netlbl_cipsov4_genl_c_listall); - if (ret_val != 0) - return ret_val; + for (i = 0; i < ARRAY_SIZE(netlbl_cipsov4_ops); i++) { + ret_val = genl_register_ops(&netlbl_cipsov4_gnl_family, + &netlbl_cipsov4_ops[i]); + if (ret_val != 0) + return ret_val; + } return 0; } diff --git a/net/netlabel/netlabel_domainhash.c b/net/netlabel/netlabel_domainhash.c index 9a8ea0195c4..02c2f7c0b25 100644 --- a/net/netlabel/netlabel_domainhash.c +++ b/net/netlabel/netlabel_domainhash.c @@ -150,11 +150,11 @@ static struct netlbl_dom_map *netlbl_domhsh_search_def(const char *domain) entry = netlbl_domhsh_search(domain); if (entry == NULL) { entry = rcu_dereference(netlbl_domhsh_def); - if (entry != NULL && entry->valid) - return entry; + if (entry != NULL && !entry->valid) + entry = NULL; } - return NULL; + return entry; } /* @@ -171,7 +171,7 @@ static struct netlbl_dom_map *netlbl_domhsh_search_def(const char *domain) * values on error. * */ -int netlbl_domhsh_init(u32 size) +int __init netlbl_domhsh_init(u32 size) { u32 iter; struct netlbl_domhsh_tbl *hsh_tbl; diff --git a/net/netlabel/netlabel_mgmt.c b/net/netlabel/netlabel_mgmt.c index e2258dc3c84..22c19126780 100644 --- a/net/netlabel/netlabel_mgmt.c +++ b/net/netlabel/netlabel_mgmt.c @@ -517,68 +517,63 @@ version_failure: * NetLabel Generic NETLINK Command Definitions */ -static struct genl_ops netlbl_mgmt_genl_c_add = { +static struct genl_ops netlbl_mgmt_genl_ops[] = { + { .cmd = NLBL_MGMT_C_ADD, .flags = GENL_ADMIN_PERM, .policy = netlbl_mgmt_genl_policy, .doit = netlbl_mgmt_add, .dumpit = NULL, -}; - -static struct genl_ops netlbl_mgmt_genl_c_remove = { + }, + { .cmd = NLBL_MGMT_C_REMOVE, .flags = GENL_ADMIN_PERM, .policy = netlbl_mgmt_genl_policy, .doit = netlbl_mgmt_remove, .dumpit = NULL, -}; - -static struct genl_ops netlbl_mgmt_genl_c_listall = { + }, + { .cmd = NLBL_MGMT_C_LISTALL, .flags = 0, .policy = netlbl_mgmt_genl_policy, .doit = NULL, .dumpit = netlbl_mgmt_listall, -}; - -static struct genl_ops netlbl_mgmt_genl_c_adddef = { + }, + { .cmd = NLBL_MGMT_C_ADDDEF, .flags = GENL_ADMIN_PERM, .policy = netlbl_mgmt_genl_policy, .doit = netlbl_mgmt_adddef, .dumpit = NULL, -}; - -static struct genl_ops netlbl_mgmt_genl_c_removedef = { + }, + { .cmd = NLBL_MGMT_C_REMOVEDEF, .flags = GENL_ADMIN_PERM, .policy = netlbl_mgmt_genl_policy, .doit = netlbl_mgmt_removedef, .dumpit = NULL, -}; - -static struct genl_ops netlbl_mgmt_genl_c_listdef = { + }, + { .cmd = NLBL_MGMT_C_LISTDEF, .flags = 0, .policy = netlbl_mgmt_genl_policy, .doit = netlbl_mgmt_listdef, .dumpit = NULL, -}; - -static struct genl_ops netlbl_mgmt_genl_c_protocols = { + }, + { .cmd = NLBL_MGMT_C_PROTOCOLS, .flags = 0, .policy = netlbl_mgmt_genl_policy, .doit = NULL, .dumpit = netlbl_mgmt_protocols, -}; - -static struct genl_ops netlbl_mgmt_genl_c_version = { + }, + { .cmd = NLBL_MGMT_C_VERSION, .flags = 0, .policy = netlbl_mgmt_genl_policy, .doit = netlbl_mgmt_version, .dumpit = NULL, + }, }; /* @@ -593,46 +588,20 @@ static struct genl_ops netlbl_mgmt_genl_c_version = { * mechanism. Returns zero on success, negative values on failure. * */ -int netlbl_mgmt_genl_init(void) +int __init netlbl_mgmt_genl_init(void) { - int ret_val; + int ret_val, i; ret_val = genl_register_family(&netlbl_mgmt_gnl_family); if (ret_val != 0) return ret_val; - ret_val = genl_register_ops(&netlbl_mgmt_gnl_family, - &netlbl_mgmt_genl_c_add); - if (ret_val != 0) - return ret_val; - ret_val = genl_register_ops(&netlbl_mgmt_gnl_family, - &netlbl_mgmt_genl_c_remove); - if (ret_val != 0) - return ret_val; - ret_val = genl_register_ops(&netlbl_mgmt_gnl_family, - &netlbl_mgmt_genl_c_listall); - if (ret_val != 0) - return ret_val; - ret_val = genl_register_ops(&netlbl_mgmt_gnl_family, - &netlbl_mgmt_genl_c_adddef); - if (ret_val != 0) - return ret_val; - ret_val = genl_register_ops(&netlbl_mgmt_gnl_family, - &netlbl_mgmt_genl_c_removedef); - if (ret_val != 0) - return ret_val; - ret_val = genl_register_ops(&netlbl_mgmt_gnl_family, - &netlbl_mgmt_genl_c_listdef); - if (ret_val != 0) - return ret_val; - ret_val = genl_register_ops(&netlbl_mgmt_gnl_family, - &netlbl_mgmt_genl_c_protocols); - if (ret_val != 0) - return ret_val; - ret_val = genl_register_ops(&netlbl_mgmt_gnl_family, - &netlbl_mgmt_genl_c_version); - if (ret_val != 0) - return ret_val; + for (i = 0; i < ARRAY_SIZE(netlbl_mgmt_genl_ops); i++) { + ret_val = genl_register_ops(&netlbl_mgmt_gnl_family, + &netlbl_mgmt_genl_ops[i]); + if (ret_val != 0) + return ret_val; + } return 0; } diff --git a/net/netlabel/netlabel_unlabeled.c b/net/netlabel/netlabel_unlabeled.c index 42e81fd8cc4..4478f2f6079 100644 --- a/net/netlabel/netlabel_unlabeled.c +++ b/net/netlabel/netlabel_unlabeled.c @@ -180,6 +180,7 @@ static void netlbl_unlabel_audit_addr4(struct audit_buffer *audit_buf, } } +#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) /** * netlbl_unlabel_audit_addr6 - Audit an IPv6 address * @audit_buf: audit buffer @@ -213,6 +214,7 @@ static void netlbl_unlabel_audit_addr6(struct audit_buffer *audit_buf, audit_log_format(audit_buf, " src_prefixlen=%d", mask_len); } } +#endif /* IPv6 */ /* * Unlabeled Connection Hash Table Functions @@ -617,8 +619,6 @@ static int netlbl_unlhsh_add(struct net *net, int ifindex; struct net_device *dev; struct netlbl_unlhsh_iface *iface; - struct in_addr *addr4, *mask4; - struct in6_addr *addr6, *mask6; struct audit_buffer *audit_buf = NULL; char *secctx = NULL; u32 secctx_len; @@ -651,7 +651,9 @@ static int netlbl_unlhsh_add(struct net *net, audit_buf = netlbl_audit_start_common(AUDIT_MAC_UNLBL_STCADD, audit_info); switch (addr_len) { - case sizeof(struct in_addr): + case sizeof(struct in_addr): { + struct in_addr *addr4, *mask4; + addr4 = (struct in_addr *)addr; mask4 = (struct in_addr *)mask; ret_val = netlbl_unlhsh_add_addr4(iface, addr4, mask4, secid); @@ -661,8 +663,11 @@ static int netlbl_unlhsh_add(struct net *net, addr4->s_addr, mask4->s_addr); break; + } #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) - case sizeof(struct in6_addr): + case sizeof(struct in6_addr): { + struct in6_addr *addr6, *mask6; + addr6 = (struct in6_addr *)addr; mask6 = (struct in6_addr *)mask; ret_val = netlbl_unlhsh_add_addr6(iface, addr6, mask6, secid); @@ -671,6 +676,7 @@ static int netlbl_unlhsh_add(struct net *net, dev_name, addr6, mask6); break; + } #endif /* IPv6 */ default: ret_val = -EINVAL; @@ -1547,68 +1553,63 @@ unlabel_staticlistdef_return: * NetLabel Generic NETLINK Command Definitions */ -static struct genl_ops netlbl_unlabel_genl_c_staticadd = { +static struct genl_ops netlbl_unlabel_genl_ops[] = { + { .cmd = NLBL_UNLABEL_C_STATICADD, .flags = GENL_ADMIN_PERM, .policy = netlbl_unlabel_genl_policy, .doit = netlbl_unlabel_staticadd, .dumpit = NULL, -}; - -static struct genl_ops netlbl_unlabel_genl_c_staticremove = { + }, + { .cmd = NLBL_UNLABEL_C_STATICREMOVE, .flags = GENL_ADMIN_PERM, .policy = netlbl_unlabel_genl_policy, .doit = netlbl_unlabel_staticremove, .dumpit = NULL, -}; - -static struct genl_ops netlbl_unlabel_genl_c_staticlist = { + }, + { .cmd = NLBL_UNLABEL_C_STATICLIST, .flags = 0, .policy = netlbl_unlabel_genl_policy, .doit = NULL, .dumpit = netlbl_unlabel_staticlist, -}; - -static struct genl_ops netlbl_unlabel_genl_c_staticadddef = { + }, + { .cmd = NLBL_UNLABEL_C_STATICADDDEF, .flags = GENL_ADMIN_PERM, .policy = netlbl_unlabel_genl_policy, .doit = netlbl_unlabel_staticadddef, .dumpit = NULL, -}; - -static struct genl_ops netlbl_unlabel_genl_c_staticremovedef = { + }, + { .cmd = NLBL_UNLABEL_C_STATICREMOVEDEF, .flags = GENL_ADMIN_PERM, .policy = netlbl_unlabel_genl_policy, .doit = netlbl_unlabel_staticremovedef, .dumpit = NULL, -}; - -static struct genl_ops netlbl_unlabel_genl_c_staticlistdef = { + }, + { .cmd = NLBL_UNLABEL_C_STATICLISTDEF, .flags = 0, .policy = netlbl_unlabel_genl_policy, .doit = NULL, .dumpit = netlbl_unlabel_staticlistdef, -}; - -static struct genl_ops netlbl_unlabel_genl_c_accept = { + }, + { .cmd = NLBL_UNLABEL_C_ACCEPT, .flags = GENL_ADMIN_PERM, .policy = netlbl_unlabel_genl_policy, .doit = netlbl_unlabel_accept, .dumpit = NULL, -}; - -static struct genl_ops netlbl_unlabel_genl_c_list = { + }, + { .cmd = NLBL_UNLABEL_C_LIST, .flags = 0, .policy = netlbl_unlabel_genl_policy, .doit = netlbl_unlabel_list, .dumpit = NULL, + }, }; /* @@ -1623,53 +1624,20 @@ static struct genl_ops netlbl_unlabel_genl_c_list = { * mechanism. Returns zero on success, negative values on failure. * */ -int netlbl_unlabel_genl_init(void) +int __init netlbl_unlabel_genl_init(void) { - int ret_val; + int ret_val, i; ret_val = genl_register_family(&netlbl_unlabel_gnl_family); if (ret_val != 0) return ret_val; - ret_val = genl_register_ops(&netlbl_unlabel_gnl_family, - &netlbl_unlabel_genl_c_staticadd); - if (ret_val != 0) - return ret_val; - - ret_val = genl_register_ops(&netlbl_unlabel_gnl_family, - &netlbl_unlabel_genl_c_staticremove); - if (ret_val != 0) - return ret_val; - - ret_val = genl_register_ops(&netlbl_unlabel_gnl_family, - &netlbl_unlabel_genl_c_staticlist); - if (ret_val != 0) - return ret_val; - - ret_val = genl_register_ops(&netlbl_unlabel_gnl_family, - &netlbl_unlabel_genl_c_staticadddef); - if (ret_val != 0) - return ret_val; - - ret_val = genl_register_ops(&netlbl_unlabel_gnl_family, - &netlbl_unlabel_genl_c_staticremovedef); - if (ret_val != 0) - return ret_val; - - ret_val = genl_register_ops(&netlbl_unlabel_gnl_family, - &netlbl_unlabel_genl_c_staticlistdef); - if (ret_val != 0) - return ret_val; - - ret_val = genl_register_ops(&netlbl_unlabel_gnl_family, - &netlbl_unlabel_genl_c_accept); - if (ret_val != 0) - return ret_val; - - ret_val = genl_register_ops(&netlbl_unlabel_gnl_family, - &netlbl_unlabel_genl_c_list); - if (ret_val != 0) - return ret_val; + for (i = 0; i < ARRAY_SIZE(netlbl_unlabel_genl_ops); i++) { + ret_val = genl_register_ops(&netlbl_unlabel_gnl_family, + &netlbl_unlabel_genl_ops[i]); + if (ret_val != 0) + return ret_val; + } return 0; } @@ -1693,7 +1661,7 @@ static struct notifier_block netlbl_unlhsh_netdev_notifier = { * non-zero values on error. * */ -int netlbl_unlabel_init(u32 size) +int __init netlbl_unlabel_init(u32 size) { u32 iter; struct netlbl_unlhsh_tbl *hsh_tbl; @@ -1741,10 +1709,6 @@ int netlbl_unlabel_getattr(const struct sk_buff *skb, u16 family, struct netlbl_lsm_secattr *secattr) { - struct iphdr *hdr4; - struct ipv6hdr *hdr6; - struct netlbl_unlhsh_addr4 *addr4; - struct netlbl_unlhsh_addr6 *addr6; struct netlbl_unlhsh_iface *iface; rcu_read_lock(); @@ -1752,21 +1716,29 @@ int netlbl_unlabel_getattr(const struct sk_buff *skb, if (iface == NULL) goto unlabel_getattr_nolabel; switch (family) { - case PF_INET: + case PF_INET: { + struct iphdr *hdr4; + struct netlbl_unlhsh_addr4 *addr4; + hdr4 = ip_hdr(skb); addr4 = netlbl_unlhsh_search_addr4(hdr4->saddr, iface); if (addr4 == NULL) goto unlabel_getattr_nolabel; secattr->attr.secid = addr4->secid; break; + } #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) - case PF_INET6: + case PF_INET6: { + struct ipv6hdr *hdr6; + struct netlbl_unlhsh_addr6 *addr6; + hdr6 = ipv6_hdr(skb); addr6 = netlbl_unlhsh_search_addr6(&hdr6->saddr, iface); if (addr6 == NULL) goto unlabel_getattr_nolabel; secattr->attr.secid = addr6->secid; break; + } #endif /* IPv6 */ default: goto unlabel_getattr_nolabel; @@ -1793,7 +1765,7 @@ unlabel_getattr_nolabel: * and to send unlabeled network traffic by default. * */ -int netlbl_unlabel_defconf(void) +int __init netlbl_unlabel_defconf(void) { int ret_val; struct netlbl_dom_map *entry; diff --git a/net/netlabel/netlabel_user.c b/net/netlabel/netlabel_user.c index 85a96a3fdda..b17d4203806 100644 --- a/net/netlabel/netlabel_user.c +++ b/net/netlabel/netlabel_user.c @@ -59,7 +59,7 @@ * non-zero on failure. * */ -int netlbl_netlink_init(void) +int __init netlbl_netlink_init(void) { int ret_val; @@ -96,7 +96,6 @@ int netlbl_netlink_init(void) struct audit_buffer *netlbl_audit_start_common(int type, struct netlbl_audit *audit_info) { - struct audit_context *audit_ctx = current->audit_context; struct audit_buffer *audit_buf; char *secctx; u32 secctx_len; @@ -104,7 +103,7 @@ struct audit_buffer *netlbl_audit_start_common(int type, if (audit_enabled == 0) return NULL; - audit_buf = audit_log_start(audit_ctx, GFP_ATOMIC, type); + audit_buf = audit_log_start(current->audit_context, GFP_ATOMIC, type); if (audit_buf == NULL) return NULL; diff --git a/net/netlink/genetlink.c b/net/netlink/genetlink.c index 150579a2146..d16929c9b4b 100644 --- a/net/netlink/genetlink.c +++ b/net/netlink/genetlink.c @@ -230,10 +230,8 @@ static void genl_unregister_mc_groups(struct genl_family *family) { struct genl_multicast_group *grp, *tmp; - genl_lock(); list_for_each_entry_safe(grp, tmp, &family->mcast_groups, list) __genl_unregister_mc_group(family, grp); - genl_unlock(); } /** @@ -396,10 +394,10 @@ int genl_unregister_family(struct genl_family *family) { struct genl_family *rc; - genl_unregister_mc_groups(family); - genl_lock(); + genl_unregister_mc_groups(family); + list_for_each_entry(rc, genl_family_chain(family->id), family_list) { if (family->id != rc->id || strcmp(rc->name, family->name)) continue; diff --git a/net/rxrpc/ar-accept.c b/net/rxrpc/ar-accept.c index 92a87fde8bf..bdfb7741779 100644 --- a/net/rxrpc/ar-accept.c +++ b/net/rxrpc/ar-accept.c @@ -156,8 +156,7 @@ static int rxrpc_accept_incoming_call(struct rxrpc_local *local, false); spin_unlock(&call->lock); notification = NULL; - if (ret < 0) - BUG(); + BUG_ON(ret < 0); } spin_unlock(&call->conn->state_lock); diff --git a/net/rxrpc/ar-ack.c b/net/rxrpc/ar-ack.c index 657ee69f213..3ac1672e107 100644 --- a/net/rxrpc/ar-ack.c +++ b/net/rxrpc/ar-ack.c @@ -814,8 +814,7 @@ static int rxrpc_post_message(struct rxrpc_call *call, u32 mark, u32 error, spin_lock_bh(&call->lock); ret = rxrpc_queue_rcv_skb(call, skb, true, fatal); spin_unlock_bh(&call->lock); - if (ret < 0) - BUG(); + BUG_ON(ret < 0); } return 0; diff --git a/net/socket.c b/net/socket.c index 7651de00850..b6d35cd72a5 100644 --- a/net/socket.c +++ b/net/socket.c @@ -701,6 +701,9 @@ static ssize_t sock_splice_read(struct file *file, loff_t *ppos, { struct socket *sock = file->private_data; + if (unlikely(!sock->ops->splice_read)) + return -EINVAL; + return sock->ops->splice_read(sock, ppos, pipe, len, flags); } diff --git a/net/sunrpc/clnt.c b/net/sunrpc/clnt.c index 0998e6d0966..8c6a7f1a25e 100644 --- a/net/sunrpc/clnt.c +++ b/net/sunrpc/clnt.c @@ -464,9 +464,9 @@ rpc_release_client(struct rpc_clnt *clnt) /** * rpc_bind_new_program - bind a new RPC program to an existing client - * @old - old rpc_client - * @program - rpc program to set - * @vers - rpc program version + * @old: old rpc_client + * @program: rpc program to set + * @vers: rpc program version * * Clones the rpc client and sets up a new RPC program. This is mainly * of use for enabling different RPC programs to share the same transport. @@ -575,7 +575,7 @@ EXPORT_SYMBOL_GPL(rpc_call_sync); * @clnt: pointer to RPC client * @msg: RPC call parameters * @flags: RPC call flags - * @ops: RPC call ops + * @tk_ops: RPC call ops * @data: user call data */ int @@ -610,7 +610,7 @@ EXPORT_SYMBOL_GPL(rpc_call_start); * rpc_peeraddr - extract remote peer address from clnt's xprt * @clnt: RPC client structure * @buf: target buffer - * @size: length of target buffer + * @bufsize: length of target buffer * * Returns the number of bytes that are actually in the stored address. */ diff --git a/net/sunrpc/rpc_pipe.c b/net/sunrpc/rpc_pipe.c index 7e197168a24..1b395a41a8b 100644 --- a/net/sunrpc/rpc_pipe.c +++ b/net/sunrpc/rpc_pipe.c @@ -495,7 +495,7 @@ rpc_lookup_parent(char *path, struct nameidata *nd) static void rpc_release_path(struct nameidata *nd) { - path_release(nd); + path_put(&nd->path); rpc_put_mount(); } @@ -668,7 +668,8 @@ rpc_lookup_negative(char *path, struct nameidata *nd) if ((error = rpc_lookup_parent(path, nd)) != 0) return ERR_PTR(error); - dentry = rpc_lookup_create(nd->dentry, nd->last.name, nd->last.len, 1); + dentry = rpc_lookup_create(nd->path.dentry, nd->last.name, nd->last.len, + 1); if (IS_ERR(dentry)) rpc_release_path(nd); return dentry; @@ -677,7 +678,7 @@ rpc_lookup_negative(char *path, struct nameidata *nd) /** * rpc_mkdir - Create a new directory in rpc_pipefs * @path: path from the rpc_pipefs root to the new directory - * @rpc_clnt: rpc client to associate with this directory + * @rpc_client: rpc client to associate with this directory * * This creates a directory at the given @path associated with * @rpc_clnt, which will contain a file named "info" with some basic @@ -695,7 +696,7 @@ rpc_mkdir(char *path, struct rpc_clnt *rpc_client) dentry = rpc_lookup_negative(path, &nd); if (IS_ERR(dentry)) return dentry; - dir = nd.dentry->d_inode; + dir = nd.path.dentry->d_inode; if ((error = __rpc_mkdir(dir, dentry)) != 0) goto err_dput; RPC_I(dentry->d_inode)->private = rpc_client; @@ -748,6 +749,7 @@ rpc_rmdir(struct dentry *dentry) * @private: private data to associate with the pipe, for the caller's use * @ops: operations defining the behavior of the pipe: upcall, downcall, * release_pipe, and destroy_msg. + * @flags: rpc_inode flags * * Data is made available for userspace to read by calls to * rpc_queue_upcall(). The actual reads will result in calls to diff --git a/net/sunrpc/xprt.c b/net/sunrpc/xprt.c index cfcade906a5..d5553b8179f 100644 --- a/net/sunrpc/xprt.c +++ b/net/sunrpc/xprt.c @@ -124,7 +124,7 @@ EXPORT_SYMBOL_GPL(xprt_register_transport); /** * xprt_unregister_transport - unregister a transport implementation - * transport: transport to unregister + * @transport: transport to unregister * * Returns: * 0: transport successfully unregistered diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c index eea75888805..b8788fd5e3c 100644 --- a/net/unix/af_unix.c +++ b/net/unix/af_unix.c @@ -718,16 +718,16 @@ static struct sock *unix_find_other(struct net *net, goto put_fail; err = -ECONNREFUSED; - if (!S_ISSOCK(nd.dentry->d_inode->i_mode)) + if (!S_ISSOCK(nd.path.dentry->d_inode->i_mode)) goto put_fail; - u=unix_find_socket_byinode(net, nd.dentry->d_inode); + u = unix_find_socket_byinode(net, nd.path.dentry->d_inode); if (!u) goto put_fail; if (u->sk_type == type) - touch_atime(nd.mnt, nd.dentry); + touch_atime(nd.path.mnt, nd.path.dentry); - path_release(&nd); + path_put(&nd.path); err=-EPROTOTYPE; if (u->sk_type != type) { @@ -748,7 +748,7 @@ static struct sock *unix_find_other(struct net *net, return u; put_fail: - path_release(&nd); + path_put(&nd.path); fail: *error=err; return NULL; @@ -819,12 +819,12 @@ static int unix_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len) */ mode = S_IFSOCK | (SOCK_INODE(sock)->i_mode & ~current->fs->umask); - err = vfs_mknod(nd.dentry->d_inode, dentry, mode, 0); + err = vfs_mknod(nd.path.dentry->d_inode, dentry, mode, 0); if (err) goto out_mknod_dput; - mutex_unlock(&nd.dentry->d_inode->i_mutex); - dput(nd.dentry); - nd.dentry = dentry; + mutex_unlock(&nd.path.dentry->d_inode->i_mutex); + dput(nd.path.dentry); + nd.path.dentry = dentry; addr->hash = UNIX_HASH_SIZE; } @@ -842,8 +842,8 @@ static int unix_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len) list = &unix_socket_table[addr->hash]; } else { list = &unix_socket_table[dentry->d_inode->i_ino & (UNIX_HASH_SIZE-1)]; - u->dentry = nd.dentry; - u->mnt = nd.mnt; + u->dentry = nd.path.dentry; + u->mnt = nd.path.mnt; } err = 0; @@ -861,8 +861,8 @@ out: out_mknod_dput: dput(dentry); out_mknod_unlock: - mutex_unlock(&nd.dentry->d_inode->i_mutex); - path_release(&nd); + mutex_unlock(&nd.path.dentry->d_inode->i_mutex); + path_put(&nd.path); out_mknod_parent: if (err==-EEXIST) err=-EADDRINUSE; diff --git a/net/xfrm/Kconfig b/net/xfrm/Kconfig index 8f9dbec319b..9201ef8ad90 100644 --- a/net/xfrm/Kconfig +++ b/net/xfrm/Kconfig @@ -38,7 +38,7 @@ config XFRM_MIGRATE config XFRM_STATISTICS bool "Transformation statistics (EXPERIMENTAL)" - depends on XFRM && PROC_FS && EXPERIMENTAL + depends on INET && XFRM && PROC_FS && EXPERIMENTAL ---help--- This statistics is not a SNMP/MIB specification but shows statistics about transformation error (or almost error) factor diff --git a/net/xfrm/xfrm_input.c b/net/xfrm/xfrm_input.c index 4d6ebc633a9..62188c6a06d 100644 --- a/net/xfrm/xfrm_input.c +++ b/net/xfrm/xfrm_input.c @@ -109,7 +109,7 @@ int xfrm_input(struct sk_buff *skb, int nexthdr, __be32 spi, int encap_type) if (encap_type < 0) { async = 1; x = xfrm_input_state(skb); - seq = XFRM_SKB_CB(skb)->seq; + seq = XFRM_SKB_CB(skb)->seq.input; goto resume; } @@ -175,7 +175,7 @@ int xfrm_input(struct sk_buff *skb, int nexthdr, __be32 spi, int encap_type) spin_unlock(&x->lock); - XFRM_SKB_CB(skb)->seq = seq; + XFRM_SKB_CB(skb)->seq.input = seq; nexthdr = x->type->input(x, skb); diff --git a/net/xfrm/xfrm_output.c b/net/xfrm/xfrm_output.c index fc690368325..569d377932c 100644 --- a/net/xfrm/xfrm_output.c +++ b/net/xfrm/xfrm_output.c @@ -62,7 +62,7 @@ static int xfrm_output_one(struct sk_buff *skb, int err) } if (x->type->flags & XFRM_TYPE_REPLAY_PROT) { - XFRM_SKB_CB(skb)->seq = ++x->replay.oseq; + XFRM_SKB_CB(skb)->seq.output = ++x->replay.oseq; if (unlikely(x->replay.oseq == 0)) { XFRM_INC_STATS(LINUX_MIB_XFRMOUTSTATESEQERROR); x->replay.oseq--; diff --git a/net/xfrm/xfrm_policy.c b/net/xfrm/xfrm_policy.c index 47219f98053..9fc4c315f6c 100644 --- a/net/xfrm/xfrm_policy.c +++ b/net/xfrm/xfrm_policy.c @@ -331,15 +331,31 @@ static void xfrm_dst_hash_transfer(struct hlist_head *list, struct hlist_head *ndsttable, unsigned int nhashmask) { - struct hlist_node *entry, *tmp; + struct hlist_node *entry, *tmp, *entry0 = NULL; struct xfrm_policy *pol; + unsigned int h0 = 0; +redo: hlist_for_each_entry_safe(pol, entry, tmp, list, bydst) { unsigned int h; h = __addr_hash(&pol->selector.daddr, &pol->selector.saddr, pol->family, nhashmask); - hlist_add_head(&pol->bydst, ndsttable+h); + if (!entry0) { + hlist_del(entry); + hlist_add_head(&pol->bydst, ndsttable+h); + h0 = h; + } else { + if (h != h0) + continue; + hlist_del(entry); + hlist_add_after(entry0, &pol->bydst); + } + entry0 = entry; + } + if (!hlist_empty(list)) { + entry0 = NULL; + goto redo; } } diff --git a/net/xfrm/xfrm_user.c b/net/xfrm/xfrm_user.c index 78338079b7f..f971ca5645f 100644 --- a/net/xfrm/xfrm_user.c +++ b/net/xfrm/xfrm_user.c @@ -1105,6 +1105,7 @@ static struct xfrm_policy *xfrm_policy_construct(struct xfrm_userpolicy_info *p, return xp; error: *errp = err; + xp->dead = 1; xfrm_policy_destroy(xp); return NULL; } diff --git a/samples/markers/probe-example.c b/samples/markers/probe-example.c index a3679753561..c8e099d4d1f 100644 --- a/samples/markers/probe-example.c +++ b/samples/markers/probe-example.c @@ -20,31 +20,27 @@ struct probe_data { marker_probe_func *probe_func; }; -void probe_subsystem_event(const struct marker *mdata, void *private, - const char *format, ...) +void probe_subsystem_event(void *probe_data, void *call_data, + const char *format, va_list *args) { - va_list ap; /* Declare args */ unsigned int value; const char *mystr; /* Assign args */ - va_start(ap, format); - value = va_arg(ap, typeof(value)); - mystr = va_arg(ap, typeof(mystr)); + value = va_arg(*args, typeof(value)); + mystr = va_arg(*args, typeof(mystr)); /* Call printk */ - printk(KERN_DEBUG "Value %u, string %s\n", value, mystr); + printk(KERN_INFO "Value %u, string %s\n", value, mystr); /* or count, check rights, serialize data in a buffer */ - - va_end(ap); } atomic_t eventb_count = ATOMIC_INIT(0); -void probe_subsystem_eventb(const struct marker *mdata, void *private, - const char *format, ...) +void probe_subsystem_eventb(void *probe_data, void *call_data, + const char *format, va_list *args) { /* Increment counter */ atomic_inc(&eventb_count); @@ -72,10 +68,6 @@ static int __init probe_init(void) if (result) printk(KERN_INFO "Unable to register probe %s\n", probe_array[i].name); - result = marker_arm(probe_array[i].name); - if (result) - printk(KERN_INFO "Unable to arm probe %s\n", - probe_array[i].name); } return 0; } @@ -85,7 +77,8 @@ static void __exit probe_fini(void) int i; for (i = 0; i < ARRAY_SIZE(probe_array); i++) - marker_probe_unregister(probe_array[i].name); + marker_probe_unregister(probe_array[i].name, + probe_array[i].probe_func, &probe_array[i]); printk(KERN_INFO "Number of event b : %u\n", atomic_read(&eventb_count)); } diff --git a/scripts/Makefile.modpost b/scripts/Makefile.modpost index 65e707e1ffc..cfc004e0441 100644 --- a/scripts/Makefile.modpost +++ b/scripts/Makefile.modpost @@ -13,6 +13,7 @@ # 2) modpost is then used to # 3) create one <module>.mod.c file pr. module # 4) create one Module.symvers file with CRC for all exported symbols +# 4a) [CONFIG_MARKERS] create one Module.markers file listing defined markers # 5) compile all <module>.mod.c files # 6) final link of the module to a <module.ko> file @@ -45,6 +46,10 @@ include scripts/Makefile.lib kernelsymfile := $(objtree)/Module.symvers modulesymfile := $(firstword $(KBUILD_EXTMOD))/Module.symvers +kernelmarkersfile := $(objtree)/Module.markers +modulemarkersfile := $(firstword $(KBUILD_EXTMOD))/Module.markers + +markersfile = $(if $(KBUILD_EXTMOD),$(modulemarkersfile),$(kernelmarkersfile)) # Step 1), find all modules listed in $(MODVERDIR)/ __modules := $(sort $(shell grep -h '\.ko' /dev/null $(wildcard $(MODVERDIR)/*.mod))) @@ -63,6 +68,8 @@ modpost = scripts/mod/modpost \ $(if $(KBUILD_EXTMOD),-I $(modulesymfile)) \ $(if $(KBUILD_EXTMOD),-o $(modulesymfile)) \ $(if $(CONFIG_DEBUG_SECTION_MISMATCH),,-S) \ + $(if $(CONFIG_MARKERS),-K $(kernelmarkersfile)) \ + $(if $(CONFIG_MARKERS),-M $(markersfile)) \ $(if $(KBUILD_EXTMOD)$(KBUILD_MODPOST_WARN),-w) quiet_cmd_modpost = MODPOST $(words $(filter-out vmlinux FORCE, $^)) modules @@ -82,6 +89,10 @@ vmlinux.o: FORCE $(symverfile): __modpost ; $(modules:.ko=.mod.c): __modpost ; +ifdef CONFIG_MARKERS +$(markersfile): __modpost ; +endif + # Step 5), compile all *.mod.c files diff --git a/scripts/kconfig/symbol.c b/scripts/kconfig/symbol.c index 3929e5b35e7..4a03191ad17 100644 --- a/scripts/kconfig/symbol.c +++ b/scripts/kconfig/symbol.c @@ -298,22 +298,30 @@ void sym_calc_value(struct symbol *sym) if (sym_is_choice_value(sym) && sym->visible == yes) { prop = sym_get_choice_prop(sym); newval.tri = (prop_get_symbol(prop)->curr.val == sym) ? yes : no; - } else if (EXPR_OR(sym->visible, sym->rev_dep.tri) != no) { - sym->flags |= SYMBOL_WRITE; - if (sym_has_value(sym)) - newval.tri = sym->def[S_DEF_USER].tri; - else if (!sym_is_choice(sym)) { - prop = sym_get_default_prop(sym); - if (prop) - newval.tri = expr_calc_value(prop->expr); + } else { + if (sym->visible != no) { + /* if the symbol is visible use the user value + * if available, otherwise try the default value + */ + sym->flags |= SYMBOL_WRITE; + if (sym_has_value(sym)) { + newval.tri = EXPR_AND(sym->def[S_DEF_USER].tri, + sym->visible); + goto calc_newval; + } } - newval.tri = EXPR_OR(EXPR_AND(newval.tri, sym->visible), sym->rev_dep.tri); - } else if (!sym_is_choice(sym)) { - prop = sym_get_default_prop(sym); - if (prop) { + if (sym->rev_dep.tri != no) sym->flags |= SYMBOL_WRITE; - newval.tri = expr_calc_value(prop->expr); + if (!sym_is_choice(sym)) { + prop = sym_get_default_prop(sym); + if (prop) { + sym->flags |= SYMBOL_WRITE; + newval.tri = EXPR_AND(expr_calc_value(prop->expr), + prop->visible.tri); + } } + calc_newval: + newval.tri = EXPR_OR(newval.tri, sym->rev_dep.tri); } if (newval.tri == mod && sym_get_type(sym) == S_BOOLEAN) newval.tri = yes; diff --git a/scripts/kernel-doc b/scripts/kernel-doc index 6c18a14386a..26146cbaa50 100755 --- a/scripts/kernel-doc +++ b/scripts/kernel-doc @@ -1624,7 +1624,6 @@ sub dump_function($$) { $prototype =~ s/^static +//; $prototype =~ s/^extern +//; - $prototype =~ s/^fastcall +//; $prototype =~ s/^asmlinkage +//; $prototype =~ s/^inline +//; $prototype =~ s/^__inline__ +//; diff --git a/scripts/mod/modpost.c b/scripts/mod/modpost.c index dbe1fb5e8cc..61742771c65 100644 --- a/scripts/mod/modpost.c +++ b/scripts/mod/modpost.c @@ -11,6 +11,8 @@ * Usage: modpost vmlinux module1.o module2.o ... */ +#define _GNU_SOURCE +#include <stdio.h> #include <ctype.h> #include "modpost.h" #include "../../include/linux/license.h" @@ -435,6 +437,8 @@ static int parse_elf(struct elf_info *info, const char *filename) info->export_unused_gpl_sec = i; else if (strcmp(secname, "__ksymtab_gpl_future") == 0) info->export_gpl_future_sec = i; + else if (strcmp(secname, "__markers_strings") == 0) + info->markers_strings_sec = i; if (sechdrs[i].sh_type != SHT_SYMTAB) continue; @@ -1470,6 +1474,62 @@ static void check_sec_ref(struct module *mod, const char *modname, } } +static void get_markers(struct elf_info *info, struct module *mod) +{ + const Elf_Shdr *sh = &info->sechdrs[info->markers_strings_sec]; + const char *strings = (const char *) info->hdr + sh->sh_offset; + const Elf_Sym *sym, *first_sym, *last_sym; + size_t n; + + if (!info->markers_strings_sec) + return; + + /* + * First count the strings. We look for all the symbols defined + * in the __markers_strings section named __mstrtab_*. For + * these local names, the compiler puts a random .NNN suffix on, + * so the names don't correspond exactly. + */ + first_sym = last_sym = NULL; + n = 0; + for (sym = info->symtab_start; sym < info->symtab_stop; sym++) + if (ELF_ST_TYPE(sym->st_info) == STT_OBJECT && + sym->st_shndx == info->markers_strings_sec && + !strncmp(info->strtab + sym->st_name, + "__mstrtab_", sizeof "__mstrtab_" - 1)) { + if (first_sym == NULL) + first_sym = sym; + last_sym = sym; + ++n; + } + + if (n == 0) + return; + + /* + * Now collect each name and format into a line for the output. + * Lines look like: + * marker_name vmlinux marker %s format %d + * The format string after the second \t can use whitespace. + */ + mod->markers = NOFAIL(malloc(sizeof mod->markers[0] * n)); + mod->nmarkers = n; + + n = 0; + for (sym = first_sym; sym <= last_sym; sym++) + if (ELF_ST_TYPE(sym->st_info) == STT_OBJECT && + sym->st_shndx == info->markers_strings_sec && + !strncmp(info->strtab + sym->st_name, + "__mstrtab_", sizeof "__mstrtab_" - 1)) { + const char *name = strings + sym->st_value; + const char *fmt = strchr(name, '\0') + 1; + char *line = NULL; + asprintf(&line, "%s\t%s\t%s\n", name, mod->name, fmt); + NOFAIL(line); + mod->markers[n++] = line; + } +} + static void read_symbols(char *modname) { const char *symname; @@ -1521,6 +1581,8 @@ static void read_symbols(char *modname) get_src_version(modname, mod->srcversion, sizeof(mod->srcversion)-1); + get_markers(&info, mod); + parse_elf_finish(&info); /* Our trick to get versioning for struct_module - it's @@ -1867,16 +1929,104 @@ static void write_dump(const char *fname) write_if_changed(&buf, fname); } +static void add_marker(struct module *mod, const char *name, const char *fmt) +{ + char *line = NULL; + asprintf(&line, "%s\t%s\t%s\n", name, mod->name, fmt); + NOFAIL(line); + + mod->markers = NOFAIL(realloc(mod->markers, ((mod->nmarkers + 1) * + sizeof mod->markers[0]))); + mod->markers[mod->nmarkers++] = line; +} + +static void read_markers(const char *fname) +{ + unsigned long size, pos = 0; + void *file = grab_file(fname, &size); + char *line; + + if (!file) /* No old markers, silently ignore */ + return; + + while ((line = get_next_line(&pos, file, size))) { + char *marker, *modname, *fmt; + struct module *mod; + + marker = line; + modname = strchr(marker, '\t'); + if (!modname) + goto fail; + *modname++ = '\0'; + fmt = strchr(modname, '\t'); + if (!fmt) + goto fail; + *fmt++ = '\0'; + if (*marker == '\0' || *modname == '\0') + goto fail; + + mod = find_module(modname); + if (!mod) { + if (is_vmlinux(modname)) + have_vmlinux = 1; + mod = new_module(NOFAIL(strdup(modname))); + mod->skip = 1; + } + + add_marker(mod, marker, fmt); + } + return; +fail: + fatal("parse error in markers list file\n"); +} + +static int compare_strings(const void *a, const void *b) +{ + return strcmp(*(const char **) a, *(const char **) b); +} + +static void write_markers(const char *fname) +{ + struct buffer buf = { }; + struct module *mod; + size_t i; + + for (mod = modules; mod; mod = mod->next) + if ((!external_module || !mod->skip) && mod->markers != NULL) { + /* + * Sort the strings so we can skip duplicates when + * we write them out. + */ + qsort(mod->markers, mod->nmarkers, + sizeof mod->markers[0], &compare_strings); + for (i = 0; i < mod->nmarkers; ++i) { + char *line = mod->markers[i]; + buf_write(&buf, line, strlen(line)); + while (i + 1 < mod->nmarkers && + !strcmp(mod->markers[i], + mod->markers[i + 1])) + free(mod->markers[i++]); + free(mod->markers[i]); + } + free(mod->markers); + mod->markers = NULL; + } + + write_if_changed(&buf, fname); +} + int main(int argc, char **argv) { struct module *mod; struct buffer buf = { }; char *kernel_read = NULL, *module_read = NULL; char *dump_write = NULL; + char *markers_read = NULL; + char *markers_write = NULL; int opt; int err; - while ((opt = getopt(argc, argv, "i:I:msSo:aw")) != -1) { + while ((opt = getopt(argc, argv, "i:I:msSo:awM:K:")) != -1) { switch (opt) { case 'i': kernel_read = optarg; @@ -1903,6 +2053,12 @@ int main(int argc, char **argv) case 'w': warn_unresolved = 1; break; + case 'M': + markers_write = optarg; + break; + case 'K': + markers_read = optarg; + break; default: exit(1); } @@ -1950,5 +2106,11 @@ int main(int argc, char **argv) "'make CONFIG_DEBUG_SECTION_MISMATCH=y'\n", sec_mismatch_count); + if (markers_read) + read_markers(markers_read); + + if (markers_write) + write_markers(markers_write); + return err; } diff --git a/scripts/mod/modpost.h b/scripts/mod/modpost.h index 999f15e0e00..565c5872407 100644 --- a/scripts/mod/modpost.h +++ b/scripts/mod/modpost.h @@ -112,6 +112,8 @@ struct module { int has_init; int has_cleanup; struct buffer dev_table_buf; + char **markers; + size_t nmarkers; char srcversion[25]; }; @@ -126,6 +128,7 @@ struct elf_info { Elf_Section export_gpl_sec; Elf_Section export_unused_gpl_sec; Elf_Section export_gpl_future_sec; + Elf_Section markers_strings_sec; const char *strtab; char *modinfo; unsigned int modinfo_len; diff --git a/security/selinux/avc.c b/security/selinux/avc.c index e8529e2f51e..187964e88af 100644 --- a/security/selinux/avc.c +++ b/security/selinux/avc.c @@ -568,10 +568,11 @@ void avc_audit(u32 ssid, u32 tsid, audit_log_format(ab, " capability=%d", a->u.cap); break; case AVC_AUDIT_DATA_FS: - if (a->u.fs.dentry) { - struct dentry *dentry = a->u.fs.dentry; - if (a->u.fs.mnt) { - audit_log_d_path(ab, "path=", dentry, a->u.fs.mnt); + if (a->u.fs.path.dentry) { + struct dentry *dentry = a->u.fs.path.dentry; + if (a->u.fs.path.mnt) { + audit_log_d_path(ab, "path=", + &a->u.fs.path); } else { audit_log_format(ab, " name="); audit_log_untrustedstring(ab, dentry->d_name.name); @@ -626,8 +627,12 @@ void avc_audit(u32 ssid, u32 tsid, case AF_UNIX: u = unix_sk(sk); if (u->dentry) { + struct path path = { + .dentry = u->dentry, + .mnt = u->mnt + }; audit_log_d_path(ab, "path=", - u->dentry, u->mnt); + &path); break; } if (!u->addr) diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index 44f16d9041e..75c2e99bfb8 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c @@ -1356,8 +1356,8 @@ static inline int dentry_has_perm(struct task_struct *tsk, struct inode *inode = dentry->d_inode; struct avc_audit_data ad; AVC_AUDIT_DATA_INIT(&ad,FS); - ad.u.fs.mnt = mnt; - ad.u.fs.dentry = dentry; + ad.u.fs.path.mnt = mnt; + ad.u.fs.path.dentry = dentry; return inode_has_perm(tsk, inode, av, &ad); } @@ -1375,15 +1375,12 @@ static int file_has_perm(struct task_struct *tsk, { struct task_security_struct *tsec = tsk->security; struct file_security_struct *fsec = file->f_security; - struct vfsmount *mnt = file->f_path.mnt; - struct dentry *dentry = file->f_path.dentry; - struct inode *inode = dentry->d_inode; + struct inode *inode = file->f_path.dentry->d_inode; struct avc_audit_data ad; int rc; AVC_AUDIT_DATA_INIT(&ad, FS); - ad.u.fs.mnt = mnt; - ad.u.fs.dentry = dentry; + ad.u.fs.path = file->f_path; if (tsec->sid != fsec->sid) { rc = avc_has_perm(tsec->sid, fsec->sid, @@ -1418,7 +1415,7 @@ static int may_create(struct inode *dir, sbsec = dir->i_sb->s_security; AVC_AUDIT_DATA_INIT(&ad, FS); - ad.u.fs.dentry = dentry; + ad.u.fs.path.dentry = dentry; rc = avc_has_perm(tsec->sid, dsec->sid, SECCLASS_DIR, DIR__ADD_NAME | DIR__SEARCH, @@ -1476,7 +1473,7 @@ static int may_link(struct inode *dir, isec = dentry->d_inode->i_security; AVC_AUDIT_DATA_INIT(&ad, FS); - ad.u.fs.dentry = dentry; + ad.u.fs.path.dentry = dentry; av = DIR__SEARCH; av |= (kind ? DIR__REMOVE_NAME : DIR__ADD_NAME); @@ -1523,7 +1520,7 @@ static inline int may_rename(struct inode *old_dir, AVC_AUDIT_DATA_INIT(&ad, FS); - ad.u.fs.dentry = old_dentry; + ad.u.fs.path.dentry = old_dentry; rc = avc_has_perm(tsec->sid, old_dsec->sid, SECCLASS_DIR, DIR__REMOVE_NAME | DIR__SEARCH, &ad); if (rc) @@ -1539,7 +1536,7 @@ static inline int may_rename(struct inode *old_dir, return rc; } - ad.u.fs.dentry = new_dentry; + ad.u.fs.path.dentry = new_dentry; av = DIR__ADD_NAME | DIR__SEARCH; if (new_dentry->d_inode) av |= DIR__REMOVE_NAME; @@ -1918,8 +1915,7 @@ static int selinux_bprm_set_security(struct linux_binprm *bprm) } AVC_AUDIT_DATA_INIT(&ad, FS); - ad.u.fs.mnt = bprm->file->f_path.mnt; - ad.u.fs.dentry = bprm->file->f_path.dentry; + ad.u.fs.path = bprm->file->f_path; if (bprm->file->f_path.mnt->mnt_flags & MNT_NOSUID) newsid = tsec->sid; @@ -2315,7 +2311,7 @@ static int selinux_sb_kern_mount(struct super_block *sb, void *data) return rc; AVC_AUDIT_DATA_INIT(&ad,FS); - ad.u.fs.dentry = sb->s_root; + ad.u.fs.path.dentry = sb->s_root; return superblock_has_perm(current, sb, FILESYSTEM__MOUNT, &ad); } @@ -2324,7 +2320,7 @@ static int selinux_sb_statfs(struct dentry *dentry) struct avc_audit_data ad; AVC_AUDIT_DATA_INIT(&ad,FS); - ad.u.fs.dentry = dentry->d_sb->s_root; + ad.u.fs.path.dentry = dentry->d_sb->s_root; return superblock_has_perm(current, dentry->d_sb, FILESYSTEM__GETATTR, &ad); } @@ -2341,10 +2337,10 @@ static int selinux_mount(char * dev_name, return rc; if (flags & MS_REMOUNT) - return superblock_has_perm(current, nd->mnt->mnt_sb, + return superblock_has_perm(current, nd->path.mnt->mnt_sb, FILESYSTEM__REMOUNT, NULL); else - return dentry_has_perm(current, nd->mnt, nd->dentry, + return dentry_has_perm(current, nd->path.mnt, nd->path.dentry, FILE__MOUNTON); } @@ -2587,7 +2583,7 @@ static int selinux_inode_setxattr(struct dentry *dentry, char *name, void *value return -EPERM; AVC_AUDIT_DATA_INIT(&ad,FS); - ad.u.fs.dentry = dentry; + ad.u.fs.path.dentry = dentry; rc = avc_has_perm(tsec->sid, isec->sid, isec->sclass, FILE__RELABELFROM, &ad); diff --git a/security/selinux/include/avc.h b/security/selinux/include/avc.h index 80c28fa6621..8e23d7a873a 100644 --- a/security/selinux/include/avc.h +++ b/security/selinux/include/avc.h @@ -13,6 +13,7 @@ #include <linux/spinlock.h> #include <linux/init.h> #include <linux/in6.h> +#include <linux/path.h> #include <asm/system.h> #include "flask.h" #include "av_permissions.h" @@ -30,8 +31,6 @@ extern int selinux_enforcing; struct avc_entry; struct task_struct; -struct vfsmount; -struct dentry; struct inode; struct sock; struct sk_buff; @@ -46,8 +45,7 @@ struct avc_audit_data { struct task_struct *tsk; union { struct { - struct vfsmount *mnt; - struct dentry *dentry; + struct path path; struct inode *inode; } fs; struct { diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c index 1c11e424585..25cbfa3f71f 100644 --- a/security/smack/smack_lsm.c +++ b/security/smack/smack_lsm.c @@ -325,7 +325,7 @@ static int smack_sb_statfs(struct dentry *dentry) static int smack_sb_mount(char *dev_name, struct nameidata *nd, char *type, unsigned long flags, void *data) { - struct superblock_smack *sbp = nd->mnt->mnt_sb->s_security; + struct superblock_smack *sbp = nd->path.mnt->mnt_sb->s_security; return smk_curacc(sbp->smk_floor, MAY_WRITE); } @@ -701,7 +701,7 @@ static int smack_inode_getsecurity(const struct inode *inode, return -EOPNOTSUPP; sock = SOCKET_I(ip); - if (sock == NULL) + if (sock == NULL || sock->sk == NULL) return -EOPNOTSUPP; ssp = sock->sk->sk_security; @@ -1251,9 +1251,8 @@ static void smack_to_secattr(char *smack, struct netlbl_lsm_secattr *nlsp) switch (smack_net_nltype) { case NETLBL_NLTYPE_CIPSOV4: - nlsp->domain = NULL; - nlsp->flags = NETLBL_SECATTR_DOMAIN; - nlsp->flags |= NETLBL_SECATTR_MLS_LVL; + nlsp->domain = kstrdup(smack, GFP_ATOMIC); + nlsp->flags = NETLBL_SECATTR_DOMAIN | NETLBL_SECATTR_MLS_LVL; rc = smack_to_cipso(smack, &cipso); if (rc == 0) { @@ -1280,16 +1279,16 @@ static void smack_to_secattr(char *smack, struct netlbl_lsm_secattr *nlsp) */ static int smack_netlabel(struct sock *sk) { - struct socket_smack *ssp = sk->sk_security; + struct socket_smack *ssp; struct netlbl_lsm_secattr secattr; - int rc = 0; + int rc; + ssp = sk->sk_security; netlbl_secattr_init(&secattr); smack_to_secattr(ssp->smk_out, &secattr); - if (secattr.flags != NETLBL_SECATTR_NONE) - rc = netlbl_sock_setattr(sk, &secattr); - + rc = netlbl_sock_setattr(sk, &secattr); netlbl_secattr_destroy(&secattr); + return rc; } @@ -1312,6 +1311,7 @@ static int smack_inode_setsecurity(struct inode *inode, const char *name, struct inode_smack *nsp = inode->i_security; struct socket_smack *ssp; struct socket *sock; + int rc = 0; if (value == NULL || size > SMK_LABELLEN) return -EACCES; @@ -1331,7 +1331,7 @@ static int smack_inode_setsecurity(struct inode *inode, const char *name, return -EOPNOTSUPP; sock = SOCKET_I(inode); - if (sock == NULL) + if (sock == NULL || sock->sk == NULL) return -EOPNOTSUPP; ssp = sock->sk->sk_security; @@ -1340,7 +1340,10 @@ static int smack_inode_setsecurity(struct inode *inode, const char *name, ssp->smk_in = sp; else if (strcmp(name, XATTR_SMACK_IPOUT) == 0) { ssp->smk_out = sp; - return smack_netlabel(sock->sk); + rc = smack_netlabel(sock->sk); + if (rc != 0) + printk(KERN_WARNING "Smack: \"%s\" netlbl error %d.\n", + __func__, -rc); } else return -EOPNOTSUPP; @@ -1362,7 +1365,7 @@ static int smack_inode_setsecurity(struct inode *inode, const char *name, static int smack_socket_post_create(struct socket *sock, int family, int type, int protocol, int kern) { - if (family != PF_INET) + if (family != PF_INET || sock->sk == NULL) return 0; /* * Set the outbound netlbl. @@ -2213,6 +2216,9 @@ static void smack_sock_graft(struct sock *sk, struct socket *parent) ssp->smk_packet[0] = '\0'; rc = smack_netlabel(sk); + if (rc != 0) + printk(KERN_WARNING "Smack: \"%s\" netlbl error %d.\n", + __func__, -rc); } /** @@ -2345,6 +2351,20 @@ static int smack_secid_to_secctx(u32 secid, char **secdata, u32 *seclen) } /* + * smack_secctx_to_secid - return the secid for a smack label + * @secdata: smack label + * @seclen: how long result is + * @secid: outgoing integer + * + * Exists for audit and networking code. + */ +static int smack_secctx_to_secid(char *secdata, u32 seclen, u32 *secid) +{ + *secid = smack_to_secid(secdata); + return 0; +} + +/* * smack_release_secctx - don't do anything. * @key_ref: unused * @context: unused @@ -2474,6 +2494,7 @@ static struct security_operations smack_ops = { .key_permission = smack_key_permission, #endif /* CONFIG_KEYS */ .secid_to_secctx = smack_secid_to_secctx, + .secctx_to_secid = smack_secctx_to_secid, .release_secctx = smack_release_secctx, }; diff --git a/security/smack/smackfs.c b/security/smack/smackfs.c index 15aa37f65b3..358c92c1a15 100644 --- a/security/smack/smackfs.c +++ b/security/smack/smackfs.c @@ -24,6 +24,7 @@ #include <net/cipso_ipv4.h> #include <linux/seq_file.h> #include <linux/ctype.h> +#include <linux/audit.h> #include "smack.h" /* @@ -45,6 +46,7 @@ enum smk_inos { */ static DEFINE_MUTEX(smack_list_lock); static DEFINE_MUTEX(smack_cipso_lock); +static DEFINE_MUTEX(smack_ambient_lock); /* * This is the "ambient" label for network traffic. @@ -342,6 +344,9 @@ void smk_cipso_doi(void) struct cipso_v4_doi *doip; struct netlbl_audit audit_info; + audit_info.loginuid = audit_get_loginuid(current); + audit_info.secid = smack_to_secid(current->security); + rc = netlbl_cfg_map_del(NULL, &audit_info); if (rc != 0) printk(KERN_WARNING "%s:%d remove rc = %d\n", @@ -363,6 +368,30 @@ void smk_cipso_doi(void) __func__, __LINE__, rc); } +/** + * smk_unlbl_ambient - initialize the unlabeled domain + */ +void smk_unlbl_ambient(char *oldambient) +{ + int rc; + struct netlbl_audit audit_info; + + audit_info.loginuid = audit_get_loginuid(current); + audit_info.secid = smack_to_secid(current->security); + + if (oldambient != NULL) { + rc = netlbl_cfg_map_del(oldambient, &audit_info); + if (rc != 0) + printk(KERN_WARNING "%s:%d remove rc = %d\n", + __func__, __LINE__, rc); + } + + rc = netlbl_cfg_unlbl_add_map(smack_net_ambient, &audit_info); + if (rc != 0) + printk(KERN_WARNING "%s:%d add rc = %d\n", + __func__, __LINE__, rc); +} + /* * Seq_file read operations for /smack/cipso */ @@ -709,7 +738,6 @@ static ssize_t smk_read_ambient(struct file *filp, char __user *buf, size_t cn, loff_t *ppos) { ssize_t rc; - char out[SMK_LABELLEN]; int asize; if (*ppos != 0) @@ -717,23 +745,18 @@ static ssize_t smk_read_ambient(struct file *filp, char __user *buf, /* * Being careful to avoid a problem in the case where * smack_net_ambient gets changed in midstream. - * Since smack_net_ambient is always set with a value - * from the label list, including initially, and those - * never get freed, the worst case is that the pointer - * gets changed just after this strncpy, in which case - * the value passed up is incorrect. Locking around - * smack_net_ambient wouldn't be any better than this - * copy scheme as by the time the caller got to look - * at the ambient value it would have cleared the lock - * and been changed. */ - strncpy(out, smack_net_ambient, SMK_LABELLEN); - asize = strlen(out) + 1; + mutex_lock(&smack_ambient_lock); - if (cn < asize) - return -EINVAL; + asize = strlen(smack_net_ambient) + 1; + + if (cn >= asize) + rc = simple_read_from_buffer(buf, cn, ppos, + smack_net_ambient, asize); + else + rc = -EINVAL; - rc = simple_read_from_buffer(buf, cn, ppos, out, asize); + mutex_unlock(&smack_ambient_lock); return rc; } @@ -751,6 +774,7 @@ static ssize_t smk_write_ambient(struct file *file, const char __user *buf, size_t count, loff_t *ppos) { char in[SMK_LABELLEN]; + char *oldambient; char *smack; if (!capable(CAP_MAC_ADMIN)) @@ -766,7 +790,13 @@ static ssize_t smk_write_ambient(struct file *file, const char __user *buf, if (smack == NULL) return -EINVAL; + mutex_lock(&smack_ambient_lock); + + oldambient = smack_net_ambient; smack_net_ambient = smack; + smk_unlbl_ambient(oldambient); + + mutex_unlock(&smack_ambient_lock); return count; } @@ -974,6 +1004,7 @@ static int __init init_smk_fs(void) sema_init(&smack_write_sem, 1); smk_cipso_doi(); + smk_unlbl_ambient(NULL); return err; } diff --git a/sound/core/seq/seq_clientmgr.c b/sound/core/seq/seq_clientmgr.c index f97c1ba43a2..47cfa5186e3 100644 --- a/sound/core/seq/seq_clientmgr.c +++ b/sound/core/seq/seq_clientmgr.c @@ -149,13 +149,13 @@ struct snd_seq_client *snd_seq_client_use_ptr(int clientid) } spin_unlock_irqrestore(&clients_lock, flags); #ifdef CONFIG_KMOD - if (!in_interrupt() && current->fs->root) { + if (!in_interrupt()) { static char client_requested[SNDRV_SEQ_GLOBAL_CLIENTS]; static char card_requested[SNDRV_CARDS]; if (clientid < SNDRV_SEQ_GLOBAL_CLIENTS) { int idx; - if (! client_requested[clientid] && current->fs->root) { + if (!client_requested[clientid]) { client_requested[clientid] = 1; for (idx = 0; idx < 15; idx++) { if (seq_client_load[idx] < 0) diff --git a/sound/core/seq/seq_device.c b/sound/core/seq/seq_device.c index 155dc7da472..2f00ad28a2b 100644 --- a/sound/core/seq/seq_device.c +++ b/sound/core/seq/seq_device.c @@ -149,9 +149,6 @@ void snd_seq_device_load_drivers(void) if (snd_seq_in_init) return; - if (! current->fs->root) - return; - mutex_lock(&ops_mutex); list_for_each_entry(ops, &opslist, list) { if (! (ops->driver & DRIVER_LOADED) && diff --git a/sound/core/sound.c b/sound/core/sound.c index 00cca4d6e56..812f91b3de5 100644 --- a/sound/core/sound.c +++ b/sound/core/sound.c @@ -71,8 +71,6 @@ static DEFINE_MUTEX(sound_mutex); */ void snd_request_card(int card) { - if (! current->fs->root) - return; if (snd_card_locked(card)) return; if (card < 0 || card >= cards_limit) @@ -86,8 +84,6 @@ static void snd_request_other(int minor) { char *str; - if (! current->fs->root) - return; switch (minor) { case SNDRV_MINOR_SEQUENCER: str = "snd-seq"; break; case SNDRV_MINOR_TIMER: str = "snd-timer"; break; diff --git a/sound/core/timer.c b/sound/core/timer.c index aece465934b..9d8184a2c2d 100644 --- a/sound/core/timer.c +++ b/sound/core/timer.c @@ -150,8 +150,6 @@ static struct snd_timer *snd_timer_find(struct snd_timer_id *tid) static void snd_timer_request(struct snd_timer_id *tid) { - if (! current->fs->root) - return; switch (tid->dev_class) { case SNDRV_TIMER_CLASS_GLOBAL: if (tid->device < timer_limit) diff --git a/sound/ppc/daca.c b/sound/ppc/daca.c index 8432c16cd6f..ca9452901a5 100644 --- a/sound/ppc/daca.c +++ b/sound/ppc/daca.c @@ -250,9 +250,8 @@ int __init snd_pmac_daca_init(struct snd_pmac *chip) struct pmac_daca *mix; #ifdef CONFIG_KMOD - if (current->fs->root) - request_module("i2c-powermac"); -#endif /* CONFIG_KMOD */ + request_module("i2c-powermac"); +#endif /* CONFIG_KMOD */ mix = kzalloc(sizeof(*mix), GFP_KERNEL); if (! mix) diff --git a/sound/ppc/tumbler.c b/sound/ppc/tumbler.c index 71a7a976542..3f8d7164cef 100644 --- a/sound/ppc/tumbler.c +++ b/sound/ppc/tumbler.c @@ -1351,9 +1351,8 @@ int __init snd_pmac_tumbler_init(struct snd_pmac *chip) char *chipname; #ifdef CONFIG_KMOD - if (current->fs->root) - request_module("i2c-powermac"); -#endif /* CONFIG_KMOD */ + request_module("i2c-powermac"); +#endif /* CONFIG_KMOD */ mix = kzalloc(sizeof(*mix), GFP_KERNEL); if (! mix) |