Merge branch 'mach_memory_h' of git://git.linaro.org/people/nico/linux into devel-stable
diff --git a/Documentation/DocBook/media/v4l/controls.xml b/Documentation/DocBook/media/v4l/controls.xml
index 8516401..23fdf79 100644
--- a/Documentation/DocBook/media/v4l/controls.xml
+++ b/Documentation/DocBook/media/v4l/controls.xml
@@ -1455,7 +1455,7 @@
</row>
<row><entry></entry></row>
- <row>
+ <row id="v4l2-mpeg-video-h264-vui-sar-idc">
<entry spanname="id"><constant>V4L2_CID_MPEG_VIDEO_H264_VUI_SAR_IDC</constant> </entry>
<entry>enum v4l2_mpeg_video_h264_vui_sar_idc</entry>
</row>
@@ -1561,7 +1561,7 @@
</row>
<row><entry></entry></row>
- <row>
+ <row id="v4l2-mpeg-video-h264-level">
<entry spanname="id"><constant>V4L2_CID_MPEG_VIDEO_H264_LEVEL</constant> </entry>
<entry>enum v4l2_mpeg_video_h264_level</entry>
</row>
@@ -1641,7 +1641,7 @@
</row>
<row><entry></entry></row>
- <row>
+ <row id="v4l2-mpeg-video-mpeg4-level">
<entry spanname="id"><constant>V4L2_CID_MPEG_VIDEO_MPEG4_LEVEL</constant> </entry>
<entry>enum v4l2_mpeg_video_mpeg4_level</entry>
</row>
@@ -1689,9 +1689,9 @@
</row>
<row><entry></entry></row>
- <row>
+ <row id="v4l2-mpeg-video-h264-profile">
<entry spanname="id"><constant>V4L2_CID_MPEG_VIDEO_H264_PROFILE</constant> </entry>
- <entry>enum v4l2_mpeg_h264_profile</entry>
+ <entry>enum v4l2_mpeg_video_h264_profile</entry>
</row>
<row><entry spanname="descr">The profile information for H264.
Applicable to the H264 encoder.
@@ -1774,9 +1774,9 @@
</row>
<row><entry></entry></row>
- <row>
+ <row id="v4l2-mpeg-video-mpeg4-profile">
<entry spanname="id"><constant>V4L2_CID_MPEG_VIDEO_MPEG4_PROFILE</constant> </entry>
- <entry>enum v4l2_mpeg_mpeg4_profile</entry>
+ <entry>enum v4l2_mpeg_video_mpeg4_profile</entry>
</row>
<row><entry spanname="descr">The profile information for MPEG4.
Applicable to the MPEG4 encoder.
@@ -1820,9 +1820,9 @@
</row>
<row><entry></entry></row>
- <row>
+ <row id="v4l2-mpeg-video-multi-slice-mode">
<entry spanname="id"><constant>V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MODE</constant> </entry>
- <entry>enum v4l2_mpeg_multi_slice_mode</entry>
+ <entry>enum v4l2_mpeg_video_multi_slice_mode</entry>
</row>
<row><entry spanname="descr">Determines how the encoder should handle division of frame into slices.
Applicable to the encoder.
@@ -1868,9 +1868,9 @@
</row>
<row><entry></entry></row>
- <row>
+ <row id="v4l2-mpeg-video-h264-loop-filter-mode">
<entry spanname="id"><constant>V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_MODE</constant> </entry>
- <entry>enum v4l2_mpeg_h264_loop_filter_mode</entry>
+ <entry>enum v4l2_mpeg_video_h264_loop_filter_mode</entry>
</row>
<row><entry spanname="descr">Loop filter mode for H264 encoder.
Possible values are:</entry>
@@ -1913,9 +1913,9 @@
</row>
<row><entry></entry></row>
- <row>
+ <row id="v4l2-mpeg-video-h264-entropy-mode">
<entry spanname="id"><constant>V4L2_CID_MPEG_VIDEO_H264_ENTROPY_MODE</constant> </entry>
- <entry>enum v4l2_mpeg_h264_symbol_mode</entry>
+ <entry>enum v4l2_mpeg_video_h264_entropy_mode</entry>
</row>
<row><entry spanname="descr">Entropy coding mode for H264 - CABAC/CAVALC.
Applicable to the H264 encoder.
@@ -2140,9 +2140,9 @@
</row>
<row><entry></entry></row>
- <row>
+ <row id="v4l2-mpeg-video-header-mode">
<entry spanname="id"><constant>V4L2_CID_MPEG_VIDEO_HEADER_MODE</constant> </entry>
- <entry>enum v4l2_mpeg_header_mode</entry>
+ <entry>enum v4l2_mpeg_video_header_mode</entry>
</row>
<row><entry spanname="descr">Determines whether the header is returned as the first buffer or is
it returned together with the first frame. Applicable to encoders.
@@ -2320,9 +2320,9 @@
Applicable to the H264 encoder.</entry>
</row>
<row><entry></entry></row>
- <row>
+ <row id="v4l2-mpeg-mfc51-video-frame-skip-mode">
<entry spanname="id"><constant>V4L2_CID_MPEG_MFC51_VIDEO_FRAME_SKIP_MODE</constant> </entry>
- <entry>enum v4l2_mpeg_mfc51_frame_skip_mode</entry>
+ <entry>enum v4l2_mpeg_mfc51_video_frame_skip_mode</entry>
</row>
<row><entry spanname="descr">
Indicates in what conditions the encoder should skip frames. If encoding a frame would cause the encoded stream to be larger then
@@ -2361,9 +2361,9 @@
</entry>
</row>
<row><entry></entry></row>
- <row>
+ <row id="v4l2-mpeg-mfc51-video-force-frame-type">
<entry spanname="id"><constant>V4L2_CID_MPEG_MFC51_VIDEO_FORCE_FRAME_TYPE</constant> </entry>
- <entry>enum v4l2_mpeg_mfc51_force_frame_type</entry>
+ <entry>enum v4l2_mpeg_mfc51_video_force_frame_type</entry>
</row>
<row><entry spanname="descr">Force a frame type for the next queued buffer. Applicable to encoders.
Possible values are:</entry>
diff --git a/Documentation/feature-removal-schedule.txt b/Documentation/feature-removal-schedule.txt
index c4a6e14..4dc4654 100644
--- a/Documentation/feature-removal-schedule.txt
+++ b/Documentation/feature-removal-schedule.txt
@@ -592,3 +592,11 @@
interface that was used by acer-wmi driver. It will replaced by
information log when acer-wmi initial.
Who: Lee, Chun-Yi <jlee@novell.com>
+
+----------------------------
+What: The XFS nodelaylog mount option
+When: 3.3
+Why: The delaylog mode that has been the default since 2.6.39 has proven
+ stable, and the old code is in the way of additional improvements in
+ the log code.
+Who: Christoph Hellwig <hch@lst.de>
diff --git a/Documentation/hwmon/max16065 b/Documentation/hwmon/max16065
index 44b4f61..c11f64a 100644
--- a/Documentation/hwmon/max16065
+++ b/Documentation/hwmon/max16065
@@ -62,6 +62,13 @@
the devices explicitly. Please see Documentation/i2c/instantiating-devices for
details.
+WARNING: Do not access chip registers using the i2cdump command, and do not use
+any of the i2ctools commands on a command register (0xa5 to 0xac). The chips
+supported by this driver interpret any access to a command register (including
+read commands) as request to execute the command in question. This may result in
+power loss, board resets, and/or Flash corruption. Worst case, your board may
+turn into a brick.
+
Sysfs entries
-------------
diff --git a/Documentation/ioctl/ioctl-number.txt b/Documentation/ioctl/ioctl-number.txt
index 845a191..54078ed 100644
--- a/Documentation/ioctl/ioctl-number.txt
+++ b/Documentation/ioctl/ioctl-number.txt
@@ -319,4 +319,6 @@
<mailto:thomas@winischhofer.net>
0xF4 00-1F video/mbxfb.h mbxfb
<mailto:raph@8d.com>
+0xF6 all LTTng Linux Trace Toolkit Next Generation
+ <mailto:mathieu.desnoyers@efficios.com>
0xFD all linux/dm-ioctl.h
diff --git a/Documentation/networking/00-INDEX b/Documentation/networking/00-INDEX
index 4edd78d..bbce121 100644
--- a/Documentation/networking/00-INDEX
+++ b/Documentation/networking/00-INDEX
@@ -1,13 +1,21 @@
00-INDEX
- this file
+3c359.txt
+ - information on the 3Com TokenLink Velocity XL (3c5359) driver.
3c505.txt
- information on the 3Com EtherLink Plus (3c505) driver.
+3c509.txt
+ - information on the 3Com Etherlink III Series Ethernet cards.
6pack.txt
- info on the 6pack protocol, an alternative to KISS for AX.25
DLINK.txt
- info on the D-Link DE-600/DE-620 parallel port pocket adapters
PLIP.txt
- PLIP: The Parallel Line Internet Protocol device driver
+README.ipw2100
+ - README for the Intel PRO/Wireless 2100 driver.
+README.ipw2200
+ - README for the Intel PRO/Wireless 2915ABG and 2200BG driver.
README.sb1000
- info on General Instrument/NextLevel SURFboard1000 cable modem.
alias.txt
@@ -20,8 +28,12 @@
- info on where to get ATM programs and support for Linux.
ax25.txt
- info on using AX.25 and NET/ROM code for Linux
+batman-adv.txt
+ - B.A.T.M.A.N routing protocol on top of layer 2 Ethernet Frames.
baycom.txt
- info on the driver for Baycom style amateur radio modems
+bonding.txt
+ - Linux Ethernet Bonding Driver HOWTO: link aggregation in Linux.
bridge.txt
- where to get user space programs for ethernet bridging with Linux.
can.txt
@@ -34,32 +46,60 @@
- Conexant AccessRunner USB ADSL Modem
cxacru-cf.py
- Conexant AccessRunner USB ADSL Modem configuration file parser
+cxgb.txt
+ - Release Notes for the Chelsio N210 Linux device driver.
+dccp.txt
+ - the Datagram Congestion Control Protocol (DCCP) (RFC 4340..42).
de4x5.txt
- the Digital EtherWORKS DE4?? and DE5?? PCI Ethernet driver
decnet.txt
- info on using the DECnet networking layer in Linux.
depca.txt
- the Digital DEPCA/EtherWORKS DE1?? and DE2?? LANCE Ethernet driver
+dl2k.txt
+ - README for D-Link DL2000-based Gigabit Ethernet Adapters (dl2k.ko).
+dm9000.txt
+ - README for the Simtec DM9000 Network driver.
dmfe.txt
- info on the Davicom DM9102(A)/DM9132/DM9801 fast ethernet driver.
+dns_resolver.txt
+ - The DNS resolver module allows kernel servies to make DNS queries.
+driver.txt
+ - Softnet driver issues.
e100.txt
- info on Intel's EtherExpress PRO/100 line of 10/100 boards
e1000.txt
- info on Intel's E1000 line of gigabit ethernet boards
+e1000e.txt
+ - README for the Intel Gigabit Ethernet Driver (e1000e).
eql.txt
- serial IP load balancing
ewrk3.txt
- the Digital EtherWORKS 3 DE203/4/5 Ethernet driver
+fib_trie.txt
+ - Level Compressed Trie (LC-trie) notes: a structure for routing.
filter.txt
- Linux Socket Filtering
fore200e.txt
- FORE Systems PCA-200E/SBA-200E ATM NIC driver info.
framerelay.txt
- info on using Frame Relay/Data Link Connection Identifier (DLCI).
+gen_stats.txt
+ - Generic networking statistics for netlink users.
+generic_hdlc.txt
+ - The generic High Level Data Link Control (HDLC) layer.
generic_netlink.txt
- info on Generic Netlink
+gianfar.txt
+ - Gianfar Ethernet Driver.
ieee802154.txt
- Linux IEEE 802.15.4 implementation, API and drivers
+ifenslave.c
+ - Configure network interfaces for parallel routing (bonding).
+igb.txt
+ - README for the Intel Gigabit Ethernet Driver (igb).
+igbvf.txt
+ - README for the Intel Gigabit Ethernet Driver (igbvf).
ip-sysctl.txt
- /proc/sys/net/ipv4/* variables
ip_dynaddr.txt
@@ -68,41 +108,117 @@
- AppleTalk-IP Decapsulation and AppleTalk-IP Encapsulation
iphase.txt
- Interphase PCI ATM (i)Chip IA Linux driver info.
+ipv6.txt
+ - Options to the ipv6 kernel module.
+ipvs-sysctl.txt
+ - Per-inode explanation of the /proc/sys/net/ipv4/vs interface.
irda.txt
- where to get IrDA (infrared) utilities and info for Linux.
+ixgb.txt
+ - README for the Intel 10 Gigabit Ethernet Driver (ixgb).
+ixgbe.txt
+ - README for the Intel 10 Gigabit Ethernet Driver (ixgbe).
+ixgbevf.txt
+ - README for the Intel Virtual Function (VF) Driver (ixgbevf).
+l2tp.txt
+ - User guide to the L2TP tunnel protocol.
lapb-module.txt
- programming information of the LAPB module.
ltpc.txt
- the Apple or Farallon LocalTalk PC card driver
+mac80211-injection.txt
+ - HOWTO use packet injection with mac80211
multicast.txt
- Behaviour of cards under Multicast
+multiqueue.txt
+ - HOWTO for multiqueue network device support.
+netconsole.txt
+ - The network console module netconsole.ko: configuration and notes.
+netdev-features.txt
+ - Network interface features API description.
netdevices.txt
- info on network device driver functions exported to the kernel.
+netif-msg.txt
+ - Design of the network interface message level setting (NETIF_MSG_*).
+nfc.txt
+ - The Linux Near Field Communication (NFS) subsystem.
olympic.txt
- IBM PCI Pit/Pit-Phy/Olympic Token Ring driver info.
+operstates.txt
+ - Overview of network interface operational states.
+packet_mmap.txt
+ - User guide to memory mapped packet socket rings (PACKET_[RT]X_RING).
+phonet.txt
+ - The Phonet packet protocol used in Nokia cellular modems.
+phy.txt
+ - The PHY abstraction layer.
+pktgen.txt
+ - User guide to the kernel packet generator (pktgen.ko).
policy-routing.txt
- IP policy-based routing
+ppp_generic.txt
+ - Information about the generic PPP driver.
+proc_net_tcp.txt
+ - Per inode overview of the /proc/net/tcp and /proc/net/tcp6 interfaces.
+radiotap-headers.txt
+ - Background on radiotap headers.
ray_cs.txt
- Raylink Wireless LAN card driver info.
+rds.txt
+ - Background on the reliable, ordered datagram delivery method RDS.
+regulatory.txt
+ - Overview of the Linux wireless regulatory infrastructure.
+rxrpc.txt
+ - Guide to the RxRPC protocol.
+s2io.txt
+ - Release notes for Neterion Xframe I/II 10GbE driver.
+scaling.txt
+ - Explanation of network scaling techniques: RSS, RPS, RFS, aRFS, XPS.
+sctp.txt
+ - Notes on the Linux kernel implementation of the SCTP protocol.
+secid.txt
+ - Explanation of the secid member in flow structures.
skfp.txt
- SysKonnect FDDI (SK-5xxx, Compaq Netelligent) driver info.
smc9.txt
- the driver for SMC's 9000 series of Ethernet cards
smctr.txt
- SMC TokenCard TokenRing Linux driver info.
+spider-net.txt
+ - README for the Spidernet Driver (as found in PS3 / Cell BE).
+stmmac.txt
+ - README for the STMicro Synopsys Ethernet driver.
+tc-actions-env-rules.txt
+ - rules for traffic control (tc) actions.
+timestamping.txt
+ - overview of network packet timestamping variants.
tcp.txt
- short blurb on how TCP output takes place.
+tcp-thin.txt
+ - kernel tuning options for low rate 'thin' TCP streams.
tlan.txt
- ThunderLAN (Compaq Netelligent 10/100, Olicom OC-2xxx) driver info.
tms380tr.txt
- SysKonnect Token Ring ISA/PCI adapter driver info.
+tproxy.txt
+ - Transparent proxy support user guide.
tuntap.txt
- TUN/TAP device driver, allowing user space Rx/Tx of packets.
+udplite.txt
+ - UDP-Lite protocol (RFC 3828) introduction.
vortex.txt
- info on using 3Com Vortex (3c590, 3c592, 3c595, 3c597) Ethernet cards.
+vxge.txt
+ - README for the Neterion X3100 PCIe Server Adapter.
x25.txt
- general info on X.25 development.
x25-iface.txt
- description of the X.25 Packet Layer to LAPB device interface.
+xfrm_proc.txt
+ - description of the statistics package for XFRM.
+xfrm_sync.txt
+ - sync patches for XFRM enable migration of an SA between hosts.
+xfrm_sysctl.txt
+ - description of the XFRM configuration options.
z8530drv.txt
- info about Linux driver for Z8530 based HDLC cards for AX.25
diff --git a/Documentation/networking/ip-sysctl.txt b/Documentation/networking/ip-sysctl.txt
index db2a406..8154699 100644
--- a/Documentation/networking/ip-sysctl.txt
+++ b/Documentation/networking/ip-sysctl.txt
@@ -992,7 +992,7 @@
TRUE: disable IPv4-mapped address feature
FALSE: enable IPv4-mapped address feature
- Default: FALSE (as specified in RFC2553bis)
+ Default: FALSE (as specified in RFC3493)
IPv6 Fragmentation:
diff --git a/Documentation/networking/scaling.txt b/Documentation/networking/scaling.txt
index 7254b4b..58fd741 100644
--- a/Documentation/networking/scaling.txt
+++ b/Documentation/networking/scaling.txt
@@ -52,7 +52,8 @@
configure. In the bnx2x driver, for instance, this parameter is called
num_queues. A typical RSS configuration would be to have one receive queue
for each CPU if the device supports enough queues, or otherwise at least
-one for each cache domain at a particular cache level (L1, L2, etc.).
+one for each memory domain, where a memory domain is a set of CPUs that
+share a particular memory level (L1, L2, NUMA node, etc.).
The indirection table of an RSS device, which resolves a queue by masked
hash, is usually programmed by the driver at initialization. The
@@ -82,11 +83,17 @@
interrupt processing forms a bottleneck. Spreading load between CPUs
decreases queue length. For low latency networking, the optimal setting
is to allocate as many queues as there are CPUs in the system (or the
-NIC maximum, if lower). Because the aggregate number of interrupts grows
-with each additional queue, the most efficient high-rate configuration
+NIC maximum, if lower). The most efficient high-rate configuration
is likely the one with the smallest number of receive queues where no
-CPU that processes receive interrupts reaches 100% utilization. Per-cpu
-load can be observed using the mpstat utility.
+receive queue overflows due to a saturated CPU, because in default
+mode with interrupt coalescing enabled, the aggregate number of
+interrupts (and thus work) grows with each additional queue.
+
+Per-cpu load can be observed using the mpstat utility, but note that on
+processors with hyperthreading (HT), each hyperthread is represented as
+a separate CPU. For interrupt handling, HT has shown no benefit in
+initial tests, so limit the number of queues to the number of CPU cores
+in the system.
RPS: Receive Packet Steering
@@ -145,7 +152,7 @@
== Suggested Configuration
For a single queue device, a typical RPS configuration would be to set
-the rps_cpus to the CPUs in the same cache domain of the interrupting
+the rps_cpus to the CPUs in the same memory domain of the interrupting
CPU. If NUMA locality is not an issue, this could also be all CPUs in
the system. At high interrupt rate, it might be wise to exclude the
interrupting CPU from the map since that already performs much work.
@@ -154,7 +161,7 @@
receive queue is mapped to each CPU, then RPS is probably redundant
and unnecessary. If there are fewer hardware queues than CPUs, then
RPS might be beneficial if the rps_cpus for each queue are the ones that
-share the same cache domain as the interrupting CPU for that queue.
+share the same memory domain as the interrupting CPU for that queue.
RFS: Receive Flow Steering
@@ -326,7 +333,7 @@
corresponding socket structure for the flow (e.g. a TCP connection).
This transmit queue is used for subsequent packets sent on the flow to
prevent out of order (ooo) packets. The choice also amortizes the cost
-of calling get_xps_queues() over all packets in the connection. To avoid
+of calling get_xps_queues() over all packets in the flow. To avoid
ooo packets, the queue for a flow can subsequently only be changed if
skb->ooo_okay is set for a packet in the flow. This flag indicates that
there are no outstanding packets in the flow, so the transmit queue can
diff --git a/Documentation/power/runtime_pm.txt b/Documentation/power/runtime_pm.txt
index 4ce5450..6066e3a 100644
--- a/Documentation/power/runtime_pm.txt
+++ b/Documentation/power/runtime_pm.txt
@@ -431,8 +431,7 @@
void pm_runtime_irq_safe(struct device *dev);
- set the power.irq_safe flag for the device, causing the runtime-PM
- suspend and resume callbacks (but not the idle callback) to be invoked
- with interrupts disabled
+ callbacks to be invoked with interrupts off
void pm_runtime_mark_last_busy(struct device *dev);
- set the power.last_busy field to the current time
diff --git a/MAINTAINERS b/MAINTAINERS
index 069ee3b..28f65c2 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -1883,7 +1883,7 @@
F: drivers/connector/
CONTROL GROUPS (CGROUPS)
-M: Paul Menage <menage@google.com>
+M: Paul Menage <paul@paulmenage.org>
M: Li Zefan <lizf@cn.fujitsu.com>
L: containers@lists.linux-foundation.org
S: Maintained
@@ -1932,7 +1932,7 @@
F: tools/power/cpupower
CPUSETS
-M: Paul Menage <menage@google.com>
+M: Paul Menage <paul@paulmenage.org>
W: http://www.bullopensource.org/cpuset/
W: http://oss.sgi.com/projects/cpusets/
S: Supported
@@ -2649,11 +2649,11 @@
F: drivers/net/wan/sdla.c
FRAMEBUFFER LAYER
-M: Paul Mundt <lethal@linux-sh.org>
+M: Florian Tobias Schandinat <FlorianSchandinat@gmx.de>
L: linux-fbdev@vger.kernel.org
W: http://linux-fbdev.sourceforge.net/
Q: http://patchwork.kernel.org/project/linux-fbdev/list/
-T: git git://git.kernel.org/pub/scm/linux/kernel/git/lethal/fbdev-2.6.git
+T: git git://github.com/schandinat/linux-2.6.git fbdev-next
S: Maintained
F: Documentation/fb/
F: Documentation/devicetree/bindings/fb/
@@ -4450,8 +4450,8 @@
L: netdev@vger.kernel.org
W: http://www.linuxfoundation.org/en/Net
W: http://patchwork.ozlabs.org/project/netdev/list/
-T: git git://git.kernel.org/pub/scm/linux/kernel/git/davem/net-2.6.git
-T: git git://git.kernel.org/pub/scm/linux/kernel/git/davem/net-next-2.6.git
+T: git git://git.kernel.org/pub/scm/linux/kernel/git/davem/net.git
+T: git git://git.kernel.org/pub/scm/linux/kernel/git/davem/net-next.git
S: Maintained
F: net/
F: include/net/
@@ -5532,6 +5532,7 @@
SAMSUNG AUDIO (ASoC) DRIVERS
M: Jassi Brar <jassisinghbrar@gmail.com>
+M: Sangbeom Kim <sbkim73@samsung.com>
L: alsa-devel@alsa-project.org (moderated for non-subscribers)
S: Supported
F: sound/soc/samsung
@@ -7087,7 +7088,7 @@
F: drivers/mmc/host/vub300.c
W1 DALLAS'S 1-WIRE BUS
-M: Evgeniy Polyakov <johnpol@2ka.mipt.ru>
+M: Evgeniy Polyakov <zbr@ioremap.net>
S: Maintained
F: Documentation/w1/
F: drivers/w1/
diff --git a/Makefile b/Makefile
index 788511f..522fa47 100644
--- a/Makefile
+++ b/Makefile
@@ -1,7 +1,7 @@
VERSION = 3
PATCHLEVEL = 1
SUBLEVEL = 0
-EXTRAVERSION = -rc3
+EXTRAVERSION = -rc6
NAME = "Divemaster Edition"
# *DOCUMENTATION*
diff --git a/arch/alpha/include/asm/sysinfo.h b/arch/alpha/include/asm/sysinfo.h
index 086aba2..e77d77c 100644
--- a/arch/alpha/include/asm/sysinfo.h
+++ b/arch/alpha/include/asm/sysinfo.h
@@ -27,13 +27,4 @@
#define UAC_NOFIX 2
#define UAC_SIGBUS 4
-
-#ifdef __KERNEL__
-
-/* This is the shift that is applied to the UAC bits as stored in the
- per-thread flags. See thread_info.h. */
-#define UAC_SHIFT 6
-
-#endif
-
#endif /* __ASM_ALPHA_SYSINFO_H */
diff --git a/arch/alpha/include/asm/thread_info.h b/arch/alpha/include/asm/thread_info.h
index 6f32f9c..ff73db0 100644
--- a/arch/alpha/include/asm/thread_info.h
+++ b/arch/alpha/include/asm/thread_info.h
@@ -74,9 +74,9 @@
#define TIF_NEED_RESCHED 3 /* rescheduling necessary */
#define TIF_POLLING_NRFLAG 8 /* poll_idle is polling NEED_RESCHED */
#define TIF_DIE_IF_KERNEL 9 /* dik recursion lock */
-#define TIF_UAC_NOPRINT 10 /* see sysinfo.h */
-#define TIF_UAC_NOFIX 11
-#define TIF_UAC_SIGBUS 12
+#define TIF_UAC_NOPRINT 10 /* ! Preserve sequence of following */
+#define TIF_UAC_NOFIX 11 /* ! flags as they match */
+#define TIF_UAC_SIGBUS 12 /* ! userspace part of 'osf_sysinfo' */
#define TIF_MEMDIE 13 /* is terminating due to OOM killer */
#define TIF_RESTORE_SIGMASK 14 /* restore signal mask in do_signal */
#define TIF_FREEZE 16 /* is freezing for suspend */
@@ -97,7 +97,7 @@
#define _TIF_ALLWORK_MASK (_TIF_WORK_MASK \
| _TIF_SYSCALL_TRACE)
-#define ALPHA_UAC_SHIFT 10
+#define ALPHA_UAC_SHIFT TIF_UAC_NOPRINT
#define ALPHA_UAC_MASK (1 << TIF_UAC_NOPRINT | 1 << TIF_UAC_NOFIX | \
1 << TIF_UAC_SIGBUS)
diff --git a/arch/alpha/kernel/osf_sys.c b/arch/alpha/kernel/osf_sys.c
index 326f0a2..01e8715 100644
--- a/arch/alpha/kernel/osf_sys.c
+++ b/arch/alpha/kernel/osf_sys.c
@@ -42,6 +42,7 @@
#include <asm/uaccess.h>
#include <asm/system.h>
#include <asm/sysinfo.h>
+#include <asm/thread_info.h>
#include <asm/hwrpb.h>
#include <asm/processor.h>
@@ -633,9 +634,10 @@
case GSI_UACPROC:
if (nbytes < sizeof(unsigned int))
return -EINVAL;
- w = (current_thread_info()->flags >> UAC_SHIFT) & UAC_BITMASK;
- if (put_user(w, (unsigned int __user *)buffer))
- return -EFAULT;
+ w = (current_thread_info()->flags >> ALPHA_UAC_SHIFT) &
+ UAC_BITMASK;
+ if (put_user(w, (unsigned int __user *)buffer))
+ return -EFAULT;
return 1;
case GSI_PROC_TYPE:
@@ -756,8 +758,8 @@
case SSIN_UACPROC:
again:
old = current_thread_info()->flags;
- new = old & ~(UAC_BITMASK << UAC_SHIFT);
- new = new | (w & UAC_BITMASK) << UAC_SHIFT;
+ new = old & ~(UAC_BITMASK << ALPHA_UAC_SHIFT);
+ new = new | (w & UAC_BITMASK) << ALPHA_UAC_SHIFT;
if (cmpxchg(¤t_thread_info()->flags,
old, new) != old)
goto again;
diff --git a/arch/alpha/kernel/systbls.S b/arch/alpha/kernel/systbls.S
index b9c28f3..6acea1f 100644
--- a/arch/alpha/kernel/systbls.S
+++ b/arch/alpha/kernel/systbls.S
@@ -360,7 +360,7 @@
.quad sys_newuname
.quad sys_nanosleep /* 340 */
.quad sys_mremap
- .quad sys_nfsservctl
+ .quad sys_ni_syscall /* old nfsservctl */
.quad sys_setresuid
.quad sys_getresuid
.quad sys_pciconfig_read /* 345 */
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index b7f7510..c8d5ec8 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -29,6 +29,7 @@
select HAVE_GENERIC_HARDIRQS
select HAVE_SPARSE_IRQ
select GENERIC_IRQ_SHOW
+ select CPU_PM if (SUSPEND || CPU_IDLE)
help
The ARM series is a line of low-power-consumption RISC chip designs
licensed by ARM Ltd and targeted at embedded applications and
@@ -1297,6 +1298,18 @@
This workaround defines cpu_relax() as smp_mb(), preventing correctly
written polling loops from denying visibility of updates to memory.
+config ARM_ERRATA_364296
+ bool "ARM errata: Possible cache data corruption with hit-under-miss enabled"
+ depends on CPU_V6 && !SMP
+ help
+ This options enables the workaround for the 364296 ARM1136
+ r0p2 erratum (possible cache data corruption with
+ hit-under-miss enabled). It sets the undocumented bit 31 in
+ the auxiliary control register and the FI bit in the control
+ register, thus disabling hit-under-miss without putting the
+ processor into full low interrupt latency mode. ARM11MPCore
+ is not affected.
+
endmenu
source "arch/arm/common/Kconfig"
@@ -1807,6 +1820,38 @@
endchoice
+config ARM_APPENDED_DTB
+ bool "Use appended device tree blob to zImage (EXPERIMENTAL)"
+ depends on OF && !ZBOOT_ROM && EXPERIMENTAL
+ help
+ With this option, the boot code will look for a device tree binary
+ (DTB) appended to zImage
+ (e.g. cat zImage <filename>.dtb > zImage_w_dtb).
+
+ This is meant as a backward compatibility convenience for those
+ systems with a bootloader that can't be upgraded to accommodate
+ the documented boot protocol using a device tree.
+
+ Beware that there is very little in terms of protection against
+ this option being confused by leftover garbage in memory that might
+ look like a DTB header after a reboot if no actual DTB is appended
+ to zImage. Do not leave this option active in a production kernel
+ if you don't intend to always append a DTB. Proper passing of the
+ location into r2 of a bootloader provided DTB is always preferable
+ to this option.
+
+config ARM_ATAG_DTB_COMPAT
+ bool "Supplement the appended DTB with traditional ATAG information"
+ depends on ARM_APPENDED_DTB
+ help
+ Some old bootloaders can't be updated to a DTB capable one, yet
+ they provide ATAGs with memory configuration, the ramdisk address,
+ the kernel cmdline string, etc. Such information is dynamically
+ provided by the bootloader and can't always be stored in a static
+ DTB. To allow a device tree enabled kernel to be used with such
+ bootloaders, this option allows zImage to extract the information
+ from the ATAG list and store it at run time into the appended DTB.
+
config CMDLINE
string "Default kernel command string"
default ""
diff --git a/arch/arm/Kconfig.debug b/arch/arm/Kconfig.debug
index 81cbe40..be3a0f7 100644
--- a/arch/arm/Kconfig.debug
+++ b/arch/arm/Kconfig.debug
@@ -129,4 +129,10 @@
The uncompressor code port configuration is now handled
by CONFIG_S3C_LOWLEVEL_UART_PORT.
+config ARM_KPROBES_TEST
+ tristate "Kprobes test module"
+ depends on KPROBES && MODULES
+ help
+ Perform tests of kprobes API and instruction set simulation.
+
endmenu
diff --git a/arch/arm/boot/compressed/.gitignore b/arch/arm/boot/compressed/.gitignore
index c602896..e0936a1 100644
--- a/arch/arm/boot/compressed/.gitignore
+++ b/arch/arm/boot/compressed/.gitignore
@@ -5,3 +5,12 @@
piggy.lzma
vmlinux
vmlinux.lds
+
+# borrowed libfdt files
+fdt.c
+fdt.h
+fdt_ro.c
+fdt_rw.c
+fdt_wip.c
+libfdt.h
+libfdt_internal.h
diff --git a/arch/arm/boot/compressed/Makefile b/arch/arm/boot/compressed/Makefile
index 0c74a6f..e4f32a8 100644
--- a/arch/arm/boot/compressed/Makefile
+++ b/arch/arm/boot/compressed/Makefile
@@ -26,6 +26,10 @@
OBJS += misc.o decompress.o
FONTC = $(srctree)/drivers/video/console/font_acorn_8x8.c
+# string library code (-Os is enforced to keep it much smaller)
+OBJS += string.o
+CFLAGS_string.o := -Os
+
#
# Architecture dependencies
#
@@ -89,21 +93,41 @@
suffix_$(CONFIG_KERNEL_LZO) = lzo
suffix_$(CONFIG_KERNEL_LZMA) = lzma
+# Borrowed libfdt files for the ATAG compatibility mode
+
+libfdt := fdt_rw.c fdt_ro.c fdt_wip.c fdt.c
+libfdt_hdrs := fdt.h libfdt.h libfdt_internal.h
+
+libfdt_objs := $(addsuffix .o, $(basename $(libfdt)))
+
+$(addprefix $(obj)/,$(libfdt) $(libfdt_hdrs)): $(obj)/%: $(srctree)/scripts/dtc/libfdt/%
+ $(call cmd,shipped)
+
+$(addprefix $(obj)/,$(libfdt_objs) atags_to_fdt.o): \
+ $(addprefix $(obj)/,$(libfdt_hdrs))
+
+ifeq ($(CONFIG_ARM_ATAG_DTB_COMPAT),y)
+OBJS += $(libfdt_objs) atags_to_fdt.o
+endif
+
targets := vmlinux vmlinux.lds \
piggy.$(suffix_y) piggy.$(suffix_y).o \
- font.o font.c head.o misc.o $(OBJS)
+ lib1funcs.o lib1funcs.S font.o font.c head.o misc.o $(OBJS)
# Make sure files are removed during clean
-extra-y += piggy.gzip piggy.lzo piggy.lzma lib1funcs.S
+extra-y += piggy.gzip piggy.lzo piggy.lzma lib1funcs.S $(libfdt) $(libfdt_hdrs)
ifeq ($(CONFIG_FUNCTION_TRACER),y)
ORIG_CFLAGS := $(KBUILD_CFLAGS)
KBUILD_CFLAGS = $(subst -pg, , $(ORIG_CFLAGS))
endif
-ccflags-y := -fpic -fno-builtin
+ccflags-y := -fpic -fno-builtin -I$(obj)
asflags-y := -Wa,-march=all
+# Supply kernel BSS size to the decompressor via a linker symbol.
+KBSS_SZ = $(shell size $(obj)/../../../../vmlinux | awk 'END{print $$3}')
+LDFLAGS_vmlinux = --defsym _kernel_bss_size=$(KBSS_SZ)
# Supply ZRELADDR to the decompressor via a linker symbol.
ifneq ($(CONFIG_AUTO_ZRELADDR),y)
LDFLAGS_vmlinux += --defsym zreladdr=$(ZRELADDR)
@@ -123,7 +147,7 @@
# For __aeabi_uidivmod
lib1funcs = $(obj)/lib1funcs.o
-$(obj)/lib1funcs.S: $(srctree)/arch/$(SRCARCH)/lib/lib1funcs.S FORCE
+$(obj)/lib1funcs.S: $(srctree)/arch/$(SRCARCH)/lib/lib1funcs.S
$(call cmd,shipped)
# We need to prevent any GOTOFF relocs being used with references
diff --git a/arch/arm/boot/compressed/atags_to_fdt.c b/arch/arm/boot/compressed/atags_to_fdt.c
new file mode 100644
index 0000000..6ce11c4
--- /dev/null
+++ b/arch/arm/boot/compressed/atags_to_fdt.c
@@ -0,0 +1,97 @@
+#include <asm/setup.h>
+#include <libfdt.h>
+
+static int node_offset(void *fdt, const char *node_path)
+{
+ int offset = fdt_path_offset(fdt, node_path);
+ if (offset == -FDT_ERR_NOTFOUND)
+ offset = fdt_add_subnode(fdt, 0, node_path);
+ return offset;
+}
+
+static int setprop(void *fdt, const char *node_path, const char *property,
+ uint32_t *val_array, int size)
+{
+ int offset = node_offset(fdt, node_path);
+ if (offset < 0)
+ return offset;
+ return fdt_setprop(fdt, offset, property, val_array, size);
+}
+
+static int setprop_string(void *fdt, const char *node_path,
+ const char *property, const char *string)
+{
+ int offset = node_offset(fdt, node_path);
+ if (offset < 0)
+ return offset;
+ return fdt_setprop_string(fdt, offset, property, string);
+}
+
+static int setprop_cell(void *fdt, const char *node_path,
+ const char *property, uint32_t val)
+{
+ int offset = node_offset(fdt, node_path);
+ if (offset < 0)
+ return offset;
+ return fdt_setprop_cell(fdt, offset, property, val);
+}
+
+/*
+ * Convert and fold provided ATAGs into the provided FDT.
+ *
+ * REturn values:
+ * = 0 -> pretend success
+ * = 1 -> bad ATAG (may retry with another possible ATAG pointer)
+ * < 0 -> error from libfdt
+ */
+int atags_to_fdt(void *atag_list, void *fdt, int total_space)
+{
+ struct tag *atag = atag_list;
+ uint32_t mem_reg_property[2 * NR_BANKS];
+ int memcount = 0;
+ int ret;
+
+ /* make sure we've got an aligned pointer */
+ if ((u32)atag_list & 0x3)
+ return 1;
+
+ /* if we get a DTB here we're done already */
+ if (*(u32 *)atag_list == fdt32_to_cpu(FDT_MAGIC))
+ return 0;
+
+ /* validate the ATAG */
+ if (atag->hdr.tag != ATAG_CORE ||
+ (atag->hdr.size != tag_size(tag_core) &&
+ atag->hdr.size != 2))
+ return 1;
+
+ /* let's give it all the room it could need */
+ ret = fdt_open_into(fdt, fdt, total_space);
+ if (ret < 0)
+ return ret;
+
+ for_each_tag(atag, atag_list) {
+ if (atag->hdr.tag == ATAG_CMDLINE) {
+ setprop_string(fdt, "/chosen", "bootargs",
+ atag->u.cmdline.cmdline);
+ } else if (atag->hdr.tag == ATAG_MEM) {
+ if (memcount >= sizeof(mem_reg_property)/4)
+ continue;
+ mem_reg_property[memcount++] = cpu_to_fdt32(atag->u.mem.start);
+ mem_reg_property[memcount++] = cpu_to_fdt32(atag->u.mem.size);
+ } else if (atag->hdr.tag == ATAG_INITRD2) {
+ uint32_t initrd_start, initrd_size;
+ initrd_start = atag->u.initrd.start;
+ initrd_size = atag->u.initrd.size;
+ setprop_cell(fdt, "/chosen", "linux,initrd-start",
+ initrd_start);
+ setprop_cell(fdt, "/chosen", "linux,initrd-end",
+ initrd_start + initrd_size);
+ }
+ }
+
+ if (memcount)
+ setprop(fdt, "/memory", "reg", mem_reg_property, 4*memcount);
+
+ return fdt_pack(fdt);
+}
diff --git a/arch/arm/boot/compressed/head.S b/arch/arm/boot/compressed/head.S
index e95a598..9f5ac11 100644
--- a/arch/arm/boot/compressed/head.S
+++ b/arch/arm/boot/compressed/head.S
@@ -216,6 +216,103 @@
mov r10, r6
#endif
+ mov r5, #0 @ init dtb size to 0
+#ifdef CONFIG_ARM_APPENDED_DTB
+/*
+ * r0 = delta
+ * r2 = BSS start
+ * r3 = BSS end
+ * r4 = final kernel address
+ * r5 = appended dtb size (still unknown)
+ * r6 = _edata
+ * r7 = architecture ID
+ * r8 = atags/device tree pointer
+ * r9 = size of decompressed image
+ * r10 = end of this image, including bss/stack/malloc space if non XIP
+ * r11 = GOT start
+ * r12 = GOT end
+ * sp = stack pointer
+ *
+ * if there are device trees (dtb) appended to zImage, advance r10 so that the
+ * dtb data will get relocated along with the kernel if necessary.
+ */
+
+ ldr lr, [r6, #0]
+#ifndef __ARMEB__
+ ldr r1, =0xedfe0dd0 @ sig is 0xd00dfeed big endian
+#else
+ ldr r1, =0xd00dfeed
+#endif
+ cmp lr, r1
+ bne dtb_check_done @ not found
+
+#ifdef CONFIG_ARM_ATAG_DTB_COMPAT
+ /*
+ * OK... Let's do some funky business here.
+ * If we do have a DTB appended to zImage, and we do have
+ * an ATAG list around, we want the later to be translated
+ * and folded into the former here. To be on the safe side,
+ * let's temporarily move the stack away into the malloc
+ * area. No GOT fixup has occurred yet, but none of the
+ * code we're about to call uses any global variable.
+ */
+ add sp, sp, #0x10000
+ stmfd sp!, {r0-r3, ip, lr}
+ mov r0, r8
+ mov r1, r6
+ sub r2, sp, r6
+ bl atags_to_fdt
+
+ /*
+ * If returned value is 1, there is no ATAG at the location
+ * pointed by r8. Try the typical 0x100 offset from start
+ * of RAM and hope for the best.
+ */
+ cmp r0, #1
+ sub r0, r4, #(TEXT_OFFSET - 0x100)
+ mov r1, r6
+ sub r2, sp, r6
+ blne atags_to_fdt
+
+ ldmfd sp!, {r0-r3, ip, lr}
+ sub sp, sp, #0x10000
+#endif
+
+ mov r8, r6 @ use the appended device tree
+
+ /*
+ * Make sure that the DTB doesn't end up in the final
+ * kernel's .bss area. To do so, we adjust the decompressed
+ * kernel size to compensate if that .bss size is larger
+ * than the relocated code.
+ */
+ ldr r5, =_kernel_bss_size
+ adr r1, wont_overwrite
+ sub r1, r6, r1
+ subs r1, r5, r1
+ addhi r9, r9, r1
+
+ /* Get the dtb's size */
+ ldr r5, [r6, #4]
+#ifndef __ARMEB__
+ /* convert r5 (dtb size) to little endian */
+ eor r1, r5, r5, ror #16
+ bic r1, r1, #0x00ff0000
+ mov r5, r5, ror #8
+ eor r5, r5, r1, lsr #8
+#endif
+
+ /* preserve 64-bit alignment */
+ add r5, r5, #7
+ bic r5, r5, #7
+
+ /* relocate some pointers past the appended dtb */
+ add r6, r6, r5
+ add r10, r10, r5
+ add sp, sp, r5
+dtb_check_done:
+#endif
+
/*
* Check to see if we will overwrite ourselves.
* r4 = final kernel address
@@ -223,15 +320,14 @@
* r10 = end of this image, including bss/stack/malloc space if non XIP
* We basically want:
* r4 - 16k page directory >= r10 -> OK
- * r4 + image length <= current position (pc) -> OK
+ * r4 + image length <= address of wont_overwrite -> OK
*/
add r10, r10, #16384
cmp r4, r10
bhs wont_overwrite
add r10, r4, r9
- ARM( cmp r10, pc )
- THUMB( mov lr, pc )
- THUMB( cmp r10, lr )
+ adr r9, wont_overwrite
+ cmp r10, r9
bls wont_overwrite
/*
@@ -285,14 +381,16 @@
* r2 = BSS start
* r3 = BSS end
* r4 = kernel execution address
+ * r5 = appended dtb size (0 if not present)
* r7 = architecture ID
* r8 = atags pointer
* r11 = GOT start
* r12 = GOT end
* sp = stack pointer
*/
- teq r0, #0
+ orrs r1, r0, r5
beq not_relocated
+
add r11, r11, r0
add r12, r12, r0
@@ -307,12 +405,21 @@
/*
* Relocate all entries in the GOT table.
+ * Bump bss entries to _edata + dtb size
*/
1: ldr r1, [r11, #0] @ relocate entries in the GOT
- add r1, r1, r0 @ table. This fixes up the
- str r1, [r11], #4 @ C references.
+ add r1, r1, r0 @ This fixes up C references
+ cmp r1, r2 @ if entry >= bss_start &&
+ cmphs r3, r1 @ bss_end > entry
+ addhi r1, r1, r5 @ entry += dtb size
+ str r1, [r11], #4 @ next entry
cmp r11, r12
blo 1b
+
+ /* bump our bss pointers too */
+ add r2, r2, r5
+ add r3, r3, r5
+
#else
/*
diff --git a/arch/arm/boot/compressed/libfdt_env.h b/arch/arm/boot/compressed/libfdt_env.h
new file mode 100644
index 0000000..1f4e718
--- /dev/null
+++ b/arch/arm/boot/compressed/libfdt_env.h
@@ -0,0 +1,15 @@
+#ifndef _ARM_LIBFDT_ENV_H
+#define _ARM_LIBFDT_ENV_H
+
+#include <linux/types.h>
+#include <linux/string.h>
+#include <asm/byteorder.h>
+
+#define fdt16_to_cpu(x) be16_to_cpu(x)
+#define cpu_to_fdt16(x) cpu_to_be16(x)
+#define fdt32_to_cpu(x) be32_to_cpu(x)
+#define cpu_to_fdt32(x) cpu_to_be32(x)
+#define fdt64_to_cpu(x) be64_to_cpu(x)
+#define cpu_to_fdt64(x) cpu_to_be64(x)
+
+#endif
diff --git a/arch/arm/boot/compressed/misc.c b/arch/arm/boot/compressed/misc.c
index 832d372..8e2a8fc 100644
--- a/arch/arm/boot/compressed/misc.c
+++ b/arch/arm/boot/compressed/misc.c
@@ -18,14 +18,9 @@
unsigned int __machine_arch_type;
-#define _LINUX_STRING_H_
-
#include <linux/compiler.h> /* for inline */
-#include <linux/types.h> /* for size_t */
-#include <linux/stddef.h> /* for NULL */
+#include <linux/types.h>
#include <linux/linkage.h>
-#include <asm/string.h>
-
static void putstr(const char *ptr);
extern void error(char *x);
@@ -101,41 +96,6 @@
flush();
}
-
-void *memcpy(void *__dest, __const void *__src, size_t __n)
-{
- int i = 0;
- unsigned char *d = (unsigned char *)__dest, *s = (unsigned char *)__src;
-
- for (i = __n >> 3; i > 0; i--) {
- *d++ = *s++;
- *d++ = *s++;
- *d++ = *s++;
- *d++ = *s++;
- *d++ = *s++;
- *d++ = *s++;
- *d++ = *s++;
- *d++ = *s++;
- }
-
- if (__n & 1 << 2) {
- *d++ = *s++;
- *d++ = *s++;
- *d++ = *s++;
- *d++ = *s++;
- }
-
- if (__n & 1 << 1) {
- *d++ = *s++;
- *d++ = *s++;
- }
-
- if (__n & 1)
- *d++ = *s++;
-
- return __dest;
-}
-
/*
* gzip declarations
*/
diff --git a/arch/arm/boot/compressed/mmcif-sh7372.c b/arch/arm/boot/compressed/mmcif-sh7372.c
index b6f61d9..672ae95 100644
--- a/arch/arm/boot/compressed/mmcif-sh7372.c
+++ b/arch/arm/boot/compressed/mmcif-sh7372.c
@@ -82,7 +82,7 @@
/* Disable clock to MMC hardware block */
- __raw_writel(__raw_readl(SMSTPCR3) & (1 << 12), SMSTPCR3);
+ __raw_writel(__raw_readl(SMSTPCR3) | (1 << 12), SMSTPCR3);
mmc_update_progress(MMC_PROGRESS_DONE);
}
diff --git a/arch/arm/boot/compressed/sdhi-sh7372.c b/arch/arm/boot/compressed/sdhi-sh7372.c
index d403a8b..d279294 100644
--- a/arch/arm/boot/compressed/sdhi-sh7372.c
+++ b/arch/arm/boot/compressed/sdhi-sh7372.c
@@ -85,7 +85,7 @@
goto err;
/* Disable clock to SDHI1 hardware block */
- __raw_writel(__raw_readl(SMSTPCR3) & (1 << 13), SMSTPCR3);
+ __raw_writel(__raw_readl(SMSTPCR3) | (1 << 13), SMSTPCR3);
mmc_update_progress(MMC_PROGRESS_DONE);
diff --git a/arch/arm/boot/compressed/string.c b/arch/arm/boot/compressed/string.c
new file mode 100644
index 0000000..36e53ef
--- /dev/null
+++ b/arch/arm/boot/compressed/string.c
@@ -0,0 +1,127 @@
+/*
+ * arch/arm/boot/compressed/string.c
+ *
+ * Small subset of simple string routines
+ */
+
+#include <linux/string.h>
+
+void *memcpy(void *__dest, __const void *__src, size_t __n)
+{
+ int i = 0;
+ unsigned char *d = (unsigned char *)__dest, *s = (unsigned char *)__src;
+
+ for (i = __n >> 3; i > 0; i--) {
+ *d++ = *s++;
+ *d++ = *s++;
+ *d++ = *s++;
+ *d++ = *s++;
+ *d++ = *s++;
+ *d++ = *s++;
+ *d++ = *s++;
+ *d++ = *s++;
+ }
+
+ if (__n & 1 << 2) {
+ *d++ = *s++;
+ *d++ = *s++;
+ *d++ = *s++;
+ *d++ = *s++;
+ }
+
+ if (__n & 1 << 1) {
+ *d++ = *s++;
+ *d++ = *s++;
+ }
+
+ if (__n & 1)
+ *d++ = *s++;
+
+ return __dest;
+}
+
+void *memmove(void *__dest, __const void *__src, size_t count)
+{
+ unsigned char *d = __dest;
+ const unsigned char *s = __src;
+
+ if (__dest == __src)
+ return __dest;
+
+ if (__dest < __src)
+ return memcpy(__dest, __src, count);
+
+ while (count--)
+ d[count] = s[count];
+ return __dest;
+}
+
+size_t strlen(const char *s)
+{
+ const char *sc = s;
+
+ while (*sc != '\0')
+ sc++;
+ return sc - s;
+}
+
+int memcmp(const void *cs, const void *ct, size_t count)
+{
+ const unsigned char *su1 = cs, *su2 = ct, *end = su1 + count;
+ int res = 0;
+
+ while (su1 < end) {
+ res = *su1++ - *su2++;
+ if (res)
+ break;
+ }
+ return res;
+}
+
+int strcmp(const char *cs, const char *ct)
+{
+ unsigned char c1, c2;
+ int res = 0;
+
+ do {
+ c1 = *cs++;
+ c2 = *ct++;
+ res = c1 - c2;
+ if (res)
+ break;
+ } while (c1);
+ return res;
+}
+
+void *memchr(const void *s, int c, size_t count)
+{
+ const unsigned char *p = s;
+
+ while (count--)
+ if ((unsigned char)c == *p++)
+ return (void *)(p - 1);
+ return NULL;
+}
+
+char *strchr(const char *s, int c)
+{
+ while (*s != (char)c)
+ if (*s++ == '\0')
+ return NULL;
+ return (char *)s;
+}
+
+#undef memset
+
+void *memset(void *s, int c, size_t count)
+{
+ char *xs = s;
+ while (count--)
+ *xs++ = c;
+ return s;
+}
+
+void __memzero(void *s, size_t count)
+{
+ memset(s, 0, count);
+}
diff --git a/arch/arm/boot/compressed/vmlinux.lds.in b/arch/arm/boot/compressed/vmlinux.lds.in
index 4e72883..4919f2a 100644
--- a/arch/arm/boot/compressed/vmlinux.lds.in
+++ b/arch/arm/boot/compressed/vmlinux.lds.in
@@ -51,6 +51,10 @@
_got_start = .;
.got : { *(.got) }
_got_end = .;
+
+ /* ensure the zImage file size is always a multiple of 64 bits */
+ /* (without a dummy byte, ld just ignores the empty section) */
+ .pad : { BYTE(0); . = ALIGN(8); }
_edata = .;
. = BSS_START;
diff --git a/arch/arm/common/gic.c b/arch/arm/common/gic.c
index 3227ca9..734db99 100644
--- a/arch/arm/common/gic.c
+++ b/arch/arm/common/gic.c
@@ -26,6 +26,7 @@
#include <linux/kernel.h>
#include <linux/list.h>
#include <linux/smp.h>
+#include <linux/cpu_pm.h>
#include <linux/cpumask.h>
#include <linux/io.h>
@@ -276,6 +277,8 @@
if (gic_irqs > 1020)
gic_irqs = 1020;
+ gic->gic_irqs = gic_irqs;
+
/*
* Set all global interrupts to be level triggered, active low.
*/
@@ -343,6 +346,189 @@
writel_relaxed(1, base + GIC_CPU_CTRL);
}
+#ifdef CONFIG_CPU_PM
+/*
+ * Saves the GIC distributor registers during suspend or idle. Must be called
+ * with interrupts disabled but before powering down the GIC. After calling
+ * this function, no interrupts will be delivered by the GIC, and another
+ * platform-specific wakeup source must be enabled.
+ */
+static void gic_dist_save(unsigned int gic_nr)
+{
+ unsigned int gic_irqs;
+ void __iomem *dist_base;
+ int i;
+
+ if (gic_nr >= MAX_GIC_NR)
+ BUG();
+
+ gic_irqs = gic_data[gic_nr].gic_irqs;
+ dist_base = gic_data[gic_nr].dist_base;
+
+ if (!dist_base)
+ return;
+
+ for (i = 0; i < DIV_ROUND_UP(gic_irqs, 16); i++)
+ gic_data[gic_nr].saved_spi_conf[i] =
+ readl_relaxed(dist_base + GIC_DIST_CONFIG + i * 4);
+
+ for (i = 0; i < DIV_ROUND_UP(gic_irqs, 4); i++)
+ gic_data[gic_nr].saved_spi_target[i] =
+ readl_relaxed(dist_base + GIC_DIST_TARGET + i * 4);
+
+ for (i = 0; i < DIV_ROUND_UP(gic_irqs, 32); i++)
+ gic_data[gic_nr].saved_spi_enable[i] =
+ readl_relaxed(dist_base + GIC_DIST_ENABLE_SET + i * 4);
+}
+
+/*
+ * Restores the GIC distributor registers during resume or when coming out of
+ * idle. Must be called before enabling interrupts. If a level interrupt
+ * that occured while the GIC was suspended is still present, it will be
+ * handled normally, but any edge interrupts that occured will not be seen by
+ * the GIC and need to be handled by the platform-specific wakeup source.
+ */
+static void gic_dist_restore(unsigned int gic_nr)
+{
+ unsigned int gic_irqs;
+ unsigned int i;
+ void __iomem *dist_base;
+
+ if (gic_nr >= MAX_GIC_NR)
+ BUG();
+
+ gic_irqs = gic_data[gic_nr].gic_irqs;
+ dist_base = gic_data[gic_nr].dist_base;
+
+ if (!dist_base)
+ return;
+
+ writel_relaxed(0, dist_base + GIC_DIST_CTRL);
+
+ for (i = 0; i < DIV_ROUND_UP(gic_irqs, 16); i++)
+ writel_relaxed(gic_data[gic_nr].saved_spi_conf[i],
+ dist_base + GIC_DIST_CONFIG + i * 4);
+
+ for (i = 0; i < DIV_ROUND_UP(gic_irqs, 4); i++)
+ writel_relaxed(0xa0a0a0a0,
+ dist_base + GIC_DIST_PRI + i * 4);
+
+ for (i = 0; i < DIV_ROUND_UP(gic_irqs, 4); i++)
+ writel_relaxed(gic_data[gic_nr].saved_spi_target[i],
+ dist_base + GIC_DIST_TARGET + i * 4);
+
+ for (i = 0; i < DIV_ROUND_UP(gic_irqs, 32); i++)
+ writel_relaxed(gic_data[gic_nr].saved_spi_enable[i],
+ dist_base + GIC_DIST_ENABLE_SET + i * 4);
+
+ writel_relaxed(1, dist_base + GIC_DIST_CTRL);
+}
+
+static void gic_cpu_save(unsigned int gic_nr)
+{
+ int i;
+ u32 *ptr;
+ void __iomem *dist_base;
+ void __iomem *cpu_base;
+
+ if (gic_nr >= MAX_GIC_NR)
+ BUG();
+
+ dist_base = gic_data[gic_nr].dist_base;
+ cpu_base = gic_data[gic_nr].cpu_base;
+
+ if (!dist_base || !cpu_base)
+ return;
+
+ ptr = __this_cpu_ptr(gic_data[gic_nr].saved_ppi_enable);
+ for (i = 0; i < DIV_ROUND_UP(32, 32); i++)
+ ptr[i] = readl_relaxed(dist_base + GIC_DIST_ENABLE_SET + i * 4);
+
+ ptr = __this_cpu_ptr(gic_data[gic_nr].saved_ppi_conf);
+ for (i = 0; i < DIV_ROUND_UP(32, 16); i++)
+ ptr[i] = readl_relaxed(dist_base + GIC_DIST_CONFIG + i * 4);
+
+}
+
+static void gic_cpu_restore(unsigned int gic_nr)
+{
+ int i;
+ u32 *ptr;
+ void __iomem *dist_base;
+ void __iomem *cpu_base;
+
+ if (gic_nr >= MAX_GIC_NR)
+ BUG();
+
+ dist_base = gic_data[gic_nr].dist_base;
+ cpu_base = gic_data[gic_nr].cpu_base;
+
+ if (!dist_base || !cpu_base)
+ return;
+
+ ptr = __this_cpu_ptr(gic_data[gic_nr].saved_ppi_enable);
+ for (i = 0; i < DIV_ROUND_UP(32, 32); i++)
+ writel_relaxed(ptr[i], dist_base + GIC_DIST_ENABLE_SET + i * 4);
+
+ ptr = __this_cpu_ptr(gic_data[gic_nr].saved_ppi_conf);
+ for (i = 0; i < DIV_ROUND_UP(32, 16); i++)
+ writel_relaxed(ptr[i], dist_base + GIC_DIST_CONFIG + i * 4);
+
+ for (i = 0; i < DIV_ROUND_UP(32, 4); i++)
+ writel_relaxed(0xa0a0a0a0, dist_base + GIC_DIST_PRI + i * 4);
+
+ writel_relaxed(0xf0, cpu_base + GIC_CPU_PRIMASK);
+ writel_relaxed(1, cpu_base + GIC_CPU_CTRL);
+}
+
+static int gic_notifier(struct notifier_block *self, unsigned long cmd, void *v)
+{
+ int i;
+
+ for (i = 0; i < MAX_GIC_NR; i++) {
+ switch (cmd) {
+ case CPU_PM_ENTER:
+ gic_cpu_save(i);
+ break;
+ case CPU_PM_ENTER_FAILED:
+ case CPU_PM_EXIT:
+ gic_cpu_restore(i);
+ break;
+ case CPU_CLUSTER_PM_ENTER:
+ gic_dist_save(i);
+ break;
+ case CPU_CLUSTER_PM_ENTER_FAILED:
+ case CPU_CLUSTER_PM_EXIT:
+ gic_dist_restore(i);
+ break;
+ }
+ }
+
+ return NOTIFY_OK;
+}
+
+static struct notifier_block gic_notifier_block = {
+ .notifier_call = gic_notifier,
+};
+
+static void __init gic_pm_init(struct gic_chip_data *gic)
+{
+ gic->saved_ppi_enable = __alloc_percpu(DIV_ROUND_UP(32, 32) * 4,
+ sizeof(u32));
+ BUG_ON(!gic->saved_ppi_enable);
+
+ gic->saved_ppi_conf = __alloc_percpu(DIV_ROUND_UP(32, 16) * 4,
+ sizeof(u32));
+ BUG_ON(!gic->saved_ppi_conf);
+
+ cpu_pm_register_notifier(&gic_notifier_block);
+}
+#else
+static void __init gic_pm_init(struct gic_chip_data *gic)
+{
+}
+#endif
+
void __init gic_init(unsigned int gic_nr, unsigned int irq_start,
void __iomem *dist_base, void __iomem *cpu_base)
{
@@ -358,8 +544,10 @@
if (gic_nr == 0)
gic_cpu_base_addr = cpu_base;
+ gic_chip.flags |= gic_arch_extn.flags;
gic_dist_init(gic, irq_start);
gic_cpu_init(gic);
+ gic_pm_init(gic);
}
void __cpuinit gic_secondary_init(unsigned int gic_nr)
diff --git a/arch/arm/include/asm/hardware/cache-l2x0.h b/arch/arm/include/asm/hardware/cache-l2x0.h
index 16bd480..99a6ed7 100644
--- a/arch/arm/include/asm/hardware/cache-l2x0.h
+++ b/arch/arm/include/asm/hardware/cache-l2x0.h
@@ -45,8 +45,13 @@
#define L2X0_CLEAN_INV_LINE_PA 0x7F0
#define L2X0_CLEAN_INV_LINE_IDX 0x7F8
#define L2X0_CLEAN_INV_WAY 0x7FC
-#define L2X0_LOCKDOWN_WAY_D 0x900
-#define L2X0_LOCKDOWN_WAY_I 0x904
+/*
+ * The lockdown registers repeat 8 times for L310, the L210 has only one
+ * D and one I lockdown register at 0x0900 and 0x0904.
+ */
+#define L2X0_LOCKDOWN_WAY_D_BASE 0x900
+#define L2X0_LOCKDOWN_WAY_I_BASE 0x904
+#define L2X0_LOCKDOWN_STRIDE 0x08
#define L2X0_TEST_OPERATION 0xF00
#define L2X0_LINE_DATA 0xF10
#define L2X0_LINE_TAG 0xF30
@@ -64,7 +69,7 @@
#define L2X0_AUX_CTRL_MASK 0xc0000fff
#define L2X0_AUX_CTRL_ASSOCIATIVITY_SHIFT 16
#define L2X0_AUX_CTRL_WAY_SIZE_SHIFT 17
-#define L2X0_AUX_CTRL_WAY_SIZE_MASK (0x3 << 17)
+#define L2X0_AUX_CTRL_WAY_SIZE_MASK (0x7 << 17)
#define L2X0_AUX_CTRL_SHARE_OVERRIDE_SHIFT 22
#define L2X0_AUX_CTRL_NS_LOCKDOWN_SHIFT 26
#define L2X0_AUX_CTRL_NS_INT_CTRL_SHIFT 27
diff --git a/arch/arm/include/asm/hardware/gic.h b/arch/arm/include/asm/hardware/gic.h
index 435d3f8..c562705 100644
--- a/arch/arm/include/asm/hardware/gic.h
+++ b/arch/arm/include/asm/hardware/gic.h
@@ -46,6 +46,14 @@
unsigned int irq_offset;
void __iomem *dist_base;
void __iomem *cpu_base;
+#ifdef CONFIG_CPU_PM
+ u32 saved_spi_enable[DIV_ROUND_UP(1020, 32)];
+ u32 saved_spi_conf[DIV_ROUND_UP(1020, 16)];
+ u32 saved_spi_target[DIV_ROUND_UP(1020, 4)];
+ u32 __percpu *saved_ppi_enable;
+ u32 __percpu *saved_ppi_conf;
+#endif
+ unsigned int gic_irqs;
};
#endif
diff --git a/arch/arm/include/asm/hw_breakpoint.h b/arch/arm/include/asm/hw_breakpoint.h
index f389b27..c190bc9 100644
--- a/arch/arm/include/asm/hw_breakpoint.h
+++ b/arch/arm/include/asm/hw_breakpoint.h
@@ -50,6 +50,7 @@
#define ARM_DEBUG_ARCH_V6_1 2
#define ARM_DEBUG_ARCH_V7_ECP14 3
#define ARM_DEBUG_ARCH_V7_MM 4
+#define ARM_DEBUG_ARCH_V7_1 5
/* Breakpoint */
#define ARM_BREAKPOINT_EXECUTE 0
@@ -57,6 +58,7 @@
/* Watchpoints */
#define ARM_BREAKPOINT_LOAD 1
#define ARM_BREAKPOINT_STORE 2
+#define ARM_FSR_ACCESS_MASK (1 << 11)
/* Privilege Levels */
#define ARM_BREAKPOINT_PRIV 1
diff --git a/arch/arm/include/asm/mach/map.h b/arch/arm/include/asm/mach/map.h
index d2fedb5..b36f365 100644
--- a/arch/arm/include/asm/mach/map.h
+++ b/arch/arm/include/asm/mach/map.h
@@ -29,6 +29,7 @@
#define MT_MEMORY_NONCACHED 11
#define MT_MEMORY_DTCM 12
#define MT_MEMORY_ITCM 13
+#define MT_MEMORY_SO 14
#ifdef CONFIG_MMU
extern void iotable_init(struct map_desc *, int);
diff --git a/arch/arm/include/asm/pgtable.h b/arch/arm/include/asm/pgtable.h
index 5750704..f1956b2 100644
--- a/arch/arm/include/asm/pgtable.h
+++ b/arch/arm/include/asm/pgtable.h
@@ -232,6 +232,9 @@
#define pgprot_writecombine(prot) \
__pgprot_modify(prot, L_PTE_MT_MASK, L_PTE_MT_BUFFERABLE)
+#define pgprot_stronglyordered(prot) \
+ __pgprot_modify(prot, L_PTE_MT_MASK, L_PTE_MT_UNCACHED)
+
#ifdef CONFIG_ARM_DMA_MEM_BUFFERABLE
#define pgprot_dmacoherent(prot) \
__pgprot_modify(prot, L_PTE_MT_MASK, L_PTE_MT_BUFFERABLE | L_PTE_XN)
diff --git a/arch/arm/include/asm/pmu.h b/arch/arm/include/asm/pmu.h
index 67c70a3..71d99b8 100644
--- a/arch/arm/include/asm/pmu.h
+++ b/arch/arm/include/asm/pmu.h
@@ -13,7 +13,12 @@
#define __ARM_PMU_H__
#include <linux/interrupt.h>
+#include <linux/perf_event.h>
+/*
+ * Types of PMUs that can be accessed directly and require mutual
+ * exclusion between profiling tools.
+ */
enum arm_pmu_type {
ARM_PMU_DEVICE_CPU = 0,
ARM_NUM_PMU_DEVICES,
@@ -37,21 +42,17 @@
* reserve_pmu() - reserve the hardware performance counters
*
* Reserve the hardware performance counters in the system for exclusive use.
- * The platform_device for the system is returned on success, ERR_PTR()
- * encoded error on failure.
+ * Returns 0 on success or -EBUSY if the lock is already held.
*/
-extern struct platform_device *
-reserve_pmu(enum arm_pmu_type device);
+extern int
+reserve_pmu(enum arm_pmu_type type);
/**
* release_pmu() - Relinquish control of the performance counters
*
* Release the performance counters and allow someone else to use them.
- * Callers must have disabled the counters and released IRQs before calling
- * this. The platform_device returned from reserve_pmu() must be passed as
- * a cookie.
*/
-extern int
+extern void
release_pmu(enum arm_pmu_type type);
/**
@@ -62,30 +63,84 @@
* the actual hardware initialisation.
*/
extern int
-init_pmu(enum arm_pmu_type device);
+init_pmu(enum arm_pmu_type type);
#else /* CONFIG_CPU_HAS_PMU */
#include <linux/err.h>
-static inline struct platform_device *
-reserve_pmu(enum arm_pmu_type device)
-{
- return ERR_PTR(-ENODEV);
-}
-
static inline int
-release_pmu(struct platform_device *pdev)
+reserve_pmu(enum arm_pmu_type type)
{
return -ENODEV;
}
-static inline int
-init_pmu(enum arm_pmu_type device)
-{
- return -ENODEV;
-}
+static inline void
+release_pmu(enum arm_pmu_type type) { }
#endif /* CONFIG_CPU_HAS_PMU */
+#ifdef CONFIG_HW_PERF_EVENTS
+
+/* The events for a given PMU register set. */
+struct pmu_hw_events {
+ /*
+ * The events that are active on the PMU for the given index.
+ */
+ struct perf_event **events;
+
+ /*
+ * A 1 bit for an index indicates that the counter is being used for
+ * an event. A 0 means that the counter can be used.
+ */
+ unsigned long *used_mask;
+
+ /*
+ * Hardware lock to serialize accesses to PMU registers. Needed for the
+ * read/modify/write sequences.
+ */
+ raw_spinlock_t pmu_lock;
+};
+
+struct arm_pmu {
+ struct pmu pmu;
+ enum arm_perf_pmu_ids id;
+ enum arm_pmu_type type;
+ cpumask_t active_irqs;
+ const char *name;
+ irqreturn_t (*handle_irq)(int irq_num, void *dev);
+ void (*enable)(struct hw_perf_event *evt, int idx);
+ void (*disable)(struct hw_perf_event *evt, int idx);
+ int (*get_event_idx)(struct pmu_hw_events *hw_events,
+ struct hw_perf_event *hwc);
+ int (*set_event_filter)(struct hw_perf_event *evt,
+ struct perf_event_attr *attr);
+ u32 (*read_counter)(int idx);
+ void (*write_counter)(int idx, u32 val);
+ void (*start)(void);
+ void (*stop)(void);
+ void (*reset)(void *);
+ int (*map_event)(struct perf_event *event);
+ int num_events;
+ atomic_t active_events;
+ struct mutex reserve_mutex;
+ u64 max_period;
+ struct platform_device *plat_device;
+ struct pmu_hw_events *(*get_hw_events)(void);
+};
+
+#define to_arm_pmu(p) (container_of(p, struct arm_pmu, pmu))
+
+int __init armpmu_register(struct arm_pmu *armpmu, char *name, int type);
+
+u64 armpmu_event_update(struct perf_event *event,
+ struct hw_perf_event *hwc,
+ int idx, int overflow);
+
+int armpmu_event_set_period(struct perf_event *event,
+ struct hw_perf_event *hwc,
+ int idx);
+
+#endif /* CONFIG_HW_PERF_EVENTS */
+
#endif /* __ARM_PMU_H__ */
diff --git a/arch/arm/include/asm/proc-fns.h b/arch/arm/include/asm/proc-fns.h
index 633d1cb..9e92cb20 100644
--- a/arch/arm/include/asm/proc-fns.h
+++ b/arch/arm/include/asm/proc-fns.h
@@ -81,6 +81,10 @@
extern void cpu_do_switch_mm(unsigned long pgd_phys, struct mm_struct *mm);
extern void cpu_set_pte_ext(pte_t *ptep, pte_t pte, unsigned int ext);
extern void cpu_reset(unsigned long addr) __attribute__((noreturn));
+
+/* These three are private to arch/arm/kernel/suspend.c */
+extern void cpu_do_suspend(void *);
+extern void cpu_do_resume(void *);
#else
#define cpu_proc_init processor._proc_init
#define cpu_proc_fin processor._proc_fin
@@ -89,6 +93,10 @@
#define cpu_dcache_clean_area processor.dcache_clean_area
#define cpu_set_pte_ext processor.set_pte_ext
#define cpu_do_switch_mm processor.switch_mm
+
+/* These three are private to arch/arm/kernel/suspend.c */
+#define cpu_do_suspend processor.do_suspend
+#define cpu_do_resume processor.do_resume
#endif
extern void cpu_resume(void);
diff --git a/arch/arm/include/asm/suspend.h b/arch/arm/include/asm/suspend.h
index b0e4e1a..1c0a551 100644
--- a/arch/arm/include/asm/suspend.h
+++ b/arch/arm/include/asm/suspend.h
@@ -1,22 +1,7 @@
#ifndef __ASM_ARM_SUSPEND_H
#define __ASM_ARM_SUSPEND_H
-#include <asm/memory.h>
-#include <asm/tlbflush.h>
-
extern void cpu_resume(void);
-
-/*
- * Hide the first two arguments to __cpu_suspend - these are an implementation
- * detail which platform code shouldn't have to know about.
- */
-static inline int cpu_suspend(unsigned long arg, int (*fn)(unsigned long))
-{
- extern int __cpu_suspend(int, long, unsigned long,
- int (*)(unsigned long));
- int ret = __cpu_suspend(0, PHYS_OFFSET - PAGE_OFFSET, arg, fn);
- flush_tlb_all();
- return ret;
-}
+extern int cpu_suspend(unsigned long, int (*)(unsigned long));
#endif
diff --git a/arch/arm/kernel/Makefile b/arch/arm/kernel/Makefile
index f7887dc..8fa83f5 100644
--- a/arch/arm/kernel/Makefile
+++ b/arch/arm/kernel/Makefile
@@ -29,7 +29,7 @@
obj-$(CONFIG_ARTHUR) += arthur.o
obj-$(CONFIG_ISA_DMA) += dma-isa.o
obj-$(CONFIG_PCI) += bios32.o isa.o
-obj-$(CONFIG_PM_SLEEP) += sleep.o
+obj-$(CONFIG_PM_SLEEP) += sleep.o suspend.o
obj-$(CONFIG_HAVE_SCHED_CLOCK) += sched_clock.o
obj-$(CONFIG_SMP) += smp.o smp_tlb.o
obj-$(CONFIG_HAVE_ARM_SCU) += smp_scu.o
@@ -43,6 +43,13 @@
else
obj-$(CONFIG_KPROBES) += kprobes-arm.o
endif
+obj-$(CONFIG_ARM_KPROBES_TEST) += test-kprobes.o
+test-kprobes-objs := kprobes-test.o
+ifdef CONFIG_THUMB2_KERNEL
+test-kprobes-objs += kprobes-test-thumb.o
+else
+test-kprobes-objs += kprobes-test-arm.o
+endif
obj-$(CONFIG_ATAGS_PROC) += atags.o
obj-$(CONFIG_OABI_COMPAT) += sys_oabi-compat.o
obj-$(CONFIG_ARM_THUMBEE) += thumbee.o
diff --git a/arch/arm/kernel/calls.S b/arch/arm/kernel/calls.S
index 80f7896..9943e9e 100644
--- a/arch/arm/kernel/calls.S
+++ b/arch/arm/kernel/calls.S
@@ -178,7 +178,7 @@
CALL(sys_ni_syscall) /* vm86 */
CALL(sys_ni_syscall) /* was sys_query_module */
CALL(sys_poll)
- CALL(sys_nfsservctl)
+ CALL(sys_ni_syscall) /* was nfsservctl */
/* 170 */ CALL(sys_setresgid16)
CALL(sys_getresgid16)
CALL(sys_prctl)
diff --git a/arch/arm/kernel/hw_breakpoint.c b/arch/arm/kernel/hw_breakpoint.c
index a927ca1..814a52a9 100644
--- a/arch/arm/kernel/hw_breakpoint.c
+++ b/arch/arm/kernel/hw_breakpoint.c
@@ -45,7 +45,6 @@
/* Number of BRP/WRP registers on this CPU. */
static int core_num_brps;
-static int core_num_reserved_brps;
static int core_num_wrps;
/* Debug architecture version. */
@@ -137,10 +136,11 @@
u32 didr;
/* Do we implement the extended CPUID interface? */
- if (WARN_ONCE((((read_cpuid_id() >> 16) & 0xf) != 0xf),
- "CPUID feature registers not supported. "
- "Assuming v6 debug is present.\n"))
+ if (((read_cpuid_id() >> 16) & 0xf) != 0xf) {
+ pr_warning("CPUID feature registers not supported. "
+ "Assuming v6 debug is present.\n");
return ARM_DEBUG_ARCH_V6;
+ }
ARM_DBG_READ(c0, 0, didr);
return (didr >> 16) & 0xf;
@@ -154,10 +154,21 @@
static int debug_arch_supported(void)
{
u8 arch = get_debug_arch();
- return arch >= ARM_DEBUG_ARCH_V6 && arch <= ARM_DEBUG_ARCH_V7_ECP14;
+
+ /* We don't support the memory-mapped interface. */
+ return (arch >= ARM_DEBUG_ARCH_V6 && arch <= ARM_DEBUG_ARCH_V7_ECP14) ||
+ arch >= ARM_DEBUG_ARCH_V7_1;
}
-/* Determine number of BRP register available. */
+/* Determine number of WRP registers available. */
+static int get_num_wrp_resources(void)
+{
+ u32 didr;
+ ARM_DBG_READ(c0, 0, didr);
+ return ((didr >> 28) & 0xf) + 1;
+}
+
+/* Determine number of BRP registers available. */
static int get_num_brp_resources(void)
{
u32 didr;
@@ -176,9 +187,10 @@
static int get_num_wrps(void)
{
/*
- * FIXME: When a watchpoint fires, the only way to work out which
- * watchpoint it was is by disassembling the faulting instruction
- * and working out the address of the memory access.
+ * On debug architectures prior to 7.1, when a watchpoint fires, the
+ * only way to work out which watchpoint it was is by disassembling
+ * the faulting instruction and working out the address of the memory
+ * access.
*
* Furthermore, we can only do this if the watchpoint was precise
* since imprecise watchpoints prevent us from calculating register
@@ -192,36 +204,17 @@
* [the ARM ARM states that the DFAR is UNKNOWN, but experience shows
* that it is set on some implementations].
*/
+ if (get_debug_arch() < ARM_DEBUG_ARCH_V7_1)
+ return 1;
-#if 0
- int wrps;
- u32 didr;
- ARM_DBG_READ(c0, 0, didr);
- wrps = ((didr >> 28) & 0xf) + 1;
-#endif
- int wrps = 1;
-
- if (core_has_mismatch_brps() && wrps >= get_num_brp_resources())
- wrps = get_num_brp_resources() - 1;
-
- return wrps;
-}
-
-/* We reserve one breakpoint for each watchpoint. */
-static int get_num_reserved_brps(void)
-{
- if (core_has_mismatch_brps())
- return get_num_wrps();
- return 0;
+ return get_num_wrp_resources();
}
/* Determine number of usable BRPs available. */
static int get_num_brps(void)
{
int brps = get_num_brp_resources();
- if (core_has_mismatch_brps())
- brps -= get_num_reserved_brps();
- return brps;
+ return core_has_mismatch_brps() ? brps - 1 : brps;
}
/*
@@ -239,7 +232,7 @@
/* Ensure that halting mode is disabled. */
if (WARN_ONCE(dscr & ARM_DSCR_HDBGEN,
- "halting debug mode enabled. Unable to access hardware resources.\n")) {
+ "halting debug mode enabled. Unable to access hardware resources.\n")) {
ret = -EPERM;
goto out;
}
@@ -255,6 +248,7 @@
ARM_DBG_WRITE(c1, 0, (dscr | ARM_DSCR_MDBGEN));
break;
case ARM_DEBUG_ARCH_V7_ECP14:
+ case ARM_DEBUG_ARCH_V7_1:
ARM_DBG_WRITE(c2, 2, (dscr | ARM_DSCR_MDBGEN));
break;
default:
@@ -346,24 +340,10 @@
val_base = ARM_BASE_BVR;
slots = (struct perf_event **)__get_cpu_var(bp_on_reg);
max_slots = core_num_brps;
- if (info->step_ctrl.enabled) {
- /* Override the breakpoint data with the step data. */
- addr = info->trigger & ~0x3;
- ctrl = encode_ctrl_reg(info->step_ctrl);
- }
} else {
/* Watchpoint */
- if (info->step_ctrl.enabled) {
- /* Install into the reserved breakpoint region. */
- ctrl_base = ARM_BASE_BCR + core_num_brps;
- val_base = ARM_BASE_BVR + core_num_brps;
- /* Override the watchpoint data with the step data. */
- addr = info->trigger & ~0x3;
- ctrl = encode_ctrl_reg(info->step_ctrl);
- } else {
- ctrl_base = ARM_BASE_WCR;
- val_base = ARM_BASE_WVR;
- }
+ ctrl_base = ARM_BASE_WCR;
+ val_base = ARM_BASE_WVR;
slots = (struct perf_event **)__get_cpu_var(wp_on_reg);
max_slots = core_num_wrps;
}
@@ -382,6 +362,17 @@
goto out;
}
+ /* Override the breakpoint data with the step data. */
+ if (info->step_ctrl.enabled) {
+ addr = info->trigger & ~0x3;
+ ctrl = encode_ctrl_reg(info->step_ctrl);
+ if (info->ctrl.type != ARM_BREAKPOINT_EXECUTE) {
+ i = 0;
+ ctrl_base = ARM_BASE_BCR + core_num_brps;
+ val_base = ARM_BASE_BVR + core_num_brps;
+ }
+ }
+
/* Setup the address register. */
write_wb_reg(val_base + i, addr);
@@ -405,10 +396,7 @@
max_slots = core_num_brps;
} else {
/* Watchpoint */
- if (info->step_ctrl.enabled)
- base = ARM_BASE_BCR + core_num_brps;
- else
- base = ARM_BASE_WCR;
+ base = ARM_BASE_WCR;
slots = (struct perf_event **)__get_cpu_var(wp_on_reg);
max_slots = core_num_wrps;
}
@@ -426,6 +414,13 @@
if (WARN_ONCE(i == max_slots, "Can't find any breakpoint slot\n"))
return;
+ /* Ensure that we disable the mismatch breakpoint. */
+ if (info->ctrl.type != ARM_BREAKPOINT_EXECUTE &&
+ info->step_ctrl.enabled) {
+ i = 0;
+ base = ARM_BASE_BCR + core_num_brps;
+ }
+
/* Reset the control register. */
write_wb_reg(base + i, 0);
}
@@ -632,10 +627,9 @@
* we can use the mismatch feature as a poor-man's hardware
* single-step, but this only works for per-task breakpoints.
*/
- if (WARN_ONCE(!bp->overflow_handler &&
- (arch_check_bp_in_kernelspace(bp) || !core_has_mismatch_brps()
- || !bp->hw.bp_target),
- "overflow handler required but none found\n")) {
+ if (!bp->overflow_handler && (arch_check_bp_in_kernelspace(bp) ||
+ !core_has_mismatch_brps() || !bp->hw.bp_target)) {
+ pr_warning("overflow handler required but none found\n");
ret = -EINVAL;
}
out:
@@ -666,34 +660,62 @@
arch_install_hw_breakpoint(bp);
}
-static void watchpoint_handler(unsigned long unknown, struct pt_regs *regs)
+static void watchpoint_handler(unsigned long addr, unsigned int fsr,
+ struct pt_regs *regs)
{
- int i;
+ int i, access;
+ u32 val, ctrl_reg, alignment_mask;
struct perf_event *wp, **slots;
struct arch_hw_breakpoint *info;
+ struct arch_hw_breakpoint_ctrl ctrl;
slots = (struct perf_event **)__get_cpu_var(wp_on_reg);
- /* Without a disassembler, we can only handle 1 watchpoint. */
- BUG_ON(core_num_wrps > 1);
-
for (i = 0; i < core_num_wrps; ++i) {
rcu_read_lock();
wp = slots[i];
- if (wp == NULL) {
- rcu_read_unlock();
- continue;
+ if (wp == NULL)
+ goto unlock;
+
+ info = counter_arch_bp(wp);
+ /*
+ * The DFAR is an unknown value on debug architectures prior
+ * to 7.1. Since we only allow a single watchpoint on these
+ * older CPUs, we can set the trigger to the lowest possible
+ * faulting address.
+ */
+ if (debug_arch < ARM_DEBUG_ARCH_V7_1) {
+ BUG_ON(i > 0);
+ info->trigger = wp->attr.bp_addr;
+ } else {
+ if (info->ctrl.len == ARM_BREAKPOINT_LEN_8)
+ alignment_mask = 0x7;
+ else
+ alignment_mask = 0x3;
+
+ /* Check if the watchpoint value matches. */
+ val = read_wb_reg(ARM_BASE_WVR + i);
+ if (val != (addr & ~alignment_mask))
+ goto unlock;
+
+ /* Possible match, check the byte address select. */
+ ctrl_reg = read_wb_reg(ARM_BASE_WCR + i);
+ decode_ctrl_reg(ctrl_reg, &ctrl);
+ if (!((1 << (addr & alignment_mask)) & ctrl.len))
+ goto unlock;
+
+ /* Check that the access type matches. */
+ access = (fsr & ARM_FSR_ACCESS_MASK) ? HW_BREAKPOINT_W :
+ HW_BREAKPOINT_R;
+ if (!(access & hw_breakpoint_type(wp)))
+ goto unlock;
+
+ /* We have a winner. */
+ info->trigger = addr;
}
- /*
- * The DFAR is an unknown value. Since we only allow a
- * single watchpoint, we can set the trigger to the lowest
- * possible faulting address.
- */
- info = counter_arch_bp(wp);
- info->trigger = wp->attr.bp_addr;
pr_debug("watchpoint fired: address = 0x%x\n", info->trigger);
perf_bp_event(wp, regs);
@@ -705,6 +727,7 @@
if (!wp->overflow_handler)
enable_single_step(wp, instruction_pointer(regs));
+unlock:
rcu_read_unlock();
}
}
@@ -717,7 +740,7 @@
slots = (struct perf_event **)__get_cpu_var(wp_on_reg);
- for (i = 0; i < core_num_reserved_brps; ++i) {
+ for (i = 0; i < core_num_wrps; ++i) {
rcu_read_lock();
wp = slots[i];
@@ -820,7 +843,7 @@
case ARM_ENTRY_ASYNC_WATCHPOINT:
WARN(1, "Asynchronous watchpoint exception taken. Debugging results may be unreliable\n");
case ARM_ENTRY_SYNC_WATCHPOINT:
- watchpoint_handler(addr, regs);
+ watchpoint_handler(addr, fsr, regs);
break;
default:
ret = 1; /* Unhandled fault. */
@@ -834,11 +857,31 @@
/*
* One-time initialisation.
*/
-static void reset_ctrl_regs(void *info)
+static cpumask_t debug_err_mask;
+
+static int debug_reg_trap(struct pt_regs *regs, unsigned int instr)
{
- int i, cpu = smp_processor_id();
+ int cpu = smp_processor_id();
+
+ pr_warning("Debug register access (0x%x) caused undefined instruction on CPU %d\n",
+ instr, cpu);
+
+ /* Set the error flag for this CPU and skip the faulting instruction. */
+ cpumask_set_cpu(cpu, &debug_err_mask);
+ instruction_pointer(regs) += 4;
+ return 0;
+}
+
+static struct undef_hook debug_reg_hook = {
+ .instr_mask = 0x0fe80f10,
+ .instr_val = 0x0e000e10,
+ .fn = debug_reg_trap,
+};
+
+static void reset_ctrl_regs(void *unused)
+{
+ int i, raw_num_brps, err = 0, cpu = smp_processor_id();
u32 dbg_power;
- cpumask_t *cpumask = info;
/*
* v7 debug contains save and restore registers so that debug state
@@ -848,38 +891,57 @@
* Access Register to avoid taking undefined instruction exceptions
* later on.
*/
- if (debug_arch >= ARM_DEBUG_ARCH_V7_ECP14) {
+ switch (debug_arch) {
+ case ARM_DEBUG_ARCH_V6:
+ case ARM_DEBUG_ARCH_V6_1:
+ /* ARMv6 cores just need to reset the registers. */
+ goto reset_regs;
+ case ARM_DEBUG_ARCH_V7_ECP14:
/*
* Ensure sticky power-down is clear (i.e. debug logic is
* powered up).
*/
asm volatile("mrc p14, 0, %0, c1, c5, 4" : "=r" (dbg_power));
- if ((dbg_power & 0x1) == 0) {
- pr_warning("CPU %d debug is powered down!\n", cpu);
- cpumask_or(cpumask, cpumask, cpumask_of(cpu));
- return;
- }
-
+ if ((dbg_power & 0x1) == 0)
+ err = -EPERM;
+ break;
+ case ARM_DEBUG_ARCH_V7_1:
/*
- * Unconditionally clear the lock by writing a value
- * other than 0xC5ACCE55 to the access register.
+ * Ensure the OS double lock is clear.
*/
- asm volatile("mcr p14, 0, %0, c1, c0, 4" : : "r" (0));
- isb();
-
- /*
- * Clear any configured vector-catch events before
- * enabling monitor mode.
- */
- asm volatile("mcr p14, 0, %0, c0, c7, 0" : : "r" (0));
- isb();
+ asm volatile("mrc p14, 0, %0, c1, c3, 4" : "=r" (dbg_power));
+ if ((dbg_power & 0x1) == 1)
+ err = -EPERM;
+ break;
}
+ if (err) {
+ pr_warning("CPU %d debug is powered down!\n", cpu);
+ cpumask_or(&debug_err_mask, &debug_err_mask, cpumask_of(cpu));
+ return;
+ }
+
+ /*
+ * Unconditionally clear the lock by writing a value
+ * other than 0xC5ACCE55 to the access register.
+ */
+ asm volatile("mcr p14, 0, %0, c1, c0, 4" : : "r" (0));
+ isb();
+
+ /*
+ * Clear any configured vector-catch events before
+ * enabling monitor mode.
+ */
+ asm volatile("mcr p14, 0, %0, c0, c7, 0" : : "r" (0));
+ isb();
+
+reset_regs:
if (enable_monitor_mode())
return;
/* We must also reset any reserved registers. */
- for (i = 0; i < core_num_brps + core_num_reserved_brps; ++i) {
+ raw_num_brps = get_num_brp_resources();
+ for (i = 0; i < raw_num_brps; ++i) {
write_wb_reg(ARM_BASE_BCR + i, 0UL);
write_wb_reg(ARM_BASE_BVR + i, 0UL);
}
@@ -895,6 +957,7 @@
{
if (action == CPU_ONLINE)
smp_call_function_single((int)cpu, reset_ctrl_regs, NULL, 1);
+
return NOTIFY_OK;
}
@@ -905,7 +968,6 @@
static int __init arch_hw_breakpoint_init(void)
{
u32 dscr;
- cpumask_t cpumask = { CPU_BITS_NONE };
debug_arch = get_debug_arch();
@@ -916,28 +978,31 @@
/* Determine how many BRPs/WRPs are available. */
core_num_brps = get_num_brps();
- core_num_reserved_brps = get_num_reserved_brps();
core_num_wrps = get_num_wrps();
- pr_info("found %d breakpoint and %d watchpoint registers.\n",
- core_num_brps + core_num_reserved_brps, core_num_wrps);
-
- if (core_num_reserved_brps)
- pr_info("%d breakpoint(s) reserved for watchpoint "
- "single-step.\n", core_num_reserved_brps);
+ /*
+ * We need to tread carefully here because DBGSWENABLE may be
+ * driven low on this core and there isn't an architected way to
+ * determine that.
+ */
+ register_undef_hook(&debug_reg_hook);
/*
* Reset the breakpoint resources. We assume that a halting
* debugger will leave the world in a nice state for us.
*/
- on_each_cpu(reset_ctrl_regs, &cpumask, 1);
- if (!cpumask_empty(&cpumask)) {
+ on_each_cpu(reset_ctrl_regs, NULL, 1);
+ unregister_undef_hook(&debug_reg_hook);
+ if (!cpumask_empty(&debug_err_mask)) {
core_num_brps = 0;
- core_num_reserved_brps = 0;
core_num_wrps = 0;
return 0;
}
+ pr_info("found %d " "%s" "breakpoint and %d watchpoint registers.\n",
+ core_num_brps, core_has_mismatch_brps() ? "(+1 reserved) " :
+ "", core_num_wrps);
+
ARM_DBG_READ(c1, 0, dscr);
if (dscr & ARM_DSCR_HDBGEN) {
max_watchpoint_len = 4;
diff --git a/arch/arm/kernel/kprobes-arm.c b/arch/arm/kernel/kprobes-arm.c
index 79203ee..9fe8910 100644
--- a/arch/arm/kernel/kprobes-arm.c
+++ b/arch/arm/kernel/kprobes-arm.c
@@ -60,6 +60,7 @@
#include <linux/kernel.h>
#include <linux/kprobes.h>
+#include <linux/module.h>
#include "kprobes.h"
@@ -971,6 +972,9 @@
DECODE_END
};
+#ifdef CONFIG_ARM_KPROBES_TEST_MODULE
+EXPORT_SYMBOL_GPL(kprobe_decode_arm_table);
+#endif
static void __kprobes arm_singlestep(struct kprobe *p, struct pt_regs *regs)
{
diff --git a/arch/arm/kernel/kprobes-test-arm.c b/arch/arm/kernel/kprobes-test-arm.c
new file mode 100644
index 0000000..fc82de8
--- /dev/null
+++ b/arch/arm/kernel/kprobes-test-arm.c
@@ -0,0 +1,1323 @@
+/*
+ * arch/arm/kernel/kprobes-test-arm.c
+ *
+ * Copyright (C) 2011 Jon Medhurst <tixy@yxit.co.uk>.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+
+#include "kprobes-test.h"
+
+
+#define TEST_ISA "32"
+
+#define TEST_ARM_TO_THUMB_INTERWORK_R(code1, reg, val, code2) \
+ TESTCASE_START(code1 #reg code2) \
+ TEST_ARG_REG(reg, val) \
+ TEST_ARG_REG(14, 99f) \
+ TEST_ARG_END("") \
+ "50: nop \n\t" \
+ "1: "code1 #reg code2" \n\t" \
+ " bx lr \n\t" \
+ ".thumb \n\t" \
+ "3: adr lr, 2f \n\t" \
+ " bx lr \n\t" \
+ ".arm \n\t" \
+ "2: nop \n\t" \
+ TESTCASE_END
+
+#define TEST_ARM_TO_THUMB_INTERWORK_P(code1, reg, val, code2) \
+ TESTCASE_START(code1 #reg code2) \
+ TEST_ARG_PTR(reg, val) \
+ TEST_ARG_REG(14, 99f) \
+ TEST_ARG_MEM(15, 3f+1) \
+ TEST_ARG_END("") \
+ "50: nop \n\t" \
+ "1: "code1 #reg code2" \n\t" \
+ " bx lr \n\t" \
+ ".thumb \n\t" \
+ "3: adr lr, 2f \n\t" \
+ " bx lr \n\t" \
+ ".arm \n\t" \
+ "2: nop \n\t" \
+ TESTCASE_END
+
+
+void kprobe_arm_test_cases(void)
+{
+ kprobe_test_flags = 0;
+
+ TEST_GROUP("Data-processing (register), (register-shifted register), (immediate)")
+
+#define _DATA_PROCESSING_DNM(op,s,val) \
+ TEST_RR( op "eq" s " r0, r",1, VAL1,", r",2, val, "") \
+ TEST_RR( op "ne" s " r1, r",1, VAL1,", r",2, val, ", lsl #3") \
+ TEST_RR( op "cs" s " r2, r",3, VAL1,", r",2, val, ", lsr #4") \
+ TEST_RR( op "cc" s " r3, r",3, VAL1,", r",2, val, ", asr #5") \
+ TEST_RR( op "mi" s " r4, r",5, VAL1,", r",2, N(val),", asr #6") \
+ TEST_RR( op "pl" s " r5, r",5, VAL1,", r",2, val, ", ror #7") \
+ TEST_RR( op "vs" s " r6, r",7, VAL1,", r",2, val, ", rrx") \
+ TEST_R( op "vc" s " r6, r",7, VAL1,", pc, lsl #3") \
+ TEST_R( op "vc" s " r6, r",7, VAL1,", sp, lsr #4") \
+ TEST_R( op "vc" s " r6, pc, r",7, VAL1,", asr #5") \
+ TEST_R( op "vc" s " r6, sp, r",7, VAL1,", ror #6") \
+ TEST_RRR( op "hi" s " r8, r",9, VAL1,", r",14,val, ", lsl r",0, 3,"")\
+ TEST_RRR( op "ls" s " r9, r",9, VAL1,", r",14,val, ", lsr r",7, 4,"")\
+ TEST_RRR( op "ge" s " r10, r",11,VAL1,", r",14,val, ", asr r",7, 5,"")\
+ TEST_RRR( op "lt" s " r11, r",11,VAL1,", r",14,N(val),", asr r",7, 6,"")\
+ TEST_RR( op "gt" s " r12, r13" ", r",14,val, ", ror r",14,7,"")\
+ TEST_RR( op "le" s " r14, r",0, val, ", r13" ", lsl r",14,8,"")\
+ TEST_RR( op s " r12, pc" ", r",14,val, ", ror r",14,7,"")\
+ TEST_RR( op s " r14, r",0, val, ", pc" ", lsl r",14,8,"")\
+ TEST_R( op "eq" s " r0, r",11,VAL1,", #0xf5") \
+ TEST_R( op "ne" s " r11, r",0, VAL1,", #0xf5000000") \
+ TEST_R( op s " r7, r",8, VAL2,", #0x000af000") \
+ TEST( op s " r4, pc" ", #0x00005a00")
+
+#define DATA_PROCESSING_DNM(op,val) \
+ _DATA_PROCESSING_DNM(op,"",val) \
+ _DATA_PROCESSING_DNM(op,"s",val)
+
+#define DATA_PROCESSING_NM(op,val) \
+ TEST_RR( op "ne r",1, VAL1,", r",2, val, "") \
+ TEST_RR( op "eq r",1, VAL1,", r",2, val, ", lsl #3") \
+ TEST_RR( op "cc r",3, VAL1,", r",2, val, ", lsr #4") \
+ TEST_RR( op "cs r",3, VAL1,", r",2, val, ", asr #5") \
+ TEST_RR( op "pl r",5, VAL1,", r",2, N(val),", asr #6") \
+ TEST_RR( op "mi r",5, VAL1,", r",2, val, ", ror #7") \
+ TEST_RR( op "vc r",7, VAL1,", r",2, val, ", rrx") \
+ TEST_R ( op "vs r",7, VAL1,", pc, lsl #3") \
+ TEST_R ( op "vs r",7, VAL1,", sp, lsr #4") \
+ TEST_R( op "vs pc, r",7, VAL1,", asr #5") \
+ TEST_R( op "vs sp, r",7, VAL1,", ror #6") \
+ TEST_RRR( op "ls r",9, VAL1,", r",14,val, ", lsl r",0, 3,"") \
+ TEST_RRR( op "hi r",9, VAL1,", r",14,val, ", lsr r",7, 4,"") \
+ TEST_RRR( op "lt r",11,VAL1,", r",14,val, ", asr r",7, 5,"") \
+ TEST_RRR( op "ge r",11,VAL1,", r",14,N(val),", asr r",7, 6,"") \
+ TEST_RR( op "le r13" ", r",14,val, ", ror r",14,7,"") \
+ TEST_RR( op "gt r",0, val, ", r13" ", lsl r",14,8,"") \
+ TEST_RR( op " pc" ", r",14,val, ", ror r",14,7,"") \
+ TEST_RR( op " r",0, val, ", pc" ", lsl r",14,8,"") \
+ TEST_R( op "eq r",11,VAL1,", #0xf5") \
+ TEST_R( op "ne r",0, VAL1,", #0xf5000000") \
+ TEST_R( op " r",8, VAL2,", #0x000af000")
+
+#define _DATA_PROCESSING_DM(op,s,val) \
+ TEST_R( op "eq" s " r0, r",1, val, "") \
+ TEST_R( op "ne" s " r1, r",1, val, ", lsl #3") \
+ TEST_R( op "cs" s " r2, r",3, val, ", lsr #4") \
+ TEST_R( op "cc" s " r3, r",3, val, ", asr #5") \
+ TEST_R( op "mi" s " r4, r",5, N(val),", asr #6") \
+ TEST_R( op "pl" s " r5, r",5, val, ", ror #7") \
+ TEST_R( op "vs" s " r6, r",10,val, ", rrx") \
+ TEST( op "vs" s " r7, pc, lsl #3") \
+ TEST( op "vs" s " r7, sp, lsr #4") \
+ TEST_RR( op "vc" s " r8, r",7, val, ", lsl r",0, 3,"") \
+ TEST_RR( op "hi" s " r9, r",9, val, ", lsr r",7, 4,"") \
+ TEST_RR( op "ls" s " r10, r",9, val, ", asr r",7, 5,"") \
+ TEST_RR( op "ge" s " r11, r",11,N(val),", asr r",7, 6,"") \
+ TEST_RR( op "lt" s " r12, r",11,val, ", ror r",14,7,"") \
+ TEST_R( op "gt" s " r14, r13" ", lsl r",14,8,"") \
+ TEST_R( op "le" s " r14, pc" ", lsl r",14,8,"") \
+ TEST( op "eq" s " r0, #0xf5") \
+ TEST( op "ne" s " r11, #0xf5000000") \
+ TEST( op s " r7, #0x000af000") \
+ TEST( op s " r4, #0x00005a00")
+
+#define DATA_PROCESSING_DM(op,val) \
+ _DATA_PROCESSING_DM(op,"",val) \
+ _DATA_PROCESSING_DM(op,"s",val)
+
+ DATA_PROCESSING_DNM("and",0xf00f00ff)
+ DATA_PROCESSING_DNM("eor",0xf00f00ff)
+ DATA_PROCESSING_DNM("sub",VAL2)
+ DATA_PROCESSING_DNM("rsb",VAL2)
+ DATA_PROCESSING_DNM("add",VAL2)
+ DATA_PROCESSING_DNM("adc",VAL2)
+ DATA_PROCESSING_DNM("sbc",VAL2)
+ DATA_PROCESSING_DNM("rsc",VAL2)
+ DATA_PROCESSING_NM("tst",0xf00f00ff)
+ DATA_PROCESSING_NM("teq",0xf00f00ff)
+ DATA_PROCESSING_NM("cmp",VAL2)
+ DATA_PROCESSING_NM("cmn",VAL2)
+ DATA_PROCESSING_DNM("orr",0xf00f00ff)
+ DATA_PROCESSING_DM("mov",VAL2)
+ DATA_PROCESSING_DNM("bic",0xf00f00ff)
+ DATA_PROCESSING_DM("mvn",VAL2)
+
+ TEST("mov ip, sp") /* This has special case emulation code */
+
+ TEST_SUPPORTED("mov pc, #0x1000");
+ TEST_SUPPORTED("mov sp, #0x1000");
+ TEST_SUPPORTED("cmp pc, #0x1000");
+ TEST_SUPPORTED("cmp sp, #0x1000");
+
+ /* Data-processing with PC as shift*/
+ TEST_UNSUPPORTED(".word 0xe15c0f1e @ cmp r12, r14, asl pc")
+ TEST_UNSUPPORTED(".word 0xe1a0cf1e @ mov r12, r14, asl pc")
+ TEST_UNSUPPORTED(".word 0xe08caf1e @ add r10, r12, r14, asl pc")
+
+ /* Data-processing with PC as shift*/
+ TEST_UNSUPPORTED("movs pc, r1")
+ TEST_UNSUPPORTED("movs pc, r1, lsl r2")
+ TEST_UNSUPPORTED("movs pc, #0x10000")
+ TEST_UNSUPPORTED("adds pc, lr, r1")
+ TEST_UNSUPPORTED("adds pc, lr, r1, lsl r2")
+ TEST_UNSUPPORTED("adds pc, lr, #4")
+
+ /* Data-processing with SP as target */
+ TEST("add sp, sp, #16")
+ TEST("sub sp, sp, #8")
+ TEST("bic sp, sp, #0x20")
+ TEST("orr sp, sp, #0x20")
+ TEST_PR( "add sp, r",10,0,", r",11,4,"")
+ TEST_PRR("add sp, r",10,0,", r",11,4,", asl r",12,1,"")
+ TEST_P( "mov sp, r",10,0,"")
+ TEST_PR( "mov sp, r",10,0,", asl r",12,0,"")
+
+ /* Data-processing with PC as target */
+ TEST_BF( "add pc, pc, #2f-1b-8")
+ TEST_BF_R ("add pc, pc, r",14,2f-1f-8,"")
+ TEST_BF_R ("add pc, r",14,2f-1f-8,", pc")
+ TEST_BF_R ("mov pc, r",0,2f,"")
+ TEST_BF_RR("mov pc, r",0,2f,", asl r",1,0,"")
+ TEST_BB( "sub pc, pc, #1b-2b+8")
+#if __LINUX_ARM_ARCH__ >= 6
+ TEST_BB( "sub pc, pc, #1b-2b+8-2") /* UNPREDICTABLE before ARMv6 */
+#endif
+ TEST_BB_R( "sub pc, pc, r",14, 1f-2f+8,"")
+ TEST_BB_R( "rsb pc, r",14,1f-2f+8,", pc")
+ TEST_RR( "add pc, pc, r",10,-2,", asl r",11,1,"")
+#ifdef CONFIG_THUMB2_KERNEL
+ TEST_ARM_TO_THUMB_INTERWORK_R("add pc, pc, r",0,3f-1f-8+1,"")
+ TEST_ARM_TO_THUMB_INTERWORK_R("sub pc, r",0,3f+8+1,", #8")
+#endif
+ TEST_GROUP("Miscellaneous instructions")
+
+ TEST("mrs r0, cpsr")
+ TEST("mrspl r7, cpsr")
+ TEST("mrs r14, cpsr")
+ TEST_UNSUPPORTED(".word 0xe10ff000 @ mrs r15, cpsr")
+ TEST_UNSUPPORTED("mrs r0, spsr")
+ TEST_UNSUPPORTED("mrs lr, spsr")
+
+ TEST_UNSUPPORTED("msr cpsr, r0")
+ TEST_UNSUPPORTED("msr cpsr_f, lr")
+ TEST_UNSUPPORTED("msr spsr, r0")
+
+ TEST_BF_R("bx r",0,2f,"")
+ TEST_BB_R("bx r",7,2f,"")
+ TEST_BF_R("bxeq r",14,2f,"")
+
+ TEST_R("clz r0, r",0, 0x0,"")
+ TEST_R("clzeq r7, r",14,0x1,"")
+ TEST_R("clz lr, r",7, 0xffffffff,"")
+ TEST( "clz r4, sp")
+ TEST_UNSUPPORTED(".word 0x016fff10 @ clz pc, r0")
+ TEST_UNSUPPORTED(".word 0x016f0f1f @ clz r0, pc")
+
+#if __LINUX_ARM_ARCH__ >= 6
+ TEST_UNSUPPORTED("bxj r0")
+#endif
+
+ TEST_BF_R("blx r",0,2f,"")
+ TEST_BB_R("blx r",7,2f,"")
+ TEST_BF_R("blxeq r",14,2f,"")
+ TEST_UNSUPPORTED(".word 0x0120003f @ blx pc")
+
+ TEST_RR( "qadd r0, r",1, VAL1,", r",2, VAL2,"")
+ TEST_RR( "qaddvs lr, r",9, VAL2,", r",8, VAL1,"")
+ TEST_R( "qadd lr, r",9, VAL2,", r13")
+ TEST_RR( "qsub r0, r",1, VAL1,", r",2, VAL2,"")
+ TEST_RR( "qsubvs lr, r",9, VAL2,", r",8, VAL1,"")
+ TEST_R( "qsub lr, r",9, VAL2,", r13")
+ TEST_RR( "qdadd r0, r",1, VAL1,", r",2, VAL2,"")
+ TEST_RR( "qdaddvs lr, r",9, VAL2,", r",8, VAL1,"")
+ TEST_R( "qdadd lr, r",9, VAL2,", r13")
+ TEST_RR( "qdsub r0, r",1, VAL1,", r",2, VAL2,"")
+ TEST_RR( "qdsubvs lr, r",9, VAL2,", r",8, VAL1,"")
+ TEST_R( "qdsub lr, r",9, VAL2,", r13")
+ TEST_UNSUPPORTED(".word 0xe101f050 @ qadd pc, r0, r1")
+ TEST_UNSUPPORTED(".word 0xe121f050 @ qsub pc, r0, r1")
+ TEST_UNSUPPORTED(".word 0xe141f050 @ qdadd pc, r0, r1")
+ TEST_UNSUPPORTED(".word 0xe161f050 @ qdsub pc, r0, r1")
+ TEST_UNSUPPORTED(".word 0xe16f2050 @ qdsub r2, r0, pc")
+ TEST_UNSUPPORTED(".word 0xe161205f @ qdsub r2, pc, r1")
+
+ TEST_UNSUPPORTED("bkpt 0xffff")
+ TEST_UNSUPPORTED("bkpt 0x0000")
+
+ TEST_UNSUPPORTED(".word 0xe1600070 @ smc #0")
+
+ TEST_GROUP("Halfword multiply and multiply-accumulate")
+
+ TEST_RRR( "smlabb r0, r",1, VAL1,", r",2, VAL2,", r",3, VAL3,"")
+ TEST_RRR( "smlabbge r7, r",8, VAL3,", r",9, VAL1,", r",10, VAL2,"")
+ TEST_RR( "smlabb lr, r",1, VAL2,", r",2, VAL3,", r13")
+ TEST_UNSUPPORTED(".word 0xe10f3281 @ smlabb pc, r1, r2, r3")
+ TEST_RRR( "smlatb r0, r",1, VAL1,", r",2, VAL2,", r",3, VAL3,"")
+ TEST_RRR( "smlatbge r7, r",8, VAL3,", r",9, VAL1,", r",10, VAL2,"")
+ TEST_RR( "smlatb lr, r",1, VAL2,", r",2, VAL3,", r13")
+ TEST_UNSUPPORTED(".word 0xe10f32a1 @ smlatb pc, r1, r2, r3")
+ TEST_RRR( "smlabt r0, r",1, VAL1,", r",2, VAL2,", r",3, VAL3,"")
+ TEST_RRR( "smlabtge r7, r",8, VAL3,", r",9, VAL1,", r",10, VAL2,"")
+ TEST_RR( "smlabt lr, r",1, VAL2,", r",2, VAL3,", r13")
+ TEST_UNSUPPORTED(".word 0xe10f32c1 @ smlabt pc, r1, r2, r3")
+ TEST_RRR( "smlatt r0, r",1, VAL1,", r",2, VAL2,", r",3, VAL3,"")
+ TEST_RRR( "smlattge r7, r",8, VAL3,", r",9, VAL1,", r",10, VAL2,"")
+ TEST_RR( "smlatt lr, r",1, VAL2,", r",2, VAL3,", r13")
+ TEST_UNSUPPORTED(".word 0xe10f32e1 @ smlatt pc, r1, r2, r3")
+
+ TEST_RRR( "smlawb r0, r",1, VAL1,", r",2, VAL2,", r",3, VAL3,"")
+ TEST_RRR( "smlawbge r7, r",8, VAL3,", r",9, VAL1,", r",10, VAL2,"")
+ TEST_RR( "smlawb lr, r",1, VAL2,", r",2, VAL3,", r13")
+ TEST_UNSUPPORTED(".word 0xe12f3281 @ smlawb pc, r1, r2, r3")
+ TEST_RRR( "smlawt r0, r",1, VAL1,", r",2, VAL2,", r",3, VAL3,"")
+ TEST_RRR( "smlawtge r7, r",8, VAL3,", r",9, VAL1,", r",10, VAL2,"")
+ TEST_RR( "smlawt lr, r",1, VAL2,", r",2, VAL3,", r13")
+ TEST_UNSUPPORTED(".word 0xe12f32c1 @ smlawt pc, r1, r2, r3")
+ TEST_UNSUPPORTED(".word 0xe12032cf @ smlawt r0, pc, r2, r3")
+ TEST_UNSUPPORTED(".word 0xe1203fc1 @ smlawt r0, r1, pc, r3")
+ TEST_UNSUPPORTED(".word 0xe120f2c1 @ smlawt r0, r1, r2, pc")
+
+ TEST_RR( "smulwb r0, r",1, VAL1,", r",2, VAL2,"")
+ TEST_RR( "smulwbge r7, r",8, VAL3,", r",9, VAL1,"")
+ TEST_R( "smulwb lr, r",1, VAL2,", r13")
+ TEST_UNSUPPORTED(".word 0xe12f02a1 @ smulwb pc, r1, r2")
+ TEST_RR( "smulwt r0, r",1, VAL1,", r",2, VAL2,"")
+ TEST_RR( "smulwtge r7, r",8, VAL3,", r",9, VAL1,"")
+ TEST_R( "smulwt lr, r",1, VAL2,", r13")
+ TEST_UNSUPPORTED(".word 0xe12f02e1 @ smulwt pc, r1, r2")
+
+ TEST_RRRR( "smlalbb r",0, VAL1,", r",1, VAL2,", r",2, VAL3,", r",3, VAL4)
+ TEST_RRRR( "smlalbble r",8, VAL4,", r",9, VAL1,", r",10,VAL2,", r",11,VAL3)
+ TEST_RRR( "smlalbb r",14,VAL3,", r",7, VAL4,", r",5, VAL1,", r13")
+ TEST_UNSUPPORTED(".word 0xe14f1382 @ smlalbb pc, r1, r2, r3")
+ TEST_UNSUPPORTED(".word 0xe141f382 @ smlalbb r1, pc, r2, r3")
+ TEST_RRRR( "smlaltb r",0, VAL1,", r",1, VAL2,", r",2, VAL3,", r",3, VAL4)
+ TEST_RRRR( "smlaltble r",8, VAL4,", r",9, VAL1,", r",10,VAL2,", r",11,VAL3)
+ TEST_RRR( "smlaltb r",14,VAL3,", r",7, VAL4,", r",5, VAL1,", r13")
+ TEST_UNSUPPORTED(".word 0xe14f13a2 @ smlaltb pc, r1, r2, r3")
+ TEST_UNSUPPORTED(".word 0xe141f3a2 @ smlaltb r1, pc, r2, r3")
+ TEST_RRRR( "smlalbt r",0, VAL1,", r",1, VAL2,", r",2, VAL3,", r",3, VAL4)
+ TEST_RRRR( "smlalbtle r",8, VAL4,", r",9, VAL1,", r",10,VAL2,", r",11,VAL3)
+ TEST_RRR( "smlalbt r",14,VAL3,", r",7, VAL4,", r",5, VAL1,", r13")
+ TEST_UNSUPPORTED(".word 0xe14f13c2 @ smlalbt pc, r1, r2, r3")
+ TEST_UNSUPPORTED(".word 0xe141f3c2 @ smlalbt r1, pc, r2, r3")
+ TEST_RRRR( "smlaltt r",0, VAL1,", r",1, VAL2,", r",2, VAL3,", r",3, VAL4)
+ TEST_RRRR( "smlalttle r",8, VAL4,", r",9, VAL1,", r",10,VAL2,", r",11,VAL3)
+ TEST_RRR( "smlaltt r",14,VAL3,", r",7, VAL4,", r",5, VAL1,", r13")
+ TEST_UNSUPPORTED(".word 0xe14f13e2 @ smlalbb pc, r1, r2, r3")
+ TEST_UNSUPPORTED(".word 0xe140f3e2 @ smlalbb r0, pc, r2, r3")
+ TEST_UNSUPPORTED(".word 0xe14013ef @ smlalbb r0, r1, pc, r3")
+ TEST_UNSUPPORTED(".word 0xe1401fe2 @ smlalbb r0, r1, r2, pc")
+
+ TEST_RR( "smulbb r0, r",1, VAL1,", r",2, VAL2,"")
+ TEST_RR( "smulbbge r7, r",8, VAL3,", r",9, VAL1,"")
+ TEST_R( "smulbb lr, r",1, VAL2,", r13")
+ TEST_UNSUPPORTED(".word 0xe16f0281 @ smulbb pc, r1, r2")
+ TEST_RR( "smultb r0, r",1, VAL1,", r",2, VAL2,"")
+ TEST_RR( "smultbge r7, r",8, VAL3,", r",9, VAL1,"")
+ TEST_R( "smultb lr, r",1, VAL2,", r13")
+ TEST_UNSUPPORTED(".word 0xe16f02a1 @ smultb pc, r1, r2")
+ TEST_RR( "smulbt r0, r",1, VAL1,", r",2, VAL2,"")
+ TEST_RR( "smulbtge r7, r",8, VAL3,", r",9, VAL1,"")
+ TEST_R( "smulbt lr, r",1, VAL2,", r13")
+ TEST_UNSUPPORTED(".word 0xe16f02c1 @ smultb pc, r1, r2")
+ TEST_RR( "smultt r0, r",1, VAL1,", r",2, VAL2,"")
+ TEST_RR( "smulttge r7, r",8, VAL3,", r",9, VAL1,"")
+ TEST_R( "smultt lr, r",1, VAL2,", r13")
+ TEST_UNSUPPORTED(".word 0xe16f02e1 @ smultt pc, r1, r2")
+ TEST_UNSUPPORTED(".word 0xe16002ef @ smultt r0, pc, r2")
+ TEST_UNSUPPORTED(".word 0xe1600fe1 @ smultt r0, r1, pc")
+
+ TEST_GROUP("Multiply and multiply-accumulate")
+
+ TEST_RR( "mul r0, r",1, VAL1,", r",2, VAL2,"")
+ TEST_RR( "mulls r7, r",8, VAL2,", r",9, VAL2,"")
+ TEST_R( "mul lr, r",4, VAL3,", r13")
+ TEST_UNSUPPORTED(".word 0xe00f0291 @ mul pc, r1, r2")
+ TEST_UNSUPPORTED(".word 0xe000029f @ mul r0, pc, r2")
+ TEST_UNSUPPORTED(".word 0xe0000f91 @ mul r0, r1, pc")
+ TEST_RR( "muls r0, r",1, VAL1,", r",2, VAL2,"")
+ TEST_RR( "mullss r7, r",8, VAL2,", r",9, VAL2,"")
+ TEST_R( "muls lr, r",4, VAL3,", r13")
+ TEST_UNSUPPORTED(".word 0xe01f0291 @ muls pc, r1, r2")
+
+ TEST_RRR( "mla r0, r",1, VAL1,", r",2, VAL2,", r",3, VAL3,"")
+ TEST_RRR( "mlahi r7, r",8, VAL3,", r",9, VAL1,", r",10, VAL2,"")
+ TEST_RR( "mla lr, r",1, VAL2,", r",2, VAL3,", r13")
+ TEST_UNSUPPORTED(".word 0xe02f3291 @ mla pc, r1, r2, r3")
+ TEST_RRR( "mlas r0, r",1, VAL1,", r",2, VAL2,", r",3, VAL3,"")
+ TEST_RRR( "mlahis r7, r",8, VAL3,", r",9, VAL1,", r",10, VAL2,"")
+ TEST_RR( "mlas lr, r",1, VAL2,", r",2, VAL3,", r13")
+ TEST_UNSUPPORTED(".word 0xe03f3291 @ mlas pc, r1, r2, r3")
+
+#if __LINUX_ARM_ARCH__ >= 6
+ TEST_RR( "umaal r0, r1, r",2, VAL1,", r",3, VAL2,"")
+ TEST_RR( "umaalls r7, r8, r",9, VAL2,", r",10, VAL1,"")
+ TEST_R( "umaal lr, r12, r",11,VAL3,", r13")
+ TEST_UNSUPPORTED(".word 0xe041f392 @ umaal pc, r1, r2, r3")
+ TEST_UNSUPPORTED(".word 0xe04f0392 @ umaal r0, pc, r2, r3")
+ TEST_UNSUPPORTED(".word 0xe0500090 @ undef")
+ TEST_UNSUPPORTED(".word 0xe05fff9f @ undef")
+
+ TEST_RRR( "mls r0, r",1, VAL1,", r",2, VAL2,", r",3, VAL3,"")
+ TEST_RRR( "mlshi r7, r",8, VAL3,", r",9, VAL1,", r",10, VAL2,"")
+ TEST_RR( "mls lr, r",1, VAL2,", r",2, VAL3,", r13")
+ TEST_UNSUPPORTED(".word 0xe06f3291 @ mls pc, r1, r2, r3")
+ TEST_UNSUPPORTED(".word 0xe060329f @ mls r0, pc, r2, r3")
+ TEST_UNSUPPORTED(".word 0xe0603f91 @ mls r0, r1, pc, r3")
+ TEST_UNSUPPORTED(".word 0xe060f291 @ mls r0, r1, r2, pc")
+#endif
+
+ TEST_UNSUPPORTED(".word 0xe0700090 @ undef")
+ TEST_UNSUPPORTED(".word 0xe07fff9f @ undef")
+
+ TEST_RR( "umull r0, r1, r",2, VAL1,", r",3, VAL2,"")
+ TEST_RR( "umullls r7, r8, r",9, VAL2,", r",10, VAL1,"")
+ TEST_R( "umull lr, r12, r",11,VAL3,", r13")
+ TEST_UNSUPPORTED(".word 0xe081f392 @ umull pc, r1, r2, r3")
+ TEST_UNSUPPORTED(".word 0xe08f1392 @ umull r1, pc, r2, r3")
+ TEST_RR( "umulls r0, r1, r",2, VAL1,", r",3, VAL2,"")
+ TEST_RR( "umulllss r7, r8, r",9, VAL2,", r",10, VAL1,"")
+ TEST_R( "umulls lr, r12, r",11,VAL3,", r13")
+ TEST_UNSUPPORTED(".word 0xe091f392 @ umulls pc, r1, r2, r3")
+ TEST_UNSUPPORTED(".word 0xe09f1392 @ umulls r1, pc, r2, r3")
+
+ TEST_RRRR( "umlal r",0, VAL1,", r",1, VAL2,", r",2, VAL3,", r",3, VAL4)
+ TEST_RRRR( "umlalle r",8, VAL4,", r",9, VAL1,", r",10,VAL2,", r",11,VAL3)
+ TEST_RRR( "umlal r",14,VAL3,", r",7, VAL4,", r",5, VAL1,", r13")
+ TEST_UNSUPPORTED(".word 0xe0af1392 @ umlal pc, r1, r2, r3")
+ TEST_UNSUPPORTED(".word 0xe0a1f392 @ umlal r1, pc, r2, r3")
+ TEST_RRRR( "umlals r",0, VAL1,", r",1, VAL2,", r",2, VAL3,", r",3, VAL4)
+ TEST_RRRR( "umlalles r",8, VAL4,", r",9, VAL1,", r",10,VAL2,", r",11,VAL3)
+ TEST_RRR( "umlals r",14,VAL3,", r",7, VAL4,", r",5, VAL1,", r13")
+ TEST_UNSUPPORTED(".word 0xe0bf1392 @ umlals pc, r1, r2, r3")
+ TEST_UNSUPPORTED(".word 0xe0b1f392 @ umlals r1, pc, r2, r3")
+
+ TEST_RR( "smull r0, r1, r",2, VAL1,", r",3, VAL2,"")
+ TEST_RR( "smullls r7, r8, r",9, VAL2,", r",10, VAL1,"")
+ TEST_R( "smull lr, r12, r",11,VAL3,", r13")
+ TEST_UNSUPPORTED(".word 0xe0c1f392 @ smull pc, r1, r2, r3")
+ TEST_UNSUPPORTED(".word 0xe0cf1392 @ smull r1, pc, r2, r3")
+ TEST_RR( "smulls r0, r1, r",2, VAL1,", r",3, VAL2,"")
+ TEST_RR( "smulllss r7, r8, r",9, VAL2,", r",10, VAL1,"")
+ TEST_R( "smulls lr, r12, r",11,VAL3,", r13")
+ TEST_UNSUPPORTED(".word 0xe0d1f392 @ smulls pc, r1, r2, r3")
+ TEST_UNSUPPORTED(".word 0xe0df1392 @ smulls r1, pc, r2, r3")
+
+ TEST_RRRR( "smlal r",0, VAL1,", r",1, VAL2,", r",2, VAL3,", r",3, VAL4)
+ TEST_RRRR( "smlalle r",8, VAL4,", r",9, VAL1,", r",10,VAL2,", r",11,VAL3)
+ TEST_RRR( "smlal r",14,VAL3,", r",7, VAL4,", r",5, VAL1,", r13")
+ TEST_UNSUPPORTED(".word 0xe0ef1392 @ smlal pc, r1, r2, r3")
+ TEST_UNSUPPORTED(".word 0xe0e1f392 @ smlal r1, pc, r2, r3")
+ TEST_RRRR( "smlals r",0, VAL1,", r",1, VAL2,", r",2, VAL3,", r",3, VAL4)
+ TEST_RRRR( "smlalles r",8, VAL4,", r",9, VAL1,", r",10,VAL2,", r",11,VAL3)
+ TEST_RRR( "smlals r",14,VAL3,", r",7, VAL4,", r",5, VAL1,", r13")
+ TEST_UNSUPPORTED(".word 0xe0ff1392 @ smlals pc, r1, r2, r3")
+ TEST_UNSUPPORTED(".word 0xe0f0f392 @ smlals r0, pc, r2, r3")
+ TEST_UNSUPPORTED(".word 0xe0f0139f @ smlals r0, r1, pc, r3")
+ TEST_UNSUPPORTED(".word 0xe0f01f92 @ smlals r0, r1, r2, pc")
+
+ TEST_GROUP("Synchronization primitives")
+
+ /*
+ * Use hard coded constants for SWP instructions to avoid warnings
+ * about deprecated instructions.
+ */
+ TEST_RP( ".word 0xe108e097 @ swp lr, r",7,VAL2,", [r",8,0,"]")
+ TEST_R( ".word 0x610d0091 @ swpvs r0, r",1,VAL1,", [sp]")
+ TEST_RP( ".word 0xe10cd09e @ swp sp, r",14,VAL2,", [r",12,13*4,"]")
+ TEST_UNSUPPORTED(".word 0xe102f091 @ swp pc, r1, [r2]")
+ TEST_UNSUPPORTED(".word 0xe102009f @ swp r0, pc, [r2]")
+ TEST_UNSUPPORTED(".word 0xe10f0091 @ swp r0, r1, [pc]")
+ TEST_RP( ".word 0xe148e097 @ swpb lr, r",7,VAL2,", [r",8,0,"]")
+ TEST_R( ".word 0x614d0091 @ swpvsb r0, r",1,VAL1,", [sp]")
+ TEST_UNSUPPORTED(".word 0xe142f091 @ swpb pc, r1, [r2]")
+
+ TEST_UNSUPPORTED(".word 0xe1100090") /* Unallocated space */
+ TEST_UNSUPPORTED(".word 0xe1200090") /* Unallocated space */
+ TEST_UNSUPPORTED(".word 0xe1300090") /* Unallocated space */
+ TEST_UNSUPPORTED(".word 0xe1500090") /* Unallocated space */
+ TEST_UNSUPPORTED(".word 0xe1600090") /* Unallocated space */
+ TEST_UNSUPPORTED(".word 0xe1700090") /* Unallocated space */
+#if __LINUX_ARM_ARCH__ >= 6
+ TEST_UNSUPPORTED("ldrex r2, [sp]")
+ TEST_UNSUPPORTED("strexd r0, r2, r3, [sp]")
+ TEST_UNSUPPORTED("ldrexd r2, r3, [sp]")
+ TEST_UNSUPPORTED("strexb r0, r2, [sp]")
+ TEST_UNSUPPORTED("ldrexb r2, [sp]")
+ TEST_UNSUPPORTED("strexh r0, r2, [sp]")
+ TEST_UNSUPPORTED("ldrexh r2, [sp]")
+#endif
+ TEST_GROUP("Extra load/store instructions")
+
+ TEST_RPR( "strh r",0, VAL1,", [r",1, 48,", -r",2, 24,"]")
+ TEST_RPR( "streqh r",14,VAL2,", [r",13,0, ", r",12, 48,"]")
+ TEST_RPR( "strh r",1, VAL1,", [r",2, 24,", r",3, 48,"]!")
+ TEST_RPR( "strneh r",12,VAL2,", [r",11,48,", -r",10,24,"]!")
+ TEST_RPR( "strh r",2, VAL1,", [r",3, 24,"], r",4, 48,"")
+ TEST_RPR( "strh r",10,VAL2,", [r",9, 48,"], -r",11,24,"")
+ TEST_UNSUPPORTED(".word 0xe1afc0ba @ strh r12, [pc, r10]!")
+ TEST_UNSUPPORTED(".word 0xe089f0bb @ strh pc, [r9], r11")
+ TEST_UNSUPPORTED(".word 0xe089a0bf @ strh r10, [r9], pc")
+
+ TEST_PR( "ldrh r0, [r",0, 48,", -r",2, 24,"]")
+ TEST_PR( "ldrcsh r14, [r",13,0, ", r",12, 48,"]")
+ TEST_PR( "ldrh r1, [r",2, 24,", r",3, 48,"]!")
+ TEST_PR( "ldrcch r12, [r",11,48,", -r",10,24,"]!")
+ TEST_PR( "ldrh r2, [r",3, 24,"], r",4, 48,"")
+ TEST_PR( "ldrh r10, [r",9, 48,"], -r",11,24,"")
+ TEST_UNSUPPORTED(".word 0xe1bfc0ba @ ldrh r12, [pc, r10]!")
+ TEST_UNSUPPORTED(".word 0xe099f0bb @ ldrh pc, [r9], r11")
+ TEST_UNSUPPORTED(".word 0xe099a0bf @ ldrh r10, [r9], pc")
+
+ TEST_RP( "strh r",0, VAL1,", [r",1, 24,", #-2]")
+ TEST_RP( "strmih r",14,VAL2,", [r",13,0, ", #2]")
+ TEST_RP( "strh r",1, VAL1,", [r",2, 24,", #4]!")
+ TEST_RP( "strplh r",12,VAL2,", [r",11,24,", #-4]!")
+ TEST_RP( "strh r",2, VAL1,", [r",3, 24,"], #48")
+ TEST_RP( "strh r",10,VAL2,", [r",9, 64,"], #-48")
+ TEST_UNSUPPORTED(".word 0xe1efc3b0 @ strh r12, [pc, #48]!")
+ TEST_UNSUPPORTED(".word 0xe0c9f3b0 @ strh pc, [r9], #48")
+
+ TEST_P( "ldrh r0, [r",0, 24,", #-2]")
+ TEST_P( "ldrvsh r14, [r",13,0, ", #2]")
+ TEST_P( "ldrh r1, [r",2, 24,", #4]!")
+ TEST_P( "ldrvch r12, [r",11,24,", #-4]!")
+ TEST_P( "ldrh r2, [r",3, 24,"], #48")
+ TEST_P( "ldrh r10, [r",9, 64,"], #-48")
+ TEST( "ldrh r0, [pc, #0]")
+ TEST_UNSUPPORTED(".word 0xe1ffc3b0 @ ldrh r12, [pc, #48]!")
+ TEST_UNSUPPORTED(".word 0xe0d9f3b0 @ ldrh pc, [r9], #48")
+
+ TEST_PR( "ldrsb r0, [r",0, 48,", -r",2, 24,"]")
+ TEST_PR( "ldrhisb r14, [r",13,0,", r",12, 48,"]")
+ TEST_PR( "ldrsb r1, [r",2, 24,", r",3, 48,"]!")
+ TEST_PR( "ldrlssb r12, [r",11,48,", -r",10,24,"]!")
+ TEST_PR( "ldrsb r2, [r",3, 24,"], r",4, 48,"")
+ TEST_PR( "ldrsb r10, [r",9, 48,"], -r",11,24,"")
+ TEST_UNSUPPORTED(".word 0xe1bfc0da @ ldrsb r12, [pc, r10]!")
+ TEST_UNSUPPORTED(".word 0xe099f0db @ ldrsb pc, [r9], r11")
+
+ TEST_P( "ldrsb r0, [r",0, 24,", #-1]")
+ TEST_P( "ldrgesb r14, [r",13,0, ", #1]")
+ TEST_P( "ldrsb r1, [r",2, 24,", #4]!")
+ TEST_P( "ldrltsb r12, [r",11,24,", #-4]!")
+ TEST_P( "ldrsb r2, [r",3, 24,"], #48")
+ TEST_P( "ldrsb r10, [r",9, 64,"], #-48")
+ TEST( "ldrsb r0, [pc, #0]")
+ TEST_UNSUPPORTED(".word 0xe1ffc3d0 @ ldrsb r12, [pc, #48]!")
+ TEST_UNSUPPORTED(".word 0xe0d9f3d0 @ ldrsb pc, [r9], #48")
+
+ TEST_PR( "ldrsh r0, [r",0, 48,", -r",2, 24,"]")
+ TEST_PR( "ldrgtsh r14, [r",13,0, ", r",12, 48,"]")
+ TEST_PR( "ldrsh r1, [r",2, 24,", r",3, 48,"]!")
+ TEST_PR( "ldrlesh r12, [r",11,48,", -r",10,24,"]!")
+ TEST_PR( "ldrsh r2, [r",3, 24,"], r",4, 48,"")
+ TEST_PR( "ldrsh r10, [r",9, 48,"], -r",11,24,"")
+ TEST_UNSUPPORTED(".word 0xe1bfc0fa @ ldrsh r12, [pc, r10]!")
+ TEST_UNSUPPORTED(".word 0xe099f0fb @ ldrsh pc, [r9], r11")
+
+ TEST_P( "ldrsh r0, [r",0, 24,", #-1]")
+ TEST_P( "ldreqsh r14, [r",13,0 ,", #1]")
+ TEST_P( "ldrsh r1, [r",2, 24,", #4]!")
+ TEST_P( "ldrnesh r12, [r",11,24,", #-4]!")
+ TEST_P( "ldrsh r2, [r",3, 24,"], #48")
+ TEST_P( "ldrsh r10, [r",9, 64,"], #-48")
+ TEST( "ldrsh r0, [pc, #0]")
+ TEST_UNSUPPORTED(".word 0xe1ffc3f0 @ ldrsh r12, [pc, #48]!")
+ TEST_UNSUPPORTED(".word 0xe0d9f3f0 @ ldrsh pc, [r9], #48")
+
+#if __LINUX_ARM_ARCH__ >= 7
+ TEST_UNSUPPORTED("strht r1, [r2], r3")
+ TEST_UNSUPPORTED("ldrht r1, [r2], r3")
+ TEST_UNSUPPORTED("strht r1, [r2], #48")
+ TEST_UNSUPPORTED("ldrht r1, [r2], #48")
+ TEST_UNSUPPORTED("ldrsbt r1, [r2], r3")
+ TEST_UNSUPPORTED("ldrsbt r1, [r2], #48")
+ TEST_UNSUPPORTED("ldrsht r1, [r2], r3")
+ TEST_UNSUPPORTED("ldrsht r1, [r2], #48")
+#endif
+
+ TEST_RPR( "strd r",0, VAL1,", [r",1, 48,", -r",2,24,"]")
+ TEST_RPR( "strccd r",8, VAL2,", [r",13,0, ", r",12,48,"]")
+ TEST_RPR( "strd r",4, VAL1,", [r",2, 24,", r",3, 48,"]!")
+ TEST_RPR( "strcsd r",12,VAL2,", [r",11,48,", -r",10,24,"]!")
+ TEST_RPR( "strd r",2, VAL1,", [r",3, 24,"], r",4,48,"")
+ TEST_RPR( "strd r",10,VAL2,", [r",9, 48,"], -r",7,24,"")
+ TEST_UNSUPPORTED(".word 0xe1afc0fa @ strd r12, [pc, r10]!")
+
+ TEST_PR( "ldrd r0, [r",0, 48,", -r",2,24,"]")
+ TEST_PR( "ldrmid r8, [r",13,0, ", r",12,48,"]")
+ TEST_PR( "ldrd r4, [r",2, 24,", r",3, 48,"]!")
+ TEST_PR( "ldrpld r6, [r",11,48,", -r",10,24,"]!")
+ TEST_PR( "ldrd r2, [r",5, 24,"], r",4,48,"")
+ TEST_PR( "ldrd r10, [r",9,48,"], -r",7,24,"")
+ TEST_UNSUPPORTED(".word 0xe1afc0da @ ldrd r12, [pc, r10]!")
+ TEST_UNSUPPORTED(".word 0xe089f0db @ ldrd pc, [r9], r11")
+ TEST_UNSUPPORTED(".word 0xe089e0db @ ldrd lr, [r9], r11")
+ TEST_UNSUPPORTED(".word 0xe089c0df @ ldrd r12, [r9], pc")
+
+ TEST_RP( "strd r",0, VAL1,", [r",1, 24,", #-8]")
+ TEST_RP( "strvsd r",8, VAL2,", [r",13,0, ", #8]")
+ TEST_RP( "strd r",4, VAL1,", [r",2, 24,", #16]!")
+ TEST_RP( "strvcd r",12,VAL2,", [r",11,24,", #-16]!")
+ TEST_RP( "strd r",2, VAL1,", [r",4, 24,"], #48")
+ TEST_RP( "strd r",10,VAL2,", [r",9, 64,"], #-48")
+ TEST_UNSUPPORTED(".word 0xe1efc3f0 @ strd r12, [pc, #48]!")
+
+ TEST_P( "ldrd r0, [r",0, 24,", #-8]")
+ TEST_P( "ldrhid r8, [r",13,0, ", #8]")
+ TEST_P( "ldrd r4, [r",2, 24,", #16]!")
+ TEST_P( "ldrlsd r6, [r",11,24,", #-16]!")
+ TEST_P( "ldrd r2, [r",5, 24,"], #48")
+ TEST_P( "ldrd r10, [r",9,6,"], #-48")
+ TEST_UNSUPPORTED(".word 0xe1efc3d0 @ ldrd r12, [pc, #48]!")
+ TEST_UNSUPPORTED(".word 0xe0c9f3d0 @ ldrd pc, [r9], #48")
+ TEST_UNSUPPORTED(".word 0xe0c9e3d0 @ ldrd lr, [r9], #48")
+
+ TEST_GROUP("Miscellaneous")
+
+#if __LINUX_ARM_ARCH__ >= 7
+ TEST("movw r0, #0")
+ TEST("movw r0, #0xffff")
+ TEST("movw lr, #0xffff")
+ TEST_UNSUPPORTED(".word 0xe300f000 @ movw pc, #0")
+ TEST_R("movt r",0, VAL1,", #0")
+ TEST_R("movt r",0, VAL2,", #0xffff")
+ TEST_R("movt r",14,VAL1,", #0xffff")
+ TEST_UNSUPPORTED(".word 0xe340f000 @ movt pc, #0")
+#endif
+
+ TEST_UNSUPPORTED("msr cpsr, 0x13")
+ TEST_UNSUPPORTED("msr cpsr_f, 0xf0000000")
+ TEST_UNSUPPORTED("msr spsr, 0x13")
+
+#if __LINUX_ARM_ARCH__ >= 7
+ TEST_SUPPORTED("yield")
+ TEST("sev")
+ TEST("nop")
+ TEST("wfi")
+ TEST_SUPPORTED("wfe")
+ TEST_UNSUPPORTED("dbg #0")
+#endif
+
+ TEST_GROUP("Load/store word and unsigned byte")
+
+#define LOAD_STORE(byte) \
+ TEST_RP( "str"byte" r",0, VAL1,", [r",1, 24,", #-2]") \
+ TEST_RP( "str"byte" r",14,VAL2,", [r",13,0, ", #2]") \
+ TEST_RP( "str"byte" r",1, VAL1,", [r",2, 24,", #4]!") \
+ TEST_RP( "str"byte" r",12,VAL2,", [r",11,24,", #-4]!") \
+ TEST_RP( "str"byte" r",2, VAL1,", [r",3, 24,"], #48") \
+ TEST_RP( "str"byte" r",10,VAL2,", [r",9, 64,"], #-48") \
+ TEST_RPR("str"byte" r",0, VAL1,", [r",1, 48,", -r",2, 24,"]") \
+ TEST_RPR("str"byte" r",14,VAL2,", [r",13,0, ", r",12, 48,"]") \
+ TEST_RPR("str"byte" r",1, VAL1,", [r",2, 24,", r",3, 48,"]!") \
+ TEST_RPR("str"byte" r",12,VAL2,", [r",11,48,", -r",10,24,"]!") \
+ TEST_RPR("str"byte" r",2, VAL1,", [r",3, 24,"], r",4, 48,"") \
+ TEST_RPR("str"byte" r",10,VAL2,", [r",9, 48,"], -r",11,24,"") \
+ TEST_RPR("str"byte" r",0, VAL1,", [r",1, 24,", r",2, 32,", asl #1]")\
+ TEST_RPR("str"byte" r",14,VAL2,", [r",13,0, ", r",12, 32,", lsr #2]")\
+ TEST_RPR("str"byte" r",1, VAL1,", [r",2, 24,", r",3, 32,", asr #3]!")\
+ TEST_RPR("str"byte" r",12,VAL2,", [r",11,24,", r",10, 4,", ror #31]!")\
+ TEST_P( "ldr"byte" r0, [r",0, 24,", #-2]") \
+ TEST_P( "ldr"byte" r14, [r",13,0, ", #2]") \
+ TEST_P( "ldr"byte" r1, [r",2, 24,", #4]!") \
+ TEST_P( "ldr"byte" r12, [r",11,24,", #-4]!") \
+ TEST_P( "ldr"byte" r2, [r",3, 24,"], #48") \
+ TEST_P( "ldr"byte" r10, [r",9, 64,"], #-48") \
+ TEST_PR( "ldr"byte" r0, [r",0, 48,", -r",2, 24,"]") \
+ TEST_PR( "ldr"byte" r14, [r",13,0, ", r",12, 48,"]") \
+ TEST_PR( "ldr"byte" r1, [r",2, 24,", r",3, 48,"]!") \
+ TEST_PR( "ldr"byte" r12, [r",11,48,", -r",10,24,"]!") \
+ TEST_PR( "ldr"byte" r2, [r",3, 24,"], r",4, 48,"") \
+ TEST_PR( "ldr"byte" r10, [r",9, 48,"], -r",11,24,"") \
+ TEST_PR( "ldr"byte" r0, [r",0, 24,", r",2, 32,", asl #1]") \
+ TEST_PR( "ldr"byte" r14, [r",13,0, ", r",12, 32,", lsr #2]") \
+ TEST_PR( "ldr"byte" r1, [r",2, 24,", r",3, 32,", asr #3]!") \
+ TEST_PR( "ldr"byte" r12, [r",11,24,", r",10, 4,", ror #31]!") \
+ TEST( "ldr"byte" r0, [pc, #0]") \
+ TEST_R( "ldr"byte" r12, [pc, r",14,0,"]")
+
+ LOAD_STORE("")
+ TEST_P( "str pc, [r",0,0,", #15*4]")
+ TEST_R( "str pc, [sp, r",2,15*4,"]")
+ TEST_BF( "ldr pc, [sp, #15*4]")
+ TEST_BF_R("ldr pc, [sp, r",2,15*4,"]")
+
+ TEST_P( "str sp, [r",0,0,", #13*4]")
+ TEST_R( "str sp, [sp, r",2,13*4,"]")
+ TEST_BF( "ldr sp, [sp, #13*4]")
+ TEST_BF_R("ldr sp, [sp, r",2,13*4,"]")
+
+#ifdef CONFIG_THUMB2_KERNEL
+ TEST_ARM_TO_THUMB_INTERWORK_P("ldr pc, [r",0,0,", #15*4]")
+#endif
+ TEST_UNSUPPORTED(".word 0xe5af6008 @ str r6, [pc, #8]!")
+ TEST_UNSUPPORTED(".word 0xe7af6008 @ str r6, [pc, r8]!")
+ TEST_UNSUPPORTED(".word 0xe5bf6008 @ ldr r6, [pc, #8]!")
+ TEST_UNSUPPORTED(".word 0xe7bf6008 @ ldr r6, [pc, r8]!")
+ TEST_UNSUPPORTED(".word 0xe788600f @ str r6, [r8, pc]")
+ TEST_UNSUPPORTED(".word 0xe798600f @ ldr r6, [r8, pc]")
+
+ LOAD_STORE("b")
+ TEST_UNSUPPORTED(".word 0xe5f7f008 @ ldrb pc, [r7, #8]!")
+ TEST_UNSUPPORTED(".word 0xe7f7f008 @ ldrb pc, [r7, r8]!")
+ TEST_UNSUPPORTED(".word 0xe5ef6008 @ strb r6, [pc, #8]!")
+ TEST_UNSUPPORTED(".word 0xe7ef6008 @ strb r6, [pc, r3]!")
+ TEST_UNSUPPORTED(".word 0xe5ff6008 @ ldrb r6, [pc, #8]!")
+ TEST_UNSUPPORTED(".word 0xe7ff6008 @ ldrb r6, [pc, r3]!")
+
+ TEST_UNSUPPORTED("ldrt r0, [r1], #4")
+ TEST_UNSUPPORTED("ldrt r1, [r2], r3")
+ TEST_UNSUPPORTED("strt r2, [r3], #4")
+ TEST_UNSUPPORTED("strt r3, [r4], r5")
+ TEST_UNSUPPORTED("ldrbt r4, [r5], #4")
+ TEST_UNSUPPORTED("ldrbt r5, [r6], r7")
+ TEST_UNSUPPORTED("strbt r6, [r7], #4")
+ TEST_UNSUPPORTED("strbt r7, [r8], r9")
+
+#if __LINUX_ARM_ARCH__ >= 7
+ TEST_GROUP("Parallel addition and subtraction, signed")
+
+ TEST_UNSUPPORTED(".word 0xe6000010") /* Unallocated space */
+ TEST_UNSUPPORTED(".word 0xe60fffff") /* Unallocated space */
+
+ TEST_RR( "sadd16 r0, r",0, HH1,", r",1, HH2,"")
+ TEST_RR( "sadd16 r14, r",12,HH2,", r",10,HH1,"")
+ TEST_UNSUPPORTED(".word 0xe61cff1a @ sadd16 pc, r12, r10")
+ TEST_RR( "sasx r0, r",0, HH1,", r",1, HH2,"")
+ TEST_RR( "sasx r14, r",12,HH2,", r",10,HH1,"")
+ TEST_UNSUPPORTED(".word 0xe61cff3a @ sasx pc, r12, r10")
+ TEST_RR( "ssax r0, r",0, HH1,", r",1, HH2,"")
+ TEST_RR( "ssax r14, r",12,HH2,", r",10,HH1,"")
+ TEST_UNSUPPORTED(".word 0xe61cff5a @ ssax pc, r12, r10")
+ TEST_RR( "ssub16 r0, r",0, HH1,", r",1, HH2,"")
+ TEST_RR( "ssub16 r14, r",12,HH2,", r",10,HH1,"")
+ TEST_UNSUPPORTED(".word 0xe61cff7a @ ssub16 pc, r12, r10")
+ TEST_RR( "sadd8 r0, r",0, HH1,", r",1, HH2,"")
+ TEST_RR( "sadd8 r14, r",12,HH2,", r",10,HH1,"")
+ TEST_UNSUPPORTED(".word 0xe61cff9a @ sadd8 pc, r12, r10")
+ TEST_UNSUPPORTED(".word 0xe61000b0") /* Unallocated space */
+ TEST_UNSUPPORTED(".word 0xe61fffbf") /* Unallocated space */
+ TEST_UNSUPPORTED(".word 0xe61000d0") /* Unallocated space */
+ TEST_UNSUPPORTED(".word 0xe61fffdf") /* Unallocated space */
+ TEST_RR( "ssub8 r0, r",0, HH1,", r",1, HH2,"")
+ TEST_RR( "ssub8 r14, r",12,HH2,", r",10,HH1,"")
+ TEST_UNSUPPORTED(".word 0xe61cfffa @ ssub8 pc, r12, r10")
+
+ TEST_RR( "qadd16 r0, r",0, HH1,", r",1, HH2,"")
+ TEST_RR( "qadd16 r14, r",12,HH2,", r",10,HH1,"")
+ TEST_UNSUPPORTED(".word 0xe62cff1a @ qadd16 pc, r12, r10")
+ TEST_RR( "qasx r0, r",0, HH1,", r",1, HH2,"")
+ TEST_RR( "qasx r14, r",12,HH2,", r",10,HH1,"")
+ TEST_UNSUPPORTED(".word 0xe62cff3a @ qasx pc, r12, r10")
+ TEST_RR( "qsax r0, r",0, HH1,", r",1, HH2,"")
+ TEST_RR( "qsax r14, r",12,HH2,", r",10,HH1,"")
+ TEST_UNSUPPORTED(".word 0xe62cff5a @ qsax pc, r12, r10")
+ TEST_RR( "qsub16 r0, r",0, HH1,", r",1, HH2,"")
+ TEST_RR( "qsub16 r14, r",12,HH2,", r",10,HH1,"")
+ TEST_UNSUPPORTED(".word 0xe62cff7a @ qsub16 pc, r12, r10")
+ TEST_RR( "qadd8 r0, r",0, HH1,", r",1, HH2,"")
+ TEST_RR( "qadd8 r14, r",12,HH2,", r",10,HH1,"")
+ TEST_UNSUPPORTED(".word 0xe62cff9a @ qadd8 pc, r12, r10")
+ TEST_UNSUPPORTED(".word 0xe62000b0") /* Unallocated space */
+ TEST_UNSUPPORTED(".word 0xe62fffbf") /* Unallocated space */
+ TEST_UNSUPPORTED(".word 0xe62000d0") /* Unallocated space */
+ TEST_UNSUPPORTED(".word 0xe62fffdf") /* Unallocated space */
+ TEST_RR( "qsub8 r0, r",0, HH1,", r",1, HH2,"")
+ TEST_RR( "qsub8 r14, r",12,HH2,", r",10,HH1,"")
+ TEST_UNSUPPORTED(".word 0xe62cfffa @ qsub8 pc, r12, r10")
+
+ TEST_RR( "shadd16 r0, r",0, HH1,", r",1, HH2,"")
+ TEST_RR( "shadd16 r14, r",12,HH2,", r",10,HH1,"")
+ TEST_UNSUPPORTED(".word 0xe63cff1a @ shadd16 pc, r12, r10")
+ TEST_RR( "shasx r0, r",0, HH1,", r",1, HH2,"")
+ TEST_RR( "shasx r14, r",12,HH2,", r",10,HH1,"")
+ TEST_UNSUPPORTED(".word 0xe63cff3a @ shasx pc, r12, r10")
+ TEST_RR( "shsax r0, r",0, HH1,", r",1, HH2,"")
+ TEST_RR( "shsax r14, r",12,HH2,", r",10,HH1,"")
+ TEST_UNSUPPORTED(".word 0xe63cff5a @ shsax pc, r12, r10")
+ TEST_RR( "shsub16 r0, r",0, HH1,", r",1, HH2,"")
+ TEST_RR( "shsub16 r14, r",12,HH2,", r",10,HH1,"")
+ TEST_UNSUPPORTED(".word 0xe63cff7a @ shsub16 pc, r12, r10")
+ TEST_RR( "shadd8 r0, r",0, HH1,", r",1, HH2,"")
+ TEST_RR( "shadd8 r14, r",12,HH2,", r",10,HH1,"")
+ TEST_UNSUPPORTED(".word 0xe63cff9a @ shadd8 pc, r12, r10")
+ TEST_UNSUPPORTED(".word 0xe63000b0") /* Unallocated space */
+ TEST_UNSUPPORTED(".word 0xe63fffbf") /* Unallocated space */
+ TEST_UNSUPPORTED(".word 0xe63000d0") /* Unallocated space */
+ TEST_UNSUPPORTED(".word 0xe63fffdf") /* Unallocated space */
+ TEST_RR( "shsub8 r0, r",0, HH1,", r",1, HH2,"")
+ TEST_RR( "shsub8 r14, r",12,HH2,", r",10,HH1,"")
+ TEST_UNSUPPORTED(".word 0xe63cfffa @ shsub8 pc, r12, r10")
+
+ TEST_GROUP("Parallel addition and subtraction, unsigned")
+
+ TEST_UNSUPPORTED(".word 0xe6400010") /* Unallocated space */
+ TEST_UNSUPPORTED(".word 0xe64fffff") /* Unallocated space */
+
+ TEST_RR( "uadd16 r0, r",0, HH1,", r",1, HH2,"")
+ TEST_RR( "uadd16 r14, r",12,HH2,", r",10,HH1,"")
+ TEST_UNSUPPORTED(".word 0xe65cff1a @ uadd16 pc, r12, r10")
+ TEST_RR( "uasx r0, r",0, HH1,", r",1, HH2,"")
+ TEST_RR( "uasx r14, r",12,HH2,", r",10,HH1,"")
+ TEST_UNSUPPORTED(".word 0xe65cff3a @ uasx pc, r12, r10")
+ TEST_RR( "usax r0, r",0, HH1,", r",1, HH2,"")
+ TEST_RR( "usax r14, r",12,HH2,", r",10,HH1,"")
+ TEST_UNSUPPORTED(".word 0xe65cff5a @ usax pc, r12, r10")
+ TEST_RR( "usub16 r0, r",0, HH1,", r",1, HH2,"")
+ TEST_RR( "usub16 r14, r",12,HH2,", r",10,HH1,"")
+ TEST_UNSUPPORTED(".word 0xe65cff7a @ usub16 pc, r12, r10")
+ TEST_RR( "uadd8 r0, r",0, HH1,", r",1, HH2,"")
+ TEST_RR( "uadd8 r14, r",12,HH2,", r",10,HH1,"")
+ TEST_UNSUPPORTED(".word 0xe65cff9a @ uadd8 pc, r12, r10")
+ TEST_UNSUPPORTED(".word 0xe65000b0") /* Unallocated space */
+ TEST_UNSUPPORTED(".word 0xe65fffbf") /* Unallocated space */
+ TEST_UNSUPPORTED(".word 0xe65000d0") /* Unallocated space */
+ TEST_UNSUPPORTED(".word 0xe65fffdf") /* Unallocated space */
+ TEST_RR( "usub8 r0, r",0, HH1,", r",1, HH2,"")
+ TEST_RR( "usub8 r14, r",12,HH2,", r",10,HH1,"")
+ TEST_UNSUPPORTED(".word 0xe65cfffa @ usub8 pc, r12, r10")
+
+ TEST_RR( "uqadd16 r0, r",0, HH1,", r",1, HH2,"")
+ TEST_RR( "uqadd16 r14, r",12,HH2,", r",10,HH1,"")
+ TEST_UNSUPPORTED(".word 0xe66cff1a @ uqadd16 pc, r12, r10")
+ TEST_RR( "uqasx r0, r",0, HH1,", r",1, HH2,"")
+ TEST_RR( "uqasx r14, r",12,HH2,", r",10,HH1,"")
+ TEST_UNSUPPORTED(".word 0xe66cff3a @ uqasx pc, r12, r10")
+ TEST_RR( "uqsax r0, r",0, HH1,", r",1, HH2,"")
+ TEST_RR( "uqsax r14, r",12,HH2,", r",10,HH1,"")
+ TEST_UNSUPPORTED(".word 0xe66cff5a @ uqsax pc, r12, r10")
+ TEST_RR( "uqsub16 r0, r",0, HH1,", r",1, HH2,"")
+ TEST_RR( "uqsub16 r14, r",12,HH2,", r",10,HH1,"")
+ TEST_UNSUPPORTED(".word 0xe66cff7a @ uqsub16 pc, r12, r10")
+ TEST_RR( "uqadd8 r0, r",0, HH1,", r",1, HH2,"")
+ TEST_RR( "uqadd8 r14, r",12,HH2,", r",10,HH1,"")
+ TEST_UNSUPPORTED(".word 0xe66cff9a @ uqadd8 pc, r12, r10")
+ TEST_UNSUPPORTED(".word 0xe66000b0") /* Unallocated space */
+ TEST_UNSUPPORTED(".word 0xe66fffbf") /* Unallocated space */
+ TEST_UNSUPPORTED(".word 0xe66000d0") /* Unallocated space */
+ TEST_UNSUPPORTED(".word 0xe66fffdf") /* Unallocated space */
+ TEST_RR( "uqsub8 r0, r",0, HH1,", r",1, HH2,"")
+ TEST_RR( "uqsub8 r14, r",12,HH2,", r",10,HH1,"")
+ TEST_UNSUPPORTED(".word 0xe66cfffa @ uqsub8 pc, r12, r10")
+
+ TEST_RR( "uhadd16 r0, r",0, HH1,", r",1, HH2,"")
+ TEST_RR( "uhadd16 r14, r",12,HH2,", r",10,HH1,"")
+ TEST_UNSUPPORTED(".word 0xe67cff1a @ uhadd16 pc, r12, r10")
+ TEST_RR( "uhasx r0, r",0, HH1,", r",1, HH2,"")
+ TEST_RR( "uhasx r14, r",12,HH2,", r",10,HH1,"")
+ TEST_UNSUPPORTED(".word 0xe67cff3a @ uhasx pc, r12, r10")
+ TEST_RR( "uhsax r0, r",0, HH1,", r",1, HH2,"")
+ TEST_RR( "uhsax r14, r",12,HH2,", r",10,HH1,"")
+ TEST_UNSUPPORTED(".word 0xe67cff5a @ uhsax pc, r12, r10")
+ TEST_RR( "uhsub16 r0, r",0, HH1,", r",1, HH2,"")
+ TEST_RR( "uhsub16 r14, r",12,HH2,", r",10,HH1,"")
+ TEST_UNSUPPORTED(".word 0xe67cff7a @ uhsub16 pc, r12, r10")
+ TEST_RR( "uhadd8 r0, r",0, HH1,", r",1, HH2,"")
+ TEST_RR( "uhadd8 r14, r",12,HH2,", r",10,HH1,"")
+ TEST_UNSUPPORTED(".word 0xe67cff9a @ uhadd8 pc, r12, r10")
+ TEST_UNSUPPORTED(".word 0xe67000b0") /* Unallocated space */
+ TEST_UNSUPPORTED(".word 0xe67fffbf") /* Unallocated space */
+ TEST_UNSUPPORTED(".word 0xe67000d0") /* Unallocated space */
+ TEST_UNSUPPORTED(".word 0xe67fffdf") /* Unallocated space */
+ TEST_RR( "uhsub8 r0, r",0, HH1,", r",1, HH2,"")
+ TEST_RR( "uhsub8 r14, r",12,HH2,", r",10,HH1,"")
+ TEST_UNSUPPORTED(".word 0xe67cfffa @ uhsub8 pc, r12, r10")
+ TEST_UNSUPPORTED(".word 0xe67feffa @ uhsub8 r14, pc, r10")
+ TEST_UNSUPPORTED(".word 0xe67cefff @ uhsub8 r14, r12, pc")
+#endif /* __LINUX_ARM_ARCH__ >= 7 */
+
+#if __LINUX_ARM_ARCH__ >= 6
+ TEST_GROUP("Packing, unpacking, saturation, and reversal")
+
+ TEST_RR( "pkhbt r0, r",0, HH1,", r",1, HH2,"")
+ TEST_RR( "pkhbt r14,r",12, HH1,", r",10,HH2,", lsl #2")
+ TEST_UNSUPPORTED(".word 0xe68cf11a @ pkhbt pc, r12, r10, lsl #2")
+ TEST_RR( "pkhtb r0, r",0, HH1,", r",1, HH2,"")
+ TEST_RR( "pkhtb r14,r",12, HH1,", r",10,HH2,", asr #2")
+ TEST_UNSUPPORTED(".word 0xe68cf15a @ pkhtb pc, r12, r10, asr #2")
+ TEST_UNSUPPORTED(".word 0xe68fe15a @ pkhtb r14, pc, r10, asr #2")
+ TEST_UNSUPPORTED(".word 0xe68ce15f @ pkhtb r14, r12, pc, asr #2")
+ TEST_UNSUPPORTED(".word 0xe6900010") /* Unallocated space */
+ TEST_UNSUPPORTED(".word 0xe69fffdf") /* Unallocated space */
+
+ TEST_R( "ssat r0, #24, r",0, VAL1,"")
+ TEST_R( "ssat r14, #24, r",12, VAL2,"")
+ TEST_R( "ssat r0, #24, r",0, VAL1,", lsl #8")
+ TEST_R( "ssat r14, #24, r",12, VAL2,", asr #8")
+ TEST_UNSUPPORTED(".word 0xe6b7f01c @ ssat pc, #24, r12")
+
+ TEST_R( "usat r0, #24, r",0, VAL1,"")
+ TEST_R( "usat r14, #24, r",12, VAL2,"")
+ TEST_R( "usat r0, #24, r",0, VAL1,", lsl #8")
+ TEST_R( "usat r14, #24, r",12, VAL2,", asr #8")
+ TEST_UNSUPPORTED(".word 0xe6f7f01c @ usat pc, #24, r12")
+
+ TEST_RR( "sxtab16 r0, r",0, HH1,", r",1, HH2,"")
+ TEST_RR( "sxtab16 r14,r",12, HH2,", r",10,HH1,", ror #8")
+ TEST_R( "sxtb16 r8, r",7, HH1,"")
+ TEST_UNSUPPORTED(".word 0xe68cf47a @ sxtab16 pc,r12, r10, ror #8")
+
+ TEST_RR( "sel r0, r",0, VAL1,", r",1, VAL2,"")
+ TEST_RR( "sel r14, r",12,VAL1,", r",10, VAL2,"")
+ TEST_UNSUPPORTED(".word 0xe68cffba @ sel pc, r12, r10")
+ TEST_UNSUPPORTED(".word 0xe68fefba @ sel r14, pc, r10")
+ TEST_UNSUPPORTED(".word 0xe68cefbf @ sel r14, r12, pc")
+
+ TEST_R( "ssat16 r0, #12, r",0, HH1,"")
+ TEST_R( "ssat16 r14, #12, r",12, HH2,"")
+ TEST_UNSUPPORTED(".word 0xe6abff3c @ ssat16 pc, #12, r12")
+
+ TEST_RR( "sxtab r0, r",0, HH1,", r",1, HH2,"")
+ TEST_RR( "sxtab r14,r",12, HH2,", r",10,HH1,", ror #8")
+ TEST_R( "sxtb r8, r",7, HH1,"")
+ TEST_UNSUPPORTED(".word 0xe6acf47a @ sxtab pc,r12, r10, ror #8")
+
+ TEST_R( "rev r0, r",0, VAL1,"")
+ TEST_R( "rev r14, r",12, VAL2,"")
+ TEST_UNSUPPORTED(".word 0xe6bfff3c @ rev pc, r12")
+
+ TEST_RR( "sxtah r0, r",0, HH1,", r",1, HH2,"")
+ TEST_RR( "sxtah r14,r",12, HH2,", r",10,HH1,", ror #8")
+ TEST_R( "sxth r8, r",7, HH1,"")
+ TEST_UNSUPPORTED(".word 0xe6bcf47a @ sxtah pc,r12, r10, ror #8")
+
+ TEST_R( "rev16 r0, r",0, VAL1,"")
+ TEST_R( "rev16 r14, r",12, VAL2,"")
+ TEST_UNSUPPORTED(".word 0xe6bfffbc @ rev16 pc, r12")
+
+ TEST_RR( "uxtab16 r0, r",0, HH1,", r",1, HH2,"")
+ TEST_RR( "uxtab16 r14,r",12, HH2,", r",10,HH1,", ror #8")
+ TEST_R( "uxtb16 r8, r",7, HH1,"")
+ TEST_UNSUPPORTED(".word 0xe6ccf47a @ uxtab16 pc,r12, r10, ror #8")
+
+ TEST_R( "usat16 r0, #12, r",0, HH1,"")
+ TEST_R( "usat16 r14, #12, r",12, HH2,"")
+ TEST_UNSUPPORTED(".word 0xe6ecff3c @ usat16 pc, #12, r12")
+ TEST_UNSUPPORTED(".word 0xe6ecef3f @ usat16 r14, #12, pc")
+
+ TEST_RR( "uxtab r0, r",0, HH1,", r",1, HH2,"")
+ TEST_RR( "uxtab r14,r",12, HH2,", r",10,HH1,", ror #8")
+ TEST_R( "uxtb r8, r",7, HH1,"")
+ TEST_UNSUPPORTED(".word 0xe6ecf47a @ uxtab pc,r12, r10, ror #8")
+
+#if __LINUX_ARM_ARCH__ >= 7
+ TEST_R( "rbit r0, r",0, VAL1,"")
+ TEST_R( "rbit r14, r",12, VAL2,"")
+ TEST_UNSUPPORTED(".word 0xe6ffff3c @ rbit pc, r12")
+#endif
+
+ TEST_RR( "uxtah r0, r",0, HH1,", r",1, HH2,"")
+ TEST_RR( "uxtah r14,r",12, HH2,", r",10,HH1,", ror #8")
+ TEST_R( "uxth r8, r",7, HH1,"")
+ TEST_UNSUPPORTED(".word 0xe6fff077 @ uxth pc, r7")
+ TEST_UNSUPPORTED(".word 0xe6ff807f @ uxth r8, pc")
+ TEST_UNSUPPORTED(".word 0xe6fcf47a @ uxtah pc, r12, r10, ror #8")
+ TEST_UNSUPPORTED(".word 0xe6fce47f @ uxtah r14, r12, pc, ror #8")
+
+ TEST_R( "revsh r0, r",0, VAL1,"")
+ TEST_R( "revsh r14, r",12, VAL2,"")
+ TEST_UNSUPPORTED(".word 0xe6ffff3c @ revsh pc, r12")
+ TEST_UNSUPPORTED(".word 0xe6ffef3f @ revsh r14, pc")
+
+ TEST_UNSUPPORTED(".word 0xe6900070") /* Unallocated space */
+ TEST_UNSUPPORTED(".word 0xe69fff7f") /* Unallocated space */
+
+ TEST_UNSUPPORTED(".word 0xe6d00070") /* Unallocated space */
+ TEST_UNSUPPORTED(".word 0xe6dfff7f") /* Unallocated space */
+#endif /* __LINUX_ARM_ARCH__ >= 6 */
+
+#if __LINUX_ARM_ARCH__ >= 6
+ TEST_GROUP("Signed multiplies")
+
+ TEST_RRR( "smlad r0, r",0, HH1,", r",1, HH2,", r",2, VAL1,"")
+ TEST_RRR( "smlad r14, r",12,HH2,", r",10,HH1,", r",8, VAL2,"")
+ TEST_UNSUPPORTED(".word 0xe70f8a1c @ smlad pc, r12, r10, r8")
+ TEST_RRR( "smladx r0, r",0, HH1,", r",1, HH2,", r",2, VAL1,"")
+ TEST_RRR( "smladx r14, r",12,HH2,", r",10,HH1,", r",8, VAL2,"")
+ TEST_UNSUPPORTED(".word 0xe70f8a3c @ smladx pc, r12, r10, r8")
+
+ TEST_RR( "smuad r0, r",0, HH1,", r",1, HH2,"")
+ TEST_RR( "smuad r14, r",12,HH2,", r",10,HH1,"")
+ TEST_UNSUPPORTED(".word 0xe70ffa1c @ smuad pc, r12, r10")
+ TEST_RR( "smuadx r0, r",0, HH1,", r",1, HH2,"")
+ TEST_RR( "smuadx r14, r",12,HH2,", r",10,HH1,"")
+ TEST_UNSUPPORTED(".word 0xe70ffa3c @ smuadx pc, r12, r10")
+
+ TEST_RRR( "smlsd r0, r",0, HH1,", r",1, HH2,", r",2, VAL1,"")
+ TEST_RRR( "smlsd r14, r",12,HH2,", r",10,HH1,", r",8, VAL2,"")
+ TEST_UNSUPPORTED(".word 0xe70f8a5c @ smlsd pc, r12, r10, r8")
+ TEST_RRR( "smlsdx r0, r",0, HH1,", r",1, HH2,", r",2, VAL1,"")
+ TEST_RRR( "smlsdx r14, r",12,HH2,", r",10,HH1,", r",8, VAL2,"")
+ TEST_UNSUPPORTED(".word 0xe70f8a7c @ smlsdx pc, r12, r10, r8")
+
+ TEST_RR( "smusd r0, r",0, HH1,", r",1, HH2,"")
+ TEST_RR( "smusd r14, r",12,HH2,", r",10,HH1,"")
+ TEST_UNSUPPORTED(".word 0xe70ffa5c @ smusd pc, r12, r10")
+ TEST_RR( "smusdx r0, r",0, HH1,", r",1, HH2,"")
+ TEST_RR( "smusdx r14, r",12,HH2,", r",10,HH1,"")
+ TEST_UNSUPPORTED(".word 0xe70ffa7c @ smusdx pc, r12, r10")
+
+ TEST_RRRR( "smlald r",0, VAL1,", r",1, VAL2, ", r",0, HH1,", r",1, HH2)
+ TEST_RRRR( "smlald r",11,VAL2,", r",10,VAL1, ", r",9, HH2,", r",8, HH1)
+ TEST_UNSUPPORTED(".word 0xe74af819 @ smlald pc, r10, r9, r8")
+ TEST_UNSUPPORTED(".word 0xe74fb819 @ smlald r11, pc, r9, r8")
+ TEST_UNSUPPORTED(".word 0xe74ab81f @ smlald r11, r10, pc, r8")
+ TEST_UNSUPPORTED(".word 0xe74abf19 @ smlald r11, r10, r9, pc")
+
+ TEST_RRRR( "smlaldx r",0, VAL1,", r",1, VAL2, ", r",0, HH1,", r",1, HH2)
+ TEST_RRRR( "smlaldx r",11,VAL2,", r",10,VAL1, ", r",9, HH2,", r",8, HH1)
+ TEST_UNSUPPORTED(".word 0xe74af839 @ smlaldx pc, r10, r9, r8")
+ TEST_UNSUPPORTED(".word 0xe74fb839 @ smlaldx r11, pc, r9, r8")
+
+ TEST_RRR( "smmla r0, r",0, VAL1,", r",1, VAL2,", r",2, VAL1,"")
+ TEST_RRR( "smmla r14, r",12,VAL2,", r",10,VAL1,", r",8, VAL2,"")
+ TEST_UNSUPPORTED(".word 0xe75f8a1c @ smmla pc, r12, r10, r8")
+ TEST_RRR( "smmlar r0, r",0, VAL1,", r",1, VAL2,", r",2, VAL1,"")
+ TEST_RRR( "smmlar r14, r",12,VAL2,", r",10,VAL1,", r",8, VAL2,"")
+ TEST_UNSUPPORTED(".word 0xe75f8a3c @ smmlar pc, r12, r10, r8")
+
+ TEST_RR( "smmul r0, r",0, VAL1,", r",1, VAL2,"")
+ TEST_RR( "smmul r14, r",12,VAL2,", r",10,VAL1,"")
+ TEST_UNSUPPORTED(".word 0xe75ffa1c @ smmul pc, r12, r10")
+ TEST_RR( "smmulr r0, r",0, VAL1,", r",1, VAL2,"")
+ TEST_RR( "smmulr r14, r",12,VAL2,", r",10,VAL1,"")
+ TEST_UNSUPPORTED(".word 0xe75ffa3c @ smmulr pc, r12, r10")
+
+ TEST_RRR( "smmls r0, r",0, VAL1,", r",1, VAL2,", r",2, VAL1,"")
+ TEST_RRR( "smmls r14, r",12,VAL2,", r",10,VAL1,", r",8, VAL2,"")
+ TEST_UNSUPPORTED(".word 0xe75f8adc @ smmls pc, r12, r10, r8")
+ TEST_RRR( "smmlsr r0, r",0, VAL1,", r",1, VAL2,", r",2, VAL1,"")
+ TEST_RRR( "smmlsr r14, r",12,VAL2,", r",10,VAL1,", r",8, VAL2,"")
+ TEST_UNSUPPORTED(".word 0xe75f8afc @ smmlsr pc, r12, r10, r8")
+ TEST_UNSUPPORTED(".word 0xe75e8aff @ smmlsr r14, pc, r10, r8")
+ TEST_UNSUPPORTED(".word 0xe75e8ffc @ smmlsr r14, r12, pc, r8")
+ TEST_UNSUPPORTED(".word 0xe75efafc @ smmlsr r14, r12, r10, pc")
+
+ TEST_RR( "usad8 r0, r",0, VAL1,", r",1, VAL2,"")
+ TEST_RR( "usad8 r14, r",12,VAL2,", r",10,VAL1,"")
+ TEST_UNSUPPORTED(".word 0xe75ffa1c @ usad8 pc, r12, r10")
+ TEST_UNSUPPORTED(".word 0xe75efa1f @ usad8 r14, pc, r10")
+ TEST_UNSUPPORTED(".word 0xe75eff1c @ usad8 r14, r12, pc")
+
+ TEST_RRR( "usada8 r0, r",0, VAL1,", r",1, VAL2,", r",2, VAL3,"")
+ TEST_RRR( "usada8 r14, r",12,VAL2,", r",10,VAL1,", r",8, VAL3,"")
+ TEST_UNSUPPORTED(".word 0xe78f8a1c @ usada8 pc, r12, r10, r8")
+ TEST_UNSUPPORTED(".word 0xe78e8a1f @ usada8 r14, pc, r10, r8")
+ TEST_UNSUPPORTED(".word 0xe78e8f1c @ usada8 r14, r12, pc, r8")
+#endif /* __LINUX_ARM_ARCH__ >= 6 */
+
+#if __LINUX_ARM_ARCH__ >= 7
+ TEST_GROUP("Bit Field")
+
+ TEST_R( "sbfx r0, r",0 , VAL1,", #0, #31")
+ TEST_R( "sbfxeq r14, r",12, VAL2,", #8, #16")
+ TEST_R( "sbfx r4, r",10, VAL1,", #16, #15")
+ TEST_UNSUPPORTED(".word 0xe7aff45c @ sbfx pc, r12, #8, #16")
+
+ TEST_R( "ubfx r0, r",0 , VAL1,", #0, #31")
+ TEST_R( "ubfxcs r14, r",12, VAL2,", #8, #16")
+ TEST_R( "ubfx r4, r",10, VAL1,", #16, #15")
+ TEST_UNSUPPORTED(".word 0xe7eff45c @ ubfx pc, r12, #8, #16")
+ TEST_UNSUPPORTED(".word 0xe7efc45f @ ubfx r12, pc, #8, #16")
+
+ TEST_R( "bfc r",0, VAL1,", #4, #20")
+ TEST_R( "bfcvs r",14,VAL2,", #4, #20")
+ TEST_R( "bfc r",7, VAL1,", #0, #31")
+ TEST_R( "bfc r",8, VAL2,", #0, #31")
+ TEST_UNSUPPORTED(".word 0xe7def01f @ bfc pc, #0, #31");
+
+ TEST_RR( "bfi r",0, VAL1,", r",0 , VAL2,", #0, #31")
+ TEST_RR( "bfipl r",12,VAL1,", r",14 , VAL2,", #4, #20")
+ TEST_UNSUPPORTED(".word 0xe7d7f21e @ bfi pc, r14, #4, #20")
+
+ TEST_UNSUPPORTED(".word 0x07f000f0") /* Permanently UNDEFINED */
+ TEST_UNSUPPORTED(".word 0x07ffffff") /* Permanently UNDEFINED */
+#endif /* __LINUX_ARM_ARCH__ >= 6 */
+
+ TEST_GROUP("Branch, branch with link, and block data transfer")
+
+ TEST_P( "stmda r",0, 16*4,", {r0}")
+ TEST_P( "stmeqda r",4, 16*4,", {r0-r15}")
+ TEST_P( "stmneda r",8, 16*4,"!, {r8-r15}")
+ TEST_P( "stmda r",12,16*4,"!, {r1,r3,r5,r7,r8-r11,r14}")
+ TEST_P( "stmda r",13,0, "!, {pc}")
+
+ TEST_P( "ldmda r",0, 16*4,", {r0}")
+ TEST_BF_P("ldmcsda r",4, 15*4,", {r0-r15}")
+ TEST_BF_P("ldmccda r",7, 15*4,"!, {r8-r15}")
+ TEST_P( "ldmda r",12,16*4,"!, {r1,r3,r5,r7,r8-r11,r14}")
+ TEST_BF_P("ldmda r",14,15*4,"!, {pc}")
+
+ TEST_P( "stmia r",0, 16*4,", {r0}")
+ TEST_P( "stmmiia r",4, 16*4,", {r0-r15}")
+ TEST_P( "stmplia r",8, 16*4,"!, {r8-r15}")
+ TEST_P( "stmia r",12,16*4,"!, {r1,r3,r5,r7,r8-r11,r14}")
+ TEST_P( "stmia r",14,0, "!, {pc}")
+
+ TEST_P( "ldmia r",0, 16*4,", {r0}")
+ TEST_BF_P("ldmvsia r",4, 0, ", {r0-r15}")
+ TEST_BF_P("ldmvcia r",7, 8*4, "!, {r8-r15}")
+ TEST_P( "ldmia r",12,16*4,"!, {r1,r3,r5,r7,r8-r11,r14}")
+ TEST_BF_P("ldmia r",14,15*4,"!, {pc}")
+
+ TEST_P( "stmdb r",0, 16*4,", {r0}")
+ TEST_P( "stmhidb r",4, 16*4,", {r0-r15}")
+ TEST_P( "stmlsdb r",8, 16*4,"!, {r8-r15}")
+ TEST_P( "stmdb r",12,16*4,"!, {r1,r3,r5,r7,r8-r11,r14}")
+ TEST_P( "stmdb r",13,4, "!, {pc}")
+
+ TEST_P( "ldmdb r",0, 16*4,", {r0}")
+ TEST_BF_P("ldmgedb r",4, 16*4,", {r0-r15}")
+ TEST_BF_P("ldmltdb r",7, 16*4,"!, {r8-r15}")
+ TEST_P( "ldmdb r",12,16*4,"!, {r1,r3,r5,r7,r8-r11,r14}")
+ TEST_BF_P("ldmdb r",14,16*4,"!, {pc}")
+
+ TEST_P( "stmib r",0, 16*4,", {r0}")
+ TEST_P( "stmgtib r",4, 16*4,", {r0-r15}")
+ TEST_P( "stmleib r",8, 16*4,"!, {r8-r15}")
+ TEST_P( "stmib r",12,16*4,"!, {r1,r3,r5,r7,r8-r11,r14}")
+ TEST_P( "stmib r",13,-4, "!, {pc}")
+
+ TEST_P( "ldmib r",0, 16*4,", {r0}")
+ TEST_BF_P("ldmeqib r",4, -4,", {r0-r15}")
+ TEST_BF_P("ldmneib r",7, 7*4,"!, {r8-r15}")
+ TEST_P( "ldmib r",12,16*4,"!, {r1,r3,r5,r7,r8-r11,r14}")
+ TEST_BF_P("ldmib r",14,14*4,"!, {pc}")
+
+ TEST_P( "stmdb r",13,16*4,"!, {r3-r12,lr}")
+ TEST_P( "stmeqdb r",13,16*4,"!, {r3-r12}")
+ TEST_P( "stmnedb r",2, 16*4,", {r3-r12,lr}")
+ TEST_P( "stmdb r",13,16*4,"!, {r2-r12,lr}")
+ TEST_P( "stmdb r",0, 16*4,", {r0-r12}")
+ TEST_P( "stmdb r",0, 16*4,", {r0-r12,lr}")
+
+ TEST_BF_P("ldmia r",13,5*4, "!, {r3-r12,pc}")
+ TEST_P( "ldmccia r",13,5*4, "!, {r3-r12}")
+ TEST_BF_P("ldmcsia r",2, 5*4, "!, {r3-r12,pc}")
+ TEST_BF_P("ldmia r",13,4*4, "!, {r2-r12,pc}")
+ TEST_P( "ldmia r",0, 16*4,", {r0-r12}")
+ TEST_P( "ldmia r",0, 16*4,", {r0-r12,lr}")
+
+#ifdef CONFIG_THUMB2_KERNEL
+ TEST_ARM_TO_THUMB_INTERWORK_P("ldmplia r",0,15*4,", {pc}")
+ TEST_ARM_TO_THUMB_INTERWORK_P("ldmmiia r",13,0,", {r0-r15}")
+#endif
+ TEST_BF("b 2f")
+ TEST_BF("bl 2f")
+ TEST_BB("b 2b")
+ TEST_BB("bl 2b")
+
+ TEST_BF("beq 2f")
+ TEST_BF("bleq 2f")
+ TEST_BB("bne 2b")
+ TEST_BB("blne 2b")
+
+ TEST_BF("bgt 2f")
+ TEST_BF("blgt 2f")
+ TEST_BB("blt 2b")
+ TEST_BB("bllt 2b")
+
+ TEST_GROUP("Supervisor Call, and coprocessor instructions")
+
+ /*
+ * We can't really test these by executing them, so all
+ * we can do is check that probes are, or are not allowed.
+ * At the moment none are allowed...
+ */
+#define TEST_COPROCESSOR(code) TEST_UNSUPPORTED(code)
+
+#define COPROCESSOR_INSTRUCTIONS_ST_LD(two,cc) \
+ TEST_COPROCESSOR("stc"two" 0, cr0, [r13, #4]") \
+ TEST_COPROCESSOR("stc"two" 0, cr0, [r13, #-4]") \
+ TEST_COPROCESSOR("stc"two" 0, cr0, [r13, #4]!") \
+ TEST_COPROCESSOR("stc"two" 0, cr0, [r13, #-4]!") \
+ TEST_COPROCESSOR("stc"two" 0, cr0, [r13], #4") \
+ TEST_COPROCESSOR("stc"two" 0, cr0, [r13], #-4") \
+ TEST_COPROCESSOR("stc"two" 0, cr0, [r13], {1}") \
+ TEST_COPROCESSOR("stc"two"l 0, cr0, [r13, #4]") \
+ TEST_COPROCESSOR("stc"two"l 0, cr0, [r13, #-4]") \
+ TEST_COPROCESSOR("stc"two"l 0, cr0, [r13, #4]!") \
+ TEST_COPROCESSOR("stc"two"l 0, cr0, [r13, #-4]!") \
+ TEST_COPROCESSOR("stc"two"l 0, cr0, [r13], #4") \
+ TEST_COPROCESSOR("stc"two"l 0, cr0, [r13], #-4") \
+ TEST_COPROCESSOR("stc"two"l 0, cr0, [r13], {1}") \
+ TEST_COPROCESSOR("ldc"two" 0, cr0, [r13, #4]") \
+ TEST_COPROCESSOR("ldc"two" 0, cr0, [r13, #-4]") \
+ TEST_COPROCESSOR("ldc"two" 0, cr0, [r13, #4]!") \
+ TEST_COPROCESSOR("ldc"two" 0, cr0, [r13, #-4]!") \
+ TEST_COPROCESSOR("ldc"two" 0, cr0, [r13], #4") \
+ TEST_COPROCESSOR("ldc"two" 0, cr0, [r13], #-4") \
+ TEST_COPROCESSOR("ldc"two" 0, cr0, [r13], {1}") \
+ TEST_COPROCESSOR("ldc"two"l 0, cr0, [r13, #4]") \
+ TEST_COPROCESSOR("ldc"two"l 0, cr0, [r13, #-4]") \
+ TEST_COPROCESSOR("ldc"two"l 0, cr0, [r13, #4]!") \
+ TEST_COPROCESSOR("ldc"two"l 0, cr0, [r13, #-4]!") \
+ TEST_COPROCESSOR("ldc"two"l 0, cr0, [r13], #4") \
+ TEST_COPROCESSOR("ldc"two"l 0, cr0, [r13], #-4") \
+ TEST_COPROCESSOR("ldc"two"l 0, cr0, [r13], {1}") \
+ \
+ TEST_COPROCESSOR( "stc"two" 0, cr0, [r15, #4]") \
+ TEST_COPROCESSOR( "stc"two" 0, cr0, [r15, #-4]") \
+ TEST_UNSUPPORTED(".word 0x"cc"daf0001 @ stc"two" 0, cr0, [r15, #4]!") \
+ TEST_UNSUPPORTED(".word 0x"cc"d2f0001 @ stc"two" 0, cr0, [r15, #-4]!") \
+ TEST_UNSUPPORTED(".word 0x"cc"caf0001 @ stc"two" 0, cr0, [r15], #4") \
+ TEST_UNSUPPORTED(".word 0x"cc"c2f0001 @ stc"two" 0, cr0, [r15], #-4") \
+ TEST_COPROCESSOR( "stc"two" 0, cr0, [r15], {1}") \
+ TEST_COPROCESSOR( "stc"two"l 0, cr0, [r15, #4]") \
+ TEST_COPROCESSOR( "stc"two"l 0, cr0, [r15, #-4]") \
+ TEST_UNSUPPORTED(".word 0x"cc"def0001 @ stc"two"l 0, cr0, [r15, #4]!") \
+ TEST_UNSUPPORTED(".word 0x"cc"d6f0001 @ stc"two"l 0, cr0, [r15, #-4]!") \
+ TEST_UNSUPPORTED(".word 0x"cc"cef0001 @ stc"two"l 0, cr0, [r15], #4") \
+ TEST_UNSUPPORTED(".word 0x"cc"c6f0001 @ stc"two"l 0, cr0, [r15], #-4") \
+ TEST_COPROCESSOR( "stc"two"l 0, cr0, [r15], {1}") \
+ TEST_COPROCESSOR( "ldc"two" 0, cr0, [r15, #4]") \
+ TEST_COPROCESSOR( "ldc"two" 0, cr0, [r15, #-4]") \
+ TEST_UNSUPPORTED(".word 0x"cc"dbf0001 @ ldc"two" 0, cr0, [r15, #4]!") \
+ TEST_UNSUPPORTED(".word 0x"cc"d3f0001 @ ldc"two" 0, cr0, [r15, #-4]!") \
+ TEST_UNSUPPORTED(".word 0x"cc"cbf0001 @ ldc"two" 0, cr0, [r15], #4") \
+ TEST_UNSUPPORTED(".word 0x"cc"c3f0001 @ ldc"two" 0, cr0, [r15], #-4") \
+ TEST_COPROCESSOR( "ldc"two" 0, cr0, [r15], {1}") \
+ TEST_COPROCESSOR( "ldc"two"l 0, cr0, [r15, #4]") \
+ TEST_COPROCESSOR( "ldc"two"l 0, cr0, [r15, #-4]") \
+ TEST_UNSUPPORTED(".word 0x"cc"dff0001 @ ldc"two"l 0, cr0, [r15, #4]!") \
+ TEST_UNSUPPORTED(".word 0x"cc"d7f0001 @ ldc"two"l 0, cr0, [r15, #-4]!") \
+ TEST_UNSUPPORTED(".word 0x"cc"cff0001 @ ldc"two"l 0, cr0, [r15], #4") \
+ TEST_UNSUPPORTED(".word 0x"cc"c7f0001 @ ldc"two"l 0, cr0, [r15], #-4") \
+ TEST_COPROCESSOR( "ldc"two"l 0, cr0, [r15], {1}")
+
+#define COPROCESSOR_INSTRUCTIONS_MC_MR(two,cc) \
+ \
+ TEST_COPROCESSOR( "mcrr"two" 0, 15, r0, r14, cr0") \
+ TEST_COPROCESSOR( "mcrr"two" 15, 0, r14, r0, cr15") \
+ TEST_UNSUPPORTED(".word 0x"cc"c4f00f0 @ mcrr"two" 0, 15, r0, r15, cr0") \
+ TEST_UNSUPPORTED(".word 0x"cc"c40ff0f @ mcrr"two" 15, 0, r15, r0, cr15") \
+ TEST_COPROCESSOR( "mrrc"two" 0, 15, r0, r14, cr0") \
+ TEST_COPROCESSOR( "mrrc"two" 15, 0, r14, r0, cr15") \
+ TEST_UNSUPPORTED(".word 0x"cc"c5f00f0 @ mrrc"two" 0, 15, r0, r15, cr0") \
+ TEST_UNSUPPORTED(".word 0x"cc"c50ff0f @ mrrc"two" 15, 0, r15, r0, cr15") \
+ TEST_COPROCESSOR( "cdp"two" 15, 15, cr15, cr15, cr15, 7") \
+ TEST_COPROCESSOR( "cdp"two" 0, 0, cr0, cr0, cr0, 0") \
+ TEST_COPROCESSOR( "mcr"two" 15, 7, r15, cr15, cr15, 7") \
+ TEST_COPROCESSOR( "mcr"two" 0, 0, r0, cr0, cr0, 0") \
+ TEST_COPROCESSOR( "mrc"two" 15, 7, r15, cr15, cr15, 7") \
+ TEST_COPROCESSOR( "mrc"two" 0, 0, r0, cr0, cr0, 0")
+
+ COPROCESSOR_INSTRUCTIONS_ST_LD("","e")
+ COPROCESSOR_INSTRUCTIONS_MC_MR("","e")
+ TEST_UNSUPPORTED("svc 0")
+ TEST_UNSUPPORTED("svc 0xffffff")
+
+ TEST_UNSUPPORTED("svc 0")
+
+ TEST_GROUP("Unconditional instruction")
+
+#if __LINUX_ARM_ARCH__ >= 6
+ TEST_UNSUPPORTED("srsda sp, 0x13")
+ TEST_UNSUPPORTED("srsdb sp, 0x13")
+ TEST_UNSUPPORTED("srsia sp, 0x13")
+ TEST_UNSUPPORTED("srsib sp, 0x13")
+ TEST_UNSUPPORTED("srsda sp!, 0x13")
+ TEST_UNSUPPORTED("srsdb sp!, 0x13")
+ TEST_UNSUPPORTED("srsia sp!, 0x13")
+ TEST_UNSUPPORTED("srsib sp!, 0x13")
+
+ TEST_UNSUPPORTED("rfeda sp")
+ TEST_UNSUPPORTED("rfedb sp")
+ TEST_UNSUPPORTED("rfeia sp")
+ TEST_UNSUPPORTED("rfeib sp")
+ TEST_UNSUPPORTED("rfeda sp!")
+ TEST_UNSUPPORTED("rfedb sp!")
+ TEST_UNSUPPORTED("rfeia sp!")
+ TEST_UNSUPPORTED("rfeib sp!")
+ TEST_UNSUPPORTED(".word 0xf81d0a00 @ rfeda pc")
+ TEST_UNSUPPORTED(".word 0xf91d0a00 @ rfedb pc")
+ TEST_UNSUPPORTED(".word 0xf89d0a00 @ rfeia pc")
+ TEST_UNSUPPORTED(".word 0xf99d0a00 @ rfeib pc")
+ TEST_UNSUPPORTED(".word 0xf83d0a00 @ rfeda pc!")
+ TEST_UNSUPPORTED(".word 0xf93d0a00 @ rfedb pc!")
+ TEST_UNSUPPORTED(".word 0xf8bd0a00 @ rfeia pc!")
+ TEST_UNSUPPORTED(".word 0xf9bd0a00 @ rfeib pc!")
+#endif /* __LINUX_ARM_ARCH__ >= 6 */
+
+#if __LINUX_ARM_ARCH__ >= 6
+ TEST_X( "blx __dummy_thumb_subroutine_even",
+ ".thumb \n\t"
+ ".space 4 \n\t"
+ ".type __dummy_thumb_subroutine_even, %%function \n\t"
+ "__dummy_thumb_subroutine_even: \n\t"
+ "mov r0, pc \n\t"
+ "bx lr \n\t"
+ ".arm \n\t"
+ )
+ TEST( "blx __dummy_thumb_subroutine_even")
+
+ TEST_X( "blx __dummy_thumb_subroutine_odd",
+ ".thumb \n\t"
+ ".space 2 \n\t"
+ ".type __dummy_thumb_subroutine_odd, %%function \n\t"
+ "__dummy_thumb_subroutine_odd: \n\t"
+ "mov r0, pc \n\t"
+ "bx lr \n\t"
+ ".arm \n\t"
+ )
+ TEST( "blx __dummy_thumb_subroutine_odd")
+#endif /* __LINUX_ARM_ARCH__ >= 6 */
+
+ COPROCESSOR_INSTRUCTIONS_ST_LD("2","f")
+#if __LINUX_ARM_ARCH__ >= 6
+ COPROCESSOR_INSTRUCTIONS_MC_MR("2","f")
+#endif
+
+ TEST_GROUP("Miscellaneous instructions, memory hints, and Advanced SIMD instructions")
+
+#if __LINUX_ARM_ARCH__ >= 6
+ TEST_UNSUPPORTED("cps 0x13")
+ TEST_UNSUPPORTED("cpsie i")
+ TEST_UNSUPPORTED("cpsid i")
+ TEST_UNSUPPORTED("cpsie i,0x13")
+ TEST_UNSUPPORTED("cpsid i,0x13")
+ TEST_UNSUPPORTED("setend le")
+ TEST_UNSUPPORTED("setend be")
+#endif
+
+#if __LINUX_ARM_ARCH__ >= 7
+ TEST_P("pli [r",0,0b,", #16]")
+ TEST( "pli [pc, #0]")
+ TEST_RR("pli [r",12,0b,", r",0, 16,"]")
+ TEST_RR("pli [r",0, 0b,", -r",12,16,", lsl #4]")
+#endif
+
+#if __LINUX_ARM_ARCH__ >= 5
+ TEST_P("pld [r",0,32,", #-16]")
+ TEST( "pld [pc, #0]")
+ TEST_PR("pld [r",7, 24, ", r",0, 16,"]")
+ TEST_PR("pld [r",8, 24, ", -r",12,16,", lsl #4]")
+#endif
+
+#if __LINUX_ARM_ARCH__ >= 7
+ TEST_SUPPORTED( ".word 0xf590f000 @ pldw [r0, #0]")
+ TEST_SUPPORTED( ".word 0xf797f000 @ pldw [r7, r0]")
+ TEST_SUPPORTED( ".word 0xf798f18c @ pldw [r8, r12, lsl #3]");
+#endif
+
+#if __LINUX_ARM_ARCH__ >= 7
+ TEST_UNSUPPORTED("clrex")
+ TEST_UNSUPPORTED("dsb")
+ TEST_UNSUPPORTED("dmb")
+ TEST_UNSUPPORTED("isb")
+#endif
+
+ verbose("\n");
+}
+
diff --git a/arch/arm/kernel/kprobes-test-thumb.c b/arch/arm/kernel/kprobes-test-thumb.c
new file mode 100644
index 0000000..5e726c3
--- /dev/null
+++ b/arch/arm/kernel/kprobes-test-thumb.c
@@ -0,0 +1,1187 @@
+/*
+ * arch/arm/kernel/kprobes-test-thumb.c
+ *
+ * Copyright (C) 2011 Jon Medhurst <tixy@yxit.co.uk>.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+
+#include "kprobes-test.h"
+
+
+#define TEST_ISA "16"
+
+#define DONT_TEST_IN_ITBLOCK(tests) \
+ kprobe_test_flags |= TEST_FLAG_NO_ITBLOCK; \
+ tests \
+ kprobe_test_flags &= ~TEST_FLAG_NO_ITBLOCK;
+
+#define CONDITION_INSTRUCTIONS(cc_pos, tests) \
+ kprobe_test_cc_position = cc_pos; \
+ DONT_TEST_IN_ITBLOCK(tests) \
+ kprobe_test_cc_position = 0;
+
+#define TEST_ITBLOCK(code) \
+ kprobe_test_flags |= TEST_FLAG_FULL_ITBLOCK; \
+ TESTCASE_START(code) \
+ TEST_ARG_END("") \
+ "50: nop \n\t" \
+ "1: "code" \n\t" \
+ " mov r1, #0x11 \n\t" \
+ " mov r2, #0x22 \n\t" \
+ " mov r3, #0x33 \n\t" \
+ "2: nop \n\t" \
+ TESTCASE_END \
+ kprobe_test_flags &= ~TEST_FLAG_FULL_ITBLOCK;
+
+#define TEST_THUMB_TO_ARM_INTERWORK_P(code1, reg, val, code2) \
+ TESTCASE_START(code1 #reg code2) \
+ TEST_ARG_PTR(reg, val) \
+ TEST_ARG_REG(14, 99f+1) \
+ TEST_ARG_MEM(15, 3f) \
+ TEST_ARG_END("") \
+ " nop \n\t" /* To align 1f */ \
+ "50: nop \n\t" \
+ "1: "code1 #reg code2" \n\t" \
+ " bx lr \n\t" \
+ ".arm \n\t" \
+ "3: adr lr, 2f+1 \n\t" \
+ " bx lr \n\t" \
+ ".thumb \n\t" \
+ "2: nop \n\t" \
+ TESTCASE_END
+
+
+void kprobe_thumb16_test_cases(void)
+{
+ kprobe_test_flags = TEST_FLAG_NARROW_INSTR;
+
+ TEST_GROUP("Shift (immediate), add, subtract, move, and compare")
+
+ TEST_R( "lsls r7, r",0,VAL1,", #5")
+ TEST_R( "lsls r0, r",7,VAL2,", #11")
+ TEST_R( "lsrs r7, r",0,VAL1,", #5")
+ TEST_R( "lsrs r0, r",7,VAL2,", #11")
+ TEST_R( "asrs r7, r",0,VAL1,", #5")
+ TEST_R( "asrs r0, r",7,VAL2,", #11")
+ TEST_RR( "adds r2, r",0,VAL1,", r",7,VAL2,"")
+ TEST_RR( "adds r5, r",7,VAL2,", r",0,VAL2,"")
+ TEST_RR( "subs r2, r",0,VAL1,", r",7,VAL2,"")
+ TEST_RR( "subs r5, r",7,VAL2,", r",0,VAL2,"")
+ TEST_R( "adds r7, r",0,VAL1,", #5")
+ TEST_R( "adds r0, r",7,VAL2,", #2")
+ TEST_R( "subs r7, r",0,VAL1,", #5")
+ TEST_R( "subs r0, r",7,VAL2,", #2")
+ TEST( "movs.n r0, #0x5f")
+ TEST( "movs.n r7, #0xa0")
+ TEST_R( "cmp.n r",0,0x5e, ", #0x5f")
+ TEST_R( "cmp.n r",5,0x15f,", #0x5f")
+ TEST_R( "cmp.n r",7,0xa0, ", #0xa0")
+ TEST_R( "adds.n r",0,VAL1,", #0x5f")
+ TEST_R( "adds.n r",7,VAL2,", #0xa0")
+ TEST_R( "subs.n r",0,VAL1,", #0x5f")
+ TEST_R( "subs.n r",7,VAL2,", #0xa0")
+
+ TEST_GROUP("16-bit Thumb data-processing instructions")
+
+#define DATA_PROCESSING16(op,val) \
+ TEST_RR( op" r",0,VAL1,", r",7,val,"") \
+ TEST_RR( op" r",7,VAL2,", r",0,val,"")
+
+ DATA_PROCESSING16("ands",0xf00f00ff)
+ DATA_PROCESSING16("eors",0xf00f00ff)
+ DATA_PROCESSING16("lsls",11)
+ DATA_PROCESSING16("lsrs",11)
+ DATA_PROCESSING16("asrs",11)
+ DATA_PROCESSING16("adcs",VAL2)
+ DATA_PROCESSING16("sbcs",VAL2)
+ DATA_PROCESSING16("rors",11)
+ DATA_PROCESSING16("tst",0xf00f00ff)
+ TEST_R("rsbs r",0,VAL1,", #0")
+ TEST_R("rsbs r",7,VAL2,", #0")
+ DATA_PROCESSING16("cmp",0xf00f00ff)
+ DATA_PROCESSING16("cmn",0xf00f00ff)
+ DATA_PROCESSING16("orrs",0xf00f00ff)
+ DATA_PROCESSING16("muls",VAL2)
+ DATA_PROCESSING16("bics",0xf00f00ff)
+ DATA_PROCESSING16("mvns",VAL2)
+
+ TEST_GROUP("Special data instructions and branch and exchange")
+
+ TEST_RR( "add r",0, VAL1,", r",7,VAL2,"")
+ TEST_RR( "add r",3, VAL2,", r",8,VAL3,"")
+ TEST_RR( "add r",8, VAL3,", r",0,VAL1,"")
+ TEST_R( "add sp" ", r",8,-8, "")
+ TEST_R( "add r",14,VAL1,", pc")
+ TEST_BF_R("add pc" ", r",0,2f-1f-8,"")
+ TEST_UNSUPPORTED(".short 0x44ff @ add pc, pc")
+
+ TEST_RR( "cmp r",3,VAL1,", r",8,VAL2,"")
+ TEST_RR( "cmp r",8,VAL2,", r",0,VAL1,"")
+ TEST_R( "cmp sp" ", r",8,-8, "")
+
+ TEST_R( "mov r0, r",7,VAL2,"")
+ TEST_R( "mov r3, r",8,VAL3,"")
+ TEST_R( "mov r8, r",0,VAL1,"")
+ TEST_P( "mov sp, r",8,-8, "")
+ TEST( "mov lr, pc")
+ TEST_BF_R("mov pc, r",0,2f, "")
+
+ TEST_BF_R("bx r",0, 2f+1,"")
+ TEST_BF_R("bx r",14,2f+1,"")
+ TESTCASE_START("bx pc")
+ TEST_ARG_REG(14, 99f+1)
+ TEST_ARG_END("")
+ " nop \n\t" /* To align the bx pc*/
+ "50: nop \n\t"
+ "1: bx pc \n\t"
+ " bx lr \n\t"
+ ".arm \n\t"
+ " adr lr, 2f+1 \n\t"
+ " bx lr \n\t"
+ ".thumb \n\t"
+ "2: nop \n\t"
+ TESTCASE_END
+
+ TEST_BF_R("blx r",0, 2f+1,"")
+ TEST_BB_R("blx r",14,2f+1,"")
+ TEST_UNSUPPORTED(".short 0x47f8 @ blx pc")
+
+ TEST_GROUP("Load from Literal Pool")
+
+ TEST_X( "ldr r0, 3f",
+ ".align \n\t"
+ "3: .word "__stringify(VAL1))
+ TEST_X( "ldr r7, 3f",
+ ".space 128 \n\t"
+ ".align \n\t"
+ "3: .word "__stringify(VAL2))
+
+ TEST_GROUP("16-bit Thumb Load/store instructions")
+
+ TEST_RPR("str r",0, VAL1,", [r",1, 24,", r",2, 48,"]")
+ TEST_RPR("str r",7, VAL2,", [r",6, 24,", r",5, 48,"]")
+ TEST_RPR("strh r",0, VAL1,", [r",1, 24,", r",2, 48,"]")
+ TEST_RPR("strh r",7, VAL2,", [r",6, 24,", r",5, 48,"]")
+ TEST_RPR("strb r",0, VAL1,", [r",1, 24,", r",2, 48,"]")
+ TEST_RPR("strb r",7, VAL2,", [r",6, 24,", r",5, 48,"]")
+ TEST_PR( "ldrsb r0, [r",1, 24,", r",2, 48,"]")
+ TEST_PR( "ldrsb r7, [r",6, 24,", r",5, 50,"]")
+ TEST_PR( "ldr r0, [r",1, 24,", r",2, 48,"]")
+ TEST_PR( "ldr r7, [r",6, 24,", r",5, 48,"]")
+ TEST_PR( "ldrh r0, [r",1, 24,", r",2, 48,"]")
+ TEST_PR( "ldrh r7, [r",6, 24,", r",5, 50,"]")
+ TEST_PR( "ldrb r0, [r",1, 24,", r",2, 48,"]")
+ TEST_PR( "ldrb r7, [r",6, 24,", r",5, 50,"]")
+ TEST_PR( "ldrsh r0, [r",1, 24,", r",2, 48,"]")
+ TEST_PR( "ldrsh r7, [r",6, 24,", r",5, 50,"]")
+
+ TEST_RP("str r",0, VAL1,", [r",1, 24,", #120]")
+ TEST_RP("str r",7, VAL2,", [r",6, 24,", #120]")
+ TEST_P( "ldr r0, [r",1, 24,", #120]")
+ TEST_P( "ldr r7, [r",6, 24,", #120]")
+ TEST_RP("strb r",0, VAL1,", [r",1, 24,", #30]")
+ TEST_RP("strb r",7, VAL2,", [r",6, 24,", #30]")
+ TEST_P( "ldrb r0, [r",1, 24,", #30]")
+ TEST_P( "ldrb r7, [r",6, 24,", #30]")
+ TEST_RP("strh r",0, VAL1,", [r",1, 24,", #60]")
+ TEST_RP("strh r",7, VAL2,", [r",6, 24,", #60]")
+ TEST_P( "ldrh r0, [r",1, 24,", #60]")
+ TEST_P( "ldrh r7, [r",6, 24,", #60]")
+
+ TEST_R( "str r",0, VAL1,", [sp, #0]")
+ TEST_R( "str r",7, VAL2,", [sp, #160]")
+ TEST( "ldr r0, [sp, #0]")
+ TEST( "ldr r7, [sp, #160]")
+
+ TEST_RP("str r",0, VAL1,", [r",0, 24,"]")
+ TEST_P( "ldr r0, [r",0, 24,"]")
+
+ TEST_GROUP("Generate PC-/SP-relative address")
+
+ TEST("add r0, pc, #4")
+ TEST("add r7, pc, #1020")
+ TEST("add r0, sp, #4")
+ TEST("add r7, sp, #1020")
+
+ TEST_GROUP("Miscellaneous 16-bit instructions")
+
+ TEST_UNSUPPORTED( "cpsie i")
+ TEST_UNSUPPORTED( "cpsid i")
+ TEST_UNSUPPORTED( "setend le")
+ TEST_UNSUPPORTED( "setend be")
+
+ TEST("add sp, #"__stringify(TEST_MEMORY_SIZE)) /* Assumes TEST_MEMORY_SIZE < 0x400 */
+ TEST("sub sp, #0x7f*4")
+
+DONT_TEST_IN_ITBLOCK(
+ TEST_BF_R( "cbnz r",0,0, ", 2f")
+ TEST_BF_R( "cbz r",2,-1,", 2f")
+ TEST_BF_RX( "cbnz r",4,1, ", 2f",0x20)
+ TEST_BF_RX( "cbz r",7,0, ", 2f",0x40)
+)
+ TEST_R("sxth r0, r",7, HH1,"")
+ TEST_R("sxth r7, r",0, HH2,"")
+ TEST_R("sxtb r0, r",7, HH1,"")
+ TEST_R("sxtb r7, r",0, HH2,"")
+ TEST_R("uxth r0, r",7, HH1,"")
+ TEST_R("uxth r7, r",0, HH2,"")
+ TEST_R("uxtb r0, r",7, HH1,"")
+ TEST_R("uxtb r7, r",0, HH2,"")
+ TEST_R("rev r0, r",7, VAL1,"")
+ TEST_R("rev r7, r",0, VAL2,"")
+ TEST_R("rev16 r0, r",7, VAL1,"")
+ TEST_R("rev16 r7, r",0, VAL2,"")
+ TEST_UNSUPPORTED(".short 0xba80")
+ TEST_UNSUPPORTED(".short 0xbabf")
+ TEST_R("revsh r0, r",7, VAL1,"")
+ TEST_R("revsh r7, r",0, VAL2,"")
+
+#define TEST_POPPC(code, offset) \
+ TESTCASE_START(code) \
+ TEST_ARG_PTR(13, offset) \
+ TEST_ARG_END("") \
+ TEST_BRANCH_F(code,0) \
+ TESTCASE_END
+
+ TEST("push {r0}")
+ TEST("push {r7}")
+ TEST("push {r14}")
+ TEST("push {r0-r7,r14}")
+ TEST("push {r0,r2,r4,r6,r14}")
+ TEST("push {r1,r3,r5,r7}")
+ TEST("pop {r0}")
+ TEST("pop {r7}")
+ TEST("pop {r0,r2,r4,r6}")
+ TEST_POPPC("pop {pc}",15*4)
+ TEST_POPPC("pop {r0-r7,pc}",7*4)
+ TEST_POPPC("pop {r1,r3,r5,r7,pc}",11*4)
+ TEST_THUMB_TO_ARM_INTERWORK_P("pop {pc} @ ",13,15*4,"")
+ TEST_THUMB_TO_ARM_INTERWORK_P("pop {r0-r7,pc} @ ",13,7*4,"")
+
+ TEST_UNSUPPORTED("bkpt.n 0")
+ TEST_UNSUPPORTED("bkpt.n 255")
+
+ TEST_SUPPORTED("yield")
+ TEST("sev")
+ TEST("nop")
+ TEST("wfi")
+ TEST_SUPPORTED("wfe")
+ TEST_UNSUPPORTED(".short 0xbf50") /* Unassigned hints */
+ TEST_UNSUPPORTED(".short 0xbff0") /* Unassigned hints */
+
+#define TEST_IT(code, code2) \
+ TESTCASE_START(code) \
+ TEST_ARG_END("") \
+ "50: nop \n\t" \
+ "1: "code" \n\t" \
+ " "code2" \n\t" \
+ "2: nop \n\t" \
+ TESTCASE_END
+
+DONT_TEST_IN_ITBLOCK(
+ TEST_IT("it eq","moveq r0,#0")
+ TEST_IT("it vc","movvc r0,#0")
+ TEST_IT("it le","movle r0,#0")
+ TEST_IT("ite eq","moveq r0,#0\n\t movne r1,#1")
+ TEST_IT("itet vc","movvc r0,#0\n\t movvs r1,#1\n\t movvc r2,#2")
+ TEST_IT("itete le","movle r0,#0\n\t movgt r1,#1\n\t movle r2,#2\n\t movgt r3,#3")
+ TEST_IT("itttt le","movle r0,#0\n\t movle r1,#1\n\t movle r2,#2\n\t movle r3,#3")
+ TEST_IT("iteee le","movle r0,#0\n\t movgt r1,#1\n\t movgt r2,#2\n\t movgt r3,#3")
+)
+
+ TEST_GROUP("Load and store multiple")
+
+ TEST_P("ldmia r",4, 16*4,"!, {r0,r7}")
+ TEST_P("ldmia r",7, 16*4,"!, {r0-r6}")
+ TEST_P("stmia r",4, 16*4,"!, {r0,r7}")
+ TEST_P("stmia r",0, 16*4,"!, {r0-r7}")
+
+ TEST_GROUP("Conditional branch and Supervisor Call instructions")
+
+CONDITION_INSTRUCTIONS(8,
+ TEST_BF("beq 2f")
+ TEST_BB("bne 2b")
+ TEST_BF("bgt 2f")
+ TEST_BB("blt 2b")
+)
+ TEST_UNSUPPORTED(".short 0xde00")
+ TEST_UNSUPPORTED(".short 0xdeff")
+ TEST_UNSUPPORTED("svc #0x00")
+ TEST_UNSUPPORTED("svc #0xff")
+
+ TEST_GROUP("Unconditional branch")
+
+ TEST_BF( "b 2f")
+ TEST_BB( "b 2b")
+ TEST_BF_X("b 2f", 0x400)
+ TEST_BB_X("b 2b", 0x400)
+
+ TEST_GROUP("Testing instructions in IT blocks")
+
+ TEST_ITBLOCK("subs.n r0, r0")
+
+ verbose("\n");
+}
+
+
+void kprobe_thumb32_test_cases(void)
+{
+ kprobe_test_flags = 0;
+
+ TEST_GROUP("Load/store multiple")
+
+ TEST_UNSUPPORTED("rfedb sp")
+ TEST_UNSUPPORTED("rfeia sp")
+ TEST_UNSUPPORTED("rfedb sp!")
+ TEST_UNSUPPORTED("rfeia sp!")
+
+ TEST_P( "stmia r",0, 16*4,", {r0,r8}")
+ TEST_P( "stmia r",4, 16*4,", {r0-r12,r14}")
+ TEST_P( "stmia r",7, 16*4,"!, {r8-r12,r14}")
+ TEST_P( "stmia r",12,16*4,"!, {r1,r3,r5,r7,r8-r11,r14}")
+
+ TEST_P( "ldmia r",0, 16*4,", {r0,r8}")
+ TEST_P( "ldmia r",4, 0, ", {r0-r12,r14}")
+ TEST_BF_P("ldmia r",5, 8*4, "!, {r6-r12,r15}")
+ TEST_P( "ldmia r",12,16*4,"!, {r1,r3,r5,r7,r8-r11,r14}")
+ TEST_BF_P("ldmia r",14,14*4,"!, {r4,pc}")
+
+ TEST_P( "stmdb r",0, 16*4,", {r0,r8}")
+ TEST_P( "stmdb r",4, 16*4,", {r0-r12,r14}")
+ TEST_P( "stmdb r",5, 16*4,"!, {r8-r12,r14}")
+ TEST_P( "stmdb r",12,16*4,"!, {r1,r3,r5,r7,r8-r11,r14}")
+
+ TEST_P( "ldmdb r",0, 16*4,", {r0,r8}")
+ TEST_P( "ldmdb r",4, 16*4,", {r0-r12,r14}")
+ TEST_BF_P("ldmdb r",5, 16*4,"!, {r6-r12,r15}")
+ TEST_P( "ldmdb r",12,16*4,"!, {r1,r3,r5,r7,r8-r11,r14}")
+ TEST_BF_P("ldmdb r",14,16*4,"!, {r4,pc}")
+
+ TEST_P( "stmdb r",13,16*4,"!, {r3-r12,lr}")
+ TEST_P( "stmdb r",13,16*4,"!, {r3-r12}")
+ TEST_P( "stmdb r",2, 16*4,", {r3-r12,lr}")
+ TEST_P( "stmdb r",13,16*4,"!, {r2-r12,lr}")
+ TEST_P( "stmdb r",0, 16*4,", {r0-r12}")
+ TEST_P( "stmdb r",0, 16*4,", {r0-r12,lr}")
+
+ TEST_BF_P("ldmia r",13,5*4, "!, {r3-r12,pc}")
+ TEST_P( "ldmia r",13,5*4, "!, {r3-r12}")
+ TEST_BF_P("ldmia r",2, 5*4, "!, {r3-r12,pc}")
+ TEST_BF_P("ldmia r",13,4*4, "!, {r2-r12,pc}")
+ TEST_P( "ldmia r",0, 16*4,", {r0-r12}")
+ TEST_P( "ldmia r",0, 16*4,", {r0-r12,lr}")
+
+ TEST_THUMB_TO_ARM_INTERWORK_P("ldmia r",0,14*4,", {r12,pc}")
+ TEST_THUMB_TO_ARM_INTERWORK_P("ldmia r",13,2*4,", {r0-r12,pc}")
+
+ TEST_UNSUPPORTED(".short 0xe88f,0x0101 @ stmia pc, {r0,r8}")
+ TEST_UNSUPPORTED(".short 0xe92f,0x5f00 @ stmdb pc!, {r8-r12,r14}")
+ TEST_UNSUPPORTED(".short 0xe8bd,0xc000 @ ldmia r13!, {r14,pc}")
+ TEST_UNSUPPORTED(".short 0xe93e,0xc000 @ ldmdb r14!, {r14,pc}")
+ TEST_UNSUPPORTED(".short 0xe8a7,0x3f00 @ stmia r7!, {r8-r12,sp}")
+ TEST_UNSUPPORTED(".short 0xe8a7,0x9f00 @ stmia r7!, {r8-r12,pc}")
+ TEST_UNSUPPORTED(".short 0xe93e,0x2010 @ ldmdb r14!, {r4,sp}")
+
+ TEST_GROUP("Load/store double or exclusive, table branch")
+
+ TEST_P( "ldrd r0, r1, [r",1, 24,", #-16]")
+ TEST( "ldrd r12, r14, [sp, #16]")
+ TEST_P( "ldrd r1, r0, [r",7, 24,", #-16]!")
+ TEST( "ldrd r14, r12, [sp, #16]!")
+ TEST_P( "ldrd r1, r0, [r",7, 24,"], #16")
+ TEST( "ldrd r7, r8, [sp], #-16")
+
+ TEST_X( "ldrd r12, r14, 3f",
+ ".align 3 \n\t"
+ "3: .word "__stringify(VAL1)" \n\t"
+ " .word "__stringify(VAL2))
+
+ TEST_UNSUPPORTED(".short 0xe9ff,0xec04 @ ldrd r14, r12, [pc, #16]!")
+ TEST_UNSUPPORTED(".short 0xe8ff,0xec04 @ ldrd r14, r12, [pc], #16")
+ TEST_UNSUPPORTED(".short 0xe9d4,0xd800 @ ldrd sp, r8, [r4]")
+ TEST_UNSUPPORTED(".short 0xe9d4,0xf800 @ ldrd pc, r8, [r4]")
+ TEST_UNSUPPORTED(".short 0xe9d4,0x7d00 @ ldrd r7, sp, [r4]")
+ TEST_UNSUPPORTED(".short 0xe9d4,0x7f00 @ ldrd r7, pc, [r4]")
+
+ TEST_RRP("strd r",0, VAL1,", r",1, VAL2,", [r",1, 24,", #-16]")
+ TEST_RR( "strd r",12,VAL2,", r",14,VAL1,", [sp, #16]")
+ TEST_RRP("strd r",1, VAL1,", r",0, VAL2,", [r",7, 24,", #-16]!")
+ TEST_RR( "strd r",14,VAL2,", r",12,VAL1,", [sp, #16]!")
+ TEST_RRP("strd r",1, VAL1,", r",0, VAL2,", [r",7, 24,"], #16")
+ TEST_RR( "strd r",7, VAL2,", r",8, VAL1,", [sp], #-16")
+ TEST_UNSUPPORTED(".short 0xe9ef,0xec04 @ strd r14, r12, [pc, #16]!")
+ TEST_UNSUPPORTED(".short 0xe8ef,0xec04 @ strd r14, r12, [pc], #16")
+
+ TEST_RX("tbb [pc, r",0, (9f-(1f+4)),"]",
+ "9: \n\t"
+ ".byte (2f-1b-4)>>1 \n\t"
+ ".byte (3f-1b-4)>>1 \n\t"
+ "3: mvn r0, r0 \n\t"
+ "2: nop \n\t")
+
+ TEST_RX("tbb [pc, r",4, (9f-(1f+4)+1),"]",
+ "9: \n\t"
+ ".byte (2f-1b-4)>>1 \n\t"
+ ".byte (3f-1b-4)>>1 \n\t"
+ "3: mvn r0, r0 \n\t"
+ "2: nop \n\t")
+
+ TEST_RRX("tbb [r",1,9f,", r",2,0,"]",
+ "9: \n\t"
+ ".byte (2f-1b-4)>>1 \n\t"
+ ".byte (3f-1b-4)>>1 \n\t"
+ "3: mvn r0, r0 \n\t"
+ "2: nop \n\t")
+
+ TEST_RX("tbh [pc, r",7, (9f-(1f+4))>>1,"]",
+ "9: \n\t"
+ ".short (2f-1b-4)>>1 \n\t"
+ ".short (3f-1b-4)>>1 \n\t"
+ "3: mvn r0, r0 \n\t"
+ "2: nop \n\t")
+
+ TEST_RX("tbh [pc, r",12, ((9f-(1f+4))>>1)+1,"]",
+ "9: \n\t"
+ ".short (2f-1b-4)>>1 \n\t"
+ ".short (3f-1b-4)>>1 \n\t"
+ "3: mvn r0, r0 \n\t"
+ "2: nop \n\t")
+
+ TEST_RRX("tbh [r",1,9f, ", r",14,1,"]",
+ "9: \n\t"
+ ".short (2f-1b-4)>>1 \n\t"
+ ".short (3f-1b-4)>>1 \n\t"
+ "3: mvn r0, r0 \n\t"
+ "2: nop \n\t")
+
+ TEST_UNSUPPORTED(".short 0xe8d1,0xf01f @ tbh [r1, pc]")
+ TEST_UNSUPPORTED(".short 0xe8d1,0xf01d @ tbh [r1, sp]")
+ TEST_UNSUPPORTED(".short 0xe8dd,0xf012 @ tbh [sp, r2]")
+
+ TEST_UNSUPPORTED("strexb r0, r1, [r2]")
+ TEST_UNSUPPORTED("strexh r0, r1, [r2]")
+ TEST_UNSUPPORTED("strexd r0, r1, [r2]")
+ TEST_UNSUPPORTED("ldrexb r0, [r1]")
+ TEST_UNSUPPORTED("ldrexh r0, [r1]")
+ TEST_UNSUPPORTED("ldrexd r0, [r1]")
+
+ TEST_GROUP("Data-processing (shifted register) and (modified immediate)")
+
+#define _DATA_PROCESSING32_DNM(op,s,val) \
+ TEST_RR(op s".w r0, r",1, VAL1,", r",2, val, "") \
+ TEST_RR(op s" r1, r",1, VAL1,", r",2, val, ", lsl #3") \
+ TEST_RR(op s" r2, r",3, VAL1,", r",2, val, ", lsr #4") \
+ TEST_RR(op s" r3, r",3, VAL1,", r",2, val, ", asr #5") \
+ TEST_RR(op s" r4, r",5, VAL1,", r",2, N(val),", asr #6") \
+ TEST_RR(op s" r5, r",5, VAL1,", r",2, val, ", ror #7") \
+ TEST_RR(op s" r8, r",9, VAL1,", r",10,val, ", rrx") \
+ TEST_R( op s" r0, r",11,VAL1,", #0x00010001") \
+ TEST_R( op s" r11, r",0, VAL1,", #0xf5000000") \
+ TEST_R( op s" r7, r",8, VAL2,", #0x000af000")
+
+#define DATA_PROCESSING32_DNM(op,val) \
+ _DATA_PROCESSING32_DNM(op,"",val) \
+ _DATA_PROCESSING32_DNM(op,"s",val)
+
+#define DATA_PROCESSING32_NM(op,val) \
+ TEST_RR(op".w r",1, VAL1,", r",2, val, "") \
+ TEST_RR(op" r",1, VAL1,", r",2, val, ", lsl #3") \
+ TEST_RR(op" r",3, VAL1,", r",2, val, ", lsr #4") \
+ TEST_RR(op" r",3, VAL1,", r",2, val, ", asr #5") \
+ TEST_RR(op" r",5, VAL1,", r",2, N(val),", asr #6") \
+ TEST_RR(op" r",5, VAL1,", r",2, val, ", ror #7") \
+ TEST_RR(op" r",9, VAL1,", r",10,val, ", rrx") \
+ TEST_R( op" r",11,VAL1,", #0x00010001") \
+ TEST_R( op" r",0, VAL1,", #0xf5000000") \
+ TEST_R( op" r",8, VAL2,", #0x000af000")
+
+#define _DATA_PROCESSING32_DM(op,s,val) \
+ TEST_R( op s".w r0, r",14, val, "") \
+ TEST_R( op s" r1, r",12, val, ", lsl #3") \
+ TEST_R( op s" r2, r",11, val, ", lsr #4") \
+ TEST_R( op s" r3, r",10, val, ", asr #5") \
+ TEST_R( op s" r4, r",9, N(val),", asr #6") \
+ TEST_R( op s" r5, r",8, val, ", ror #7") \
+ TEST_R( op s" r8, r",7,val, ", rrx") \
+ TEST( op s" r0, #0x00010001") \
+ TEST( op s" r11, #0xf5000000") \
+ TEST( op s" r7, #0x000af000") \
+ TEST( op s" r4, #0x00005a00")
+
+#define DATA_PROCESSING32_DM(op,val) \
+ _DATA_PROCESSING32_DM(op,"",val) \
+ _DATA_PROCESSING32_DM(op,"s",val)
+
+ DATA_PROCESSING32_DNM("and",0xf00f00ff)
+ DATA_PROCESSING32_NM("tst",0xf00f00ff)
+ DATA_PROCESSING32_DNM("bic",0xf00f00ff)
+ DATA_PROCESSING32_DNM("orr",0xf00f00ff)
+ DATA_PROCESSING32_DM("mov",VAL2)
+ DATA_PROCESSING32_DNM("orn",0xf00f00ff)
+ DATA_PROCESSING32_DM("mvn",VAL2)
+ DATA_PROCESSING32_DNM("eor",0xf00f00ff)
+ DATA_PROCESSING32_NM("teq",0xf00f00ff)
+ DATA_PROCESSING32_DNM("add",VAL2)
+ DATA_PROCESSING32_NM("cmn",VAL2)
+ DATA_PROCESSING32_DNM("adc",VAL2)
+ DATA_PROCESSING32_DNM("sbc",VAL2)
+ DATA_PROCESSING32_DNM("sub",VAL2)
+ DATA_PROCESSING32_NM("cmp",VAL2)
+ DATA_PROCESSING32_DNM("rsb",VAL2)
+
+ TEST_RR("pkhbt r0, r",0, HH1,", r",1, HH2,"")
+ TEST_RR("pkhbt r14,r",12, HH1,", r",10,HH2,", lsl #2")
+ TEST_RR("pkhtb r0, r",0, HH1,", r",1, HH2,"")
+ TEST_RR("pkhtb r14,r",12, HH1,", r",10,HH2,", asr #2")
+
+ TEST_UNSUPPORTED(".short 0xea17,0x0f0d @ tst.w r7, sp")
+ TEST_UNSUPPORTED(".short 0xea17,0x0f0f @ tst.w r7, pc")
+ TEST_UNSUPPORTED(".short 0xea1d,0x0f07 @ tst.w sp, r7")
+ TEST_UNSUPPORTED(".short 0xea1f,0x0f07 @ tst.w pc, r7")
+ TEST_UNSUPPORTED(".short 0xf01d,0x1f08 @ tst sp, #0x00080008")
+ TEST_UNSUPPORTED(".short 0xf01f,0x1f08 @ tst pc, #0x00080008")
+
+ TEST_UNSUPPORTED(".short 0xea97,0x0f0d @ teq.w r7, sp")
+ TEST_UNSUPPORTED(".short 0xea97,0x0f0f @ teq.w r7, pc")
+ TEST_UNSUPPORTED(".short 0xea9d,0x0f07 @ teq.w sp, r7")
+ TEST_UNSUPPORTED(".short 0xea9f,0x0f07 @ teq.w pc, r7")
+ TEST_UNSUPPORTED(".short 0xf09d,0x1f08 @ tst sp, #0x00080008")
+ TEST_UNSUPPORTED(".short 0xf09f,0x1f08 @ tst pc, #0x00080008")
+
+ TEST_UNSUPPORTED(".short 0xeb17,0x0f0d @ cmn.w r7, sp")
+ TEST_UNSUPPORTED(".short 0xeb17,0x0f0f @ cmn.w r7, pc")
+ TEST_P("cmn.w sp, r",7,0,"")
+ TEST_UNSUPPORTED(".short 0xeb1f,0x0f07 @ cmn.w pc, r7")
+ TEST( "cmn sp, #0x00080008")
+ TEST_UNSUPPORTED(".short 0xf11f,0x1f08 @ cmn pc, #0x00080008")
+
+ TEST_UNSUPPORTED(".short 0xebb7,0x0f0d @ cmp.w r7, sp")
+ TEST_UNSUPPORTED(".short 0xebb7,0x0f0f @ cmp.w r7, pc")
+ TEST_P("cmp.w sp, r",7,0,"")
+ TEST_UNSUPPORTED(".short 0xebbf,0x0f07 @ cmp.w pc, r7")
+ TEST( "cmp sp, #0x00080008")
+ TEST_UNSUPPORTED(".short 0xf1bf,0x1f08 @ cmp pc, #0x00080008")
+
+ TEST_UNSUPPORTED(".short 0xea5f,0x070d @ movs.w r7, sp")
+ TEST_UNSUPPORTED(".short 0xea5f,0x070f @ movs.w r7, pc")
+ TEST_UNSUPPORTED(".short 0xea5f,0x0d07 @ movs.w sp, r7")
+ TEST_UNSUPPORTED(".short 0xea4f,0x0f07 @ mov.w pc, r7")
+ TEST_UNSUPPORTED(".short 0xf04f,0x1d08 @ mov sp, #0x00080008")
+ TEST_UNSUPPORTED(".short 0xf04f,0x1f08 @ mov pc, #0x00080008")
+
+ TEST_R("add.w r0, sp, r",1, 4,"")
+ TEST_R("adds r0, sp, r",1, 4,", asl #3")
+ TEST_R("add r0, sp, r",1, 4,", asl #4")
+ TEST_R("add r0, sp, r",1, 16,", ror #1")
+ TEST_R("add.w sp, sp, r",1, 4,"")
+ TEST_R("add sp, sp, r",1, 4,", asl #3")
+ TEST_UNSUPPORTED(".short 0xeb0d,0x1d01 @ add sp, sp, r1, asl #4")
+ TEST_UNSUPPORTED(".short 0xeb0d,0x0d71 @ add sp, sp, r1, ror #1")
+ TEST( "add.w r0, sp, #24")
+ TEST( "add.w sp, sp, #24")
+ TEST_UNSUPPORTED(".short 0xeb0d,0x0f01 @ add pc, sp, r1")
+ TEST_UNSUPPORTED(".short 0xeb0d,0x000f @ add r0, sp, pc")
+ TEST_UNSUPPORTED(".short 0xeb0d,0x000d @ add r0, sp, sp")
+ TEST_UNSUPPORTED(".short 0xeb0d,0x0d0f @ add sp, sp, pc")
+ TEST_UNSUPPORTED(".short 0xeb0d,0x0d0d @ add sp, sp, sp")
+
+ TEST_R("sub.w r0, sp, r",1, 4,"")
+ TEST_R("subs r0, sp, r",1, 4,", asl #3")
+ TEST_R("sub r0, sp, r",1, 4,", asl #4")
+ TEST_R("sub r0, sp, r",1, 16,", ror #1")
+ TEST_R("sub.w sp, sp, r",1, 4,"")
+ TEST_R("sub sp, sp, r",1, 4,", asl #3")
+ TEST_UNSUPPORTED(".short 0xebad,0x1d01 @ sub sp, sp, r1, asl #4")
+ TEST_UNSUPPORTED(".short 0xebad,0x0d71 @ sub sp, sp, r1, ror #1")
+ TEST_UNSUPPORTED(".short 0xebad,0x0f01 @ sub pc, sp, r1")
+ TEST( "sub.w r0, sp, #24")
+ TEST( "sub.w sp, sp, #24")
+
+ TEST_UNSUPPORTED(".short 0xea02,0x010f @ and r1, r2, pc")
+ TEST_UNSUPPORTED(".short 0xea0f,0x0103 @ and r1, pc, r3")
+ TEST_UNSUPPORTED(".short 0xea02,0x0f03 @ and pc, r2, r3")
+ TEST_UNSUPPORTED(".short 0xea02,0x010d @ and r1, r2, sp")
+ TEST_UNSUPPORTED(".short 0xea0d,0x0103 @ and r1, sp, r3")
+ TEST_UNSUPPORTED(".short 0xea02,0x0d03 @ and sp, r2, r3")
+ TEST_UNSUPPORTED(".short 0xf00d,0x1108 @ and r1, sp, #0x00080008")
+ TEST_UNSUPPORTED(".short 0xf00f,0x1108 @ and r1, pc, #0x00080008")
+ TEST_UNSUPPORTED(".short 0xf002,0x1d08 @ and sp, r8, #0x00080008")
+ TEST_UNSUPPORTED(".short 0xf002,0x1f08 @ and pc, r8, #0x00080008")
+
+ TEST_UNSUPPORTED(".short 0xeb02,0x010f @ add r1, r2, pc")
+ TEST_UNSUPPORTED(".short 0xeb0f,0x0103 @ add r1, pc, r3")
+ TEST_UNSUPPORTED(".short 0xeb02,0x0f03 @ add pc, r2, r3")
+ TEST_UNSUPPORTED(".short 0xeb02,0x010d @ add r1, r2, sp")
+ TEST_SUPPORTED( ".short 0xeb0d,0x0103 @ add r1, sp, r3")
+ TEST_UNSUPPORTED(".short 0xeb02,0x0d03 @ add sp, r2, r3")
+ TEST_SUPPORTED( ".short 0xf10d,0x1108 @ add r1, sp, #0x00080008")
+ TEST_UNSUPPORTED(".short 0xf10d,0x1f08 @ add pc, sp, #0x00080008")
+ TEST_UNSUPPORTED(".short 0xf10f,0x1108 @ add r1, pc, #0x00080008")
+ TEST_UNSUPPORTED(".short 0xf102,0x1d08 @ add sp, r8, #0x00080008")
+ TEST_UNSUPPORTED(".short 0xf102,0x1f08 @ add pc, r8, #0x00080008")
+
+ TEST_UNSUPPORTED(".short 0xeaa0,0x0000")
+ TEST_UNSUPPORTED(".short 0xeaf0,0x0000")
+ TEST_UNSUPPORTED(".short 0xeb20,0x0000")
+ TEST_UNSUPPORTED(".short 0xeb80,0x0000")
+ TEST_UNSUPPORTED(".short 0xebe0,0x0000")
+
+ TEST_UNSUPPORTED(".short 0xf0a0,0x0000")
+ TEST_UNSUPPORTED(".short 0xf0c0,0x0000")
+ TEST_UNSUPPORTED(".short 0xf0f0,0x0000")
+ TEST_UNSUPPORTED(".short 0xf120,0x0000")
+ TEST_UNSUPPORTED(".short 0xf180,0x0000")
+ TEST_UNSUPPORTED(".short 0xf1e0,0x0000")
+
+ TEST_GROUP("Coprocessor instructions")
+
+ TEST_UNSUPPORTED(".short 0xec00,0x0000")
+ TEST_UNSUPPORTED(".short 0xeff0,0x0000")
+ TEST_UNSUPPORTED(".short 0xfc00,0x0000")
+ TEST_UNSUPPORTED(".short 0xfff0,0x0000")
+
+ TEST_GROUP("Data-processing (plain binary immediate)")
+
+ TEST_R("addw r0, r",1, VAL1,", #0x123")
+ TEST( "addw r14, sp, #0xf5a")
+ TEST( "addw sp, sp, #0x20")
+ TEST( "addw r7, pc, #0x888")
+ TEST_UNSUPPORTED(".short 0xf20f,0x1f20 @ addw pc, pc, #0x120")
+ TEST_UNSUPPORTED(".short 0xf20d,0x1f20 @ addw pc, sp, #0x120")
+ TEST_UNSUPPORTED(".short 0xf20f,0x1d20 @ addw sp, pc, #0x120")
+ TEST_UNSUPPORTED(".short 0xf200,0x1d20 @ addw sp, r0, #0x120")
+
+ TEST_R("subw r0, r",1, VAL1,", #0x123")
+ TEST( "subw r14, sp, #0xf5a")
+ TEST( "subw sp, sp, #0x20")
+ TEST( "subw r7, pc, #0x888")
+ TEST_UNSUPPORTED(".short 0xf2af,0x1f20 @ subw pc, pc, #0x120")
+ TEST_UNSUPPORTED(".short 0xf2ad,0x1f20 @ subw pc, sp, #0x120")
+ TEST_UNSUPPORTED(".short 0xf2af,0x1d20 @ subw sp, pc, #0x120")
+ TEST_UNSUPPORTED(".short 0xf2a0,0x1d20 @ subw sp, r0, #0x120")
+
+ TEST("movw r0, #0")
+ TEST("movw r0, #0xffff")
+ TEST("movw lr, #0xffff")
+ TEST_UNSUPPORTED(".short 0xf240,0x0d00 @ movw sp, #0")
+ TEST_UNSUPPORTED(".short 0xf240,0x0f00 @ movw pc, #0")
+
+ TEST_R("movt r",0, VAL1,", #0")
+ TEST_R("movt r",0, VAL2,", #0xffff")
+ TEST_R("movt r",14,VAL1,", #0xffff")
+ TEST_UNSUPPORTED(".short 0xf2c0,0x0d00 @ movt sp, #0")
+ TEST_UNSUPPORTED(".short 0xf2c0,0x0f00 @ movt pc, #0")
+
+ TEST_R( "ssat r0, #24, r",0, VAL1,"")
+ TEST_R( "ssat r14, #24, r",12, VAL2,"")
+ TEST_R( "ssat r0, #24, r",0, VAL1,", lsl #8")
+ TEST_R( "ssat r14, #24, r",12, VAL2,", asr #8")
+ TEST_UNSUPPORTED(".short 0xf30c,0x0d17 @ ssat sp, #24, r12")
+ TEST_UNSUPPORTED(".short 0xf30c,0x0f17 @ ssat pc, #24, r12")
+ TEST_UNSUPPORTED(".short 0xf30d,0x0c17 @ ssat r12, #24, sp")
+ TEST_UNSUPPORTED(".short 0xf30f,0x0c17 @ ssat r12, #24, pc")
+
+ TEST_R( "usat r0, #24, r",0, VAL1,"")
+ TEST_R( "usat r14, #24, r",12, VAL2,"")
+ TEST_R( "usat r0, #24, r",0, VAL1,", lsl #8")
+ TEST_R( "usat r14, #24, r",12, VAL2,", asr #8")
+ TEST_UNSUPPORTED(".short 0xf38c,0x0d17 @ usat sp, #24, r12")
+ TEST_UNSUPPORTED(".short 0xf38c,0x0f17 @ usat pc, #24, r12")
+ TEST_UNSUPPORTED(".short 0xf38d,0x0c17 @ usat r12, #24, sp")
+ TEST_UNSUPPORTED(".short 0xf38f,0x0c17 @ usat r12, #24, pc")
+
+ TEST_R( "ssat16 r0, #12, r",0, HH1,"")
+ TEST_R( "ssat16 r14, #12, r",12, HH2,"")
+ TEST_UNSUPPORTED(".short 0xf32c,0x0d0b @ ssat16 sp, #12, r12")
+ TEST_UNSUPPORTED(".short 0xf32c,0x0f0b @ ssat16 pc, #12, r12")
+ TEST_UNSUPPORTED(".short 0xf32d,0x0c0b @ ssat16 r12, #12, sp")
+ TEST_UNSUPPORTED(".short 0xf32f,0x0c0b @ ssat16 r12, #12, pc")
+
+ TEST_R( "usat16 r0, #12, r",0, HH1,"")
+ TEST_R( "usat16 r14, #12, r",12, HH2,"")
+ TEST_UNSUPPORTED(".short 0xf3ac,0x0d0b @ usat16 sp, #12, r12")
+ TEST_UNSUPPORTED(".short 0xf3ac,0x0f0b @ usat16 pc, #12, r12")
+ TEST_UNSUPPORTED(".short 0xf3ad,0x0c0b @ usat16 r12, #12, sp")
+ TEST_UNSUPPORTED(".short 0xf3af,0x0c0b @ usat16 r12, #12, pc")
+
+ TEST_R( "sbfx r0, r",0 , VAL1,", #0, #31")
+ TEST_R( "sbfx r14, r",12, VAL2,", #8, #16")
+ TEST_R( "sbfx r4, r",10, VAL1,", #16, #15")
+ TEST_UNSUPPORTED(".short 0xf34c,0x2d0f @ sbfx sp, r12, #8, #16")
+ TEST_UNSUPPORTED(".short 0xf34c,0x2f0f @ sbfx pc, r12, #8, #16")
+ TEST_UNSUPPORTED(".short 0xf34d,0x2c0f @ sbfx r12, sp, #8, #16")
+ TEST_UNSUPPORTED(".short 0xf34f,0x2c0f @ sbfx r12, pc, #8, #16")
+
+ TEST_R( "ubfx r0, r",0 , VAL1,", #0, #31")
+ TEST_R( "ubfx r14, r",12, VAL2,", #8, #16")
+ TEST_R( "ubfx r4, r",10, VAL1,", #16, #15")
+ TEST_UNSUPPORTED(".short 0xf3cc,0x2d0f @ ubfx sp, r12, #8, #16")
+ TEST_UNSUPPORTED(".short 0xf3cc,0x2f0f @ ubfx pc, r12, #8, #16")
+ TEST_UNSUPPORTED(".short 0xf3cd,0x2c0f @ ubfx r12, sp, #8, #16")
+ TEST_UNSUPPORTED(".short 0xf3cf,0x2c0f @ ubfx r12, pc, #8, #16")
+
+ TEST_R( "bfc r",0, VAL1,", #4, #20")
+ TEST_R( "bfc r",14,VAL2,", #4, #20")
+ TEST_R( "bfc r",7, VAL1,", #0, #31")
+ TEST_R( "bfc r",8, VAL2,", #0, #31")
+ TEST_UNSUPPORTED(".short 0xf36f,0x0d1e @ bfc sp, #0, #31")
+ TEST_UNSUPPORTED(".short 0xf36f,0x0f1e @ bfc pc, #0, #31")
+
+ TEST_RR( "bfi r",0, VAL1,", r",0 , VAL2,", #0, #31")
+ TEST_RR( "bfi r",12,VAL1,", r",14 , VAL2,", #4, #20")
+ TEST_UNSUPPORTED(".short 0xf36e,0x1d17 @ bfi sp, r14, #4, #20")
+ TEST_UNSUPPORTED(".short 0xf36e,0x1f17 @ bfi pc, r14, #4, #20")
+ TEST_UNSUPPORTED(".short 0xf36d,0x1e17 @ bfi r14, sp, #4, #20")
+
+ TEST_GROUP("Branches and miscellaneous control")
+
+CONDITION_INSTRUCTIONS(22,
+ TEST_BF("beq.w 2f")
+ TEST_BB("bne.w 2b")
+ TEST_BF("bgt.w 2f")
+ TEST_BB("blt.w 2b")
+ TEST_BF_X("bpl.w 2f",0x1000)
+)
+
+ TEST_UNSUPPORTED("msr cpsr, r0")
+ TEST_UNSUPPORTED("msr cpsr_f, r1")
+ TEST_UNSUPPORTED("msr spsr, r2")
+
+ TEST_UNSUPPORTED("cpsie.w i")
+ TEST_UNSUPPORTED("cpsid.w i")
+ TEST_UNSUPPORTED("cps 0x13")
+
+ TEST_SUPPORTED("yield.w")
+ TEST("sev.w")
+ TEST("nop.w")
+ TEST("wfi.w")
+ TEST_SUPPORTED("wfe.w")
+ TEST_UNSUPPORTED("dbg.w #0")
+
+ TEST_UNSUPPORTED("clrex")
+ TEST_UNSUPPORTED("dsb")
+ TEST_UNSUPPORTED("dmb")
+ TEST_UNSUPPORTED("isb")
+
+ TEST_UNSUPPORTED("bxj r0")
+
+ TEST_UNSUPPORTED("subs pc, lr, #4")
+
+ TEST("mrs r0, cpsr")
+ TEST("mrs r14, cpsr")
+ TEST_UNSUPPORTED(".short 0xf3ef,0x8d00 @ mrs sp, spsr")
+ TEST_UNSUPPORTED(".short 0xf3ef,0x8f00 @ mrs pc, spsr")
+ TEST_UNSUPPORTED("mrs r0, spsr")
+ TEST_UNSUPPORTED("mrs lr, spsr")
+
+ TEST_UNSUPPORTED(".short 0xf7f0,0x8000 @ smc #0")
+
+ TEST_UNSUPPORTED(".short 0xf7f0,0xa000 @ undefeined")
+
+ TEST_BF( "b.w 2f")
+ TEST_BB( "b.w 2b")
+ TEST_BF_X("b.w 2f", 0x1000)
+
+ TEST_BF( "bl.w 2f")
+ TEST_BB( "bl.w 2b")
+ TEST_BB_X("bl.w 2b", 0x1000)
+
+ TEST_X( "blx __dummy_arm_subroutine",
+ ".arm \n\t"
+ ".align \n\t"
+ ".type __dummy_arm_subroutine, %%function \n\t"
+ "__dummy_arm_subroutine: \n\t"
+ "mov r0, pc \n\t"
+ "bx lr \n\t"
+ ".thumb \n\t"
+ )
+ TEST( "blx __dummy_arm_subroutine")
+
+ TEST_GROUP("Store single data item")
+
+#define SINGLE_STORE(size) \
+ TEST_RP( "str"size" r",0, VAL1,", [r",11,-1024,", #1024]") \
+ TEST_RP( "str"size" r",14,VAL2,", [r",1, -1024,", #1080]") \
+ TEST_RP( "str"size" r",0, VAL1,", [r",11,256, ", #-120]") \
+ TEST_RP( "str"size" r",14,VAL2,", [r",1, 256, ", #-128]") \
+ TEST_RP( "str"size" r",0, VAL1,", [r",11,24, "], #120") \
+ TEST_RP( "str"size" r",14,VAL2,", [r",1, 24, "], #128") \
+ TEST_RP( "str"size" r",0, VAL1,", [r",11,24, "], #-120") \
+ TEST_RP( "str"size" r",14,VAL2,", [r",1, 24, "], #-128") \
+ TEST_RP( "str"size" r",0, VAL1,", [r",11,24, ", #120]!") \
+ TEST_RP( "str"size" r",14,VAL2,", [r",1, 24, ", #128]!") \
+ TEST_RP( "str"size" r",0, VAL1,", [r",11,256, ", #-120]!") \
+ TEST_RP( "str"size" r",14,VAL2,", [r",1, 256, ", #-128]!") \
+ TEST_RPR("str"size".w r",0, VAL1,", [r",1, 0,", r",2, 4,"]") \
+ TEST_RPR("str"size" r",14,VAL2,", [r",10,0,", r",11,4,", lsl #1]") \
+ TEST_R( "str"size".w r",7, VAL1,", [sp, #24]") \
+ TEST_RP( "str"size".w r",0, VAL2,", [r",0,0, "]") \
+ TEST_UNSUPPORTED("str"size"t r0, [r1, #4]")
+
+ SINGLE_STORE("b")
+ SINGLE_STORE("h")
+ SINGLE_STORE("")
+
+ TEST("str sp, [sp]")
+ TEST_UNSUPPORTED(".short 0xf8cf,0xe000 @ str r14, [pc]")
+ TEST_UNSUPPORTED(".short 0xf8ce,0xf000 @ str pc, [r14]")
+
+ TEST_GROUP("Advanced SIMD element or structure load/store instructions")
+
+ TEST_UNSUPPORTED(".short 0xf900,0x0000")
+ TEST_UNSUPPORTED(".short 0xf92f,0xffff")
+ TEST_UNSUPPORTED(".short 0xf980,0x0000")
+ TEST_UNSUPPORTED(".short 0xf9ef,0xffff")
+
+ TEST_GROUP("Load single data item and memory hints")
+
+#define SINGLE_LOAD(size) \
+ TEST_P( "ldr"size" r0, [r",11,-1024, ", #1024]") \
+ TEST_P( "ldr"size" r14, [r",1, -1024,", #1080]") \
+ TEST_P( "ldr"size" r0, [r",11,256, ", #-120]") \
+ TEST_P( "ldr"size" r14, [r",1, 256, ", #-128]") \
+ TEST_P( "ldr"size" r0, [r",11,24, "], #120") \
+ TEST_P( "ldr"size" r14, [r",1, 24, "], #128") \
+ TEST_P( "ldr"size" r0, [r",11,24, "], #-120") \
+ TEST_P( "ldr"size" r14, [r",1,24, "], #-128") \
+ TEST_P( "ldr"size" r0, [r",11,24, ", #120]!") \
+ TEST_P( "ldr"size" r14, [r",1, 24, ", #128]!") \
+ TEST_P( "ldr"size" r0, [r",11,256, ", #-120]!") \
+ TEST_P( "ldr"size" r14, [r",1, 256, ", #-128]!") \
+ TEST_PR("ldr"size".w r0, [r",1, 0,", r",2, 4,"]") \
+ TEST_PR("ldr"size" r14, [r",10,0,", r",11,4,", lsl #1]") \
+ TEST_X( "ldr"size".w r0, 3f", \
+ ".align 3 \n\t" \
+ "3: .word "__stringify(VAL1)) \
+ TEST_X( "ldr"size".w r14, 3f", \
+ ".align 3 \n\t" \
+ "3: .word "__stringify(VAL2)) \
+ TEST( "ldr"size".w r7, 3b") \
+ TEST( "ldr"size".w r7, [sp, #24]") \
+ TEST_P( "ldr"size".w r0, [r",0,0, "]") \
+ TEST_UNSUPPORTED("ldr"size"t r0, [r1, #4]")
+
+ SINGLE_LOAD("b")
+ SINGLE_LOAD("sb")
+ SINGLE_LOAD("h")
+ SINGLE_LOAD("sh")
+ SINGLE_LOAD("")
+
+ TEST_BF_P("ldr pc, [r",14, 15*4,"]")
+ TEST_P( "ldr sp, [r",14, 13*4,"]")
+ TEST_BF_R("ldr pc, [sp, r",14, 15*4,"]")
+ TEST_R( "ldr sp, [sp, r",14, 13*4,"]")
+ TEST_THUMB_TO_ARM_INTERWORK_P("ldr pc, [r",0,0,", #15*4]")
+ TEST_SUPPORTED("ldr sp, 99f")
+ TEST_SUPPORTED("ldr pc, 99f")
+
+ TEST_UNSUPPORTED(".short 0xf854,0x700d @ ldr r7, [r4, sp]")
+ TEST_UNSUPPORTED(".short 0xf854,0x700f @ ldr r7, [r4, pc]")
+ TEST_UNSUPPORTED(".short 0xf814,0x700d @ ldrb r7, [r4, sp]")
+ TEST_UNSUPPORTED(".short 0xf814,0x700f @ ldrb r7, [r4, pc]")
+ TEST_UNSUPPORTED(".short 0xf89f,0xd004 @ ldrb sp, 99f")
+ TEST_UNSUPPORTED(".short 0xf814,0xd008 @ ldrb sp, [r4, r8]")
+ TEST_UNSUPPORTED(".short 0xf894,0xd000 @ ldrb sp, [r4]")
+
+ TEST_UNSUPPORTED(".short 0xf860,0x0000") /* Unallocated space */
+ TEST_UNSUPPORTED(".short 0xf9ff,0xffff") /* Unallocated space */
+ TEST_UNSUPPORTED(".short 0xf950,0x0000") /* Unallocated space */
+ TEST_UNSUPPORTED(".short 0xf95f,0xffff") /* Unallocated space */
+ TEST_UNSUPPORTED(".short 0xf800,0x0800") /* Unallocated space */
+ TEST_UNSUPPORTED(".short 0xf97f,0xfaff") /* Unallocated space */
+
+ TEST( "pli [pc, #4]")
+ TEST( "pli [pc, #-4]")
+ TEST( "pld [pc, #4]")
+ TEST( "pld [pc, #-4]")
+
+ TEST_P( "pld [r",0,-1024,", #1024]")
+ TEST( ".short 0xf8b0,0xf400 @ pldw [r0, #1024]")
+ TEST_P( "pli [r",4, 0b,", #1024]")
+ TEST_P( "pld [r",7, 120,", #-120]")
+ TEST( ".short 0xf837,0xfc78 @ pldw [r7, #-120]")
+ TEST_P( "pli [r",11,120,", #-120]")
+ TEST( "pld [sp, #0]")
+
+ TEST_PR("pld [r",7, 24, ", r",0, 16,"]")
+ TEST_PR("pld [r",8, 24, ", r",12,16,", lsl #3]")
+ TEST_SUPPORTED(".short 0xf837,0xf000 @ pldw [r7, r0]")
+ TEST_SUPPORTED(".short 0xf838,0xf03c @ pldw [r8, r12, lsl #3]");
+ TEST_RR("pli [r",12,0b,", r",0, 16,"]")
+ TEST_RR("pli [r",0, 0b,", r",12,16,", lsl #3]")
+ TEST_R( "pld [sp, r",1, 16,"]")
+ TEST_UNSUPPORTED(".short 0xf817,0xf00d @pld [r7, sp]")
+ TEST_UNSUPPORTED(".short 0xf817,0xf00f @pld [r7, pc]")
+
+ TEST_GROUP("Data-processing (register)")
+
+#define SHIFTS32(op) \
+ TEST_RR(op" r0, r",1, VAL1,", r",2, 3, "") \
+ TEST_RR(op" r14, r",12,VAL2,", r",11,10,"")
+
+ SHIFTS32("lsl")
+ SHIFTS32("lsls")
+ SHIFTS32("lsr")
+ SHIFTS32("lsrs")
+ SHIFTS32("asr")
+ SHIFTS32("asrs")
+ SHIFTS32("ror")
+ SHIFTS32("rors")
+
+ TEST_UNSUPPORTED(".short 0xfa01,0xff02 @ lsl pc, r1, r2")
+ TEST_UNSUPPORTED(".short 0xfa01,0xfd02 @ lsl sp, r1, r2")
+ TEST_UNSUPPORTED(".short 0xfa0f,0xf002 @ lsl r0, pc, r2")
+ TEST_UNSUPPORTED(".short 0xfa0d,0xf002 @ lsl r0, sp, r2")
+ TEST_UNSUPPORTED(".short 0xfa01,0xf00f @ lsl r0, r1, pc")
+ TEST_UNSUPPORTED(".short 0xfa01,0xf00d @ lsl r0, r1, sp")
+
+ TEST_RR( "sxtah r0, r",0, HH1,", r",1, HH2,"")
+ TEST_RR( "sxtah r14,r",12, HH2,", r",10,HH1,", ror #8")
+ TEST_R( "sxth r8, r",7, HH1,"")
+
+ TEST_UNSUPPORTED(".short 0xfa0f,0xff87 @ sxth pc, r7");
+ TEST_UNSUPPORTED(".short 0xfa0f,0xfd87 @ sxth sp, r7");
+ TEST_UNSUPPORTED(".short 0xfa0f,0xf88f @ sxth r8, pc");
+ TEST_UNSUPPORTED(".short 0xfa0f,0xf88d @ sxth r8, sp");
+
+ TEST_RR( "uxtah r0, r",0, HH1,", r",1, HH2,"")
+ TEST_RR( "uxtah r14,r",12, HH2,", r",10,HH1,", ror #8")
+ TEST_R( "uxth r8, r",7, HH1,"")
+
+ TEST_RR( "sxtab16 r0, r",0, HH1,", r",1, HH2,"")
+ TEST_RR( "sxtab16 r14,r",12, HH2,", r",10,HH1,", ror #8")
+ TEST_R( "sxtb16 r8, r",7, HH1,"")
+
+ TEST_RR( "uxtab16 r0, r",0, HH1,", r",1, HH2,"")
+ TEST_RR( "uxtab16 r14,r",12, HH2,", r",10,HH1,", ror #8")
+ TEST_R( "uxtb16 r8, r",7, HH1,"")
+
+ TEST_RR( "sxtab r0, r",0, HH1,", r",1, HH2,"")
+ TEST_RR( "sxtab r14,r",12, HH2,", r",10,HH1,", ror #8")
+ TEST_R( "sxtb r8, r",7, HH1,"")
+
+ TEST_RR( "uxtab r0, r",0, HH1,", r",1, HH2,"")
+ TEST_RR( "uxtab r14,r",12, HH2,", r",10,HH1,", ror #8")
+ TEST_R( "uxtb r8, r",7, HH1,"")
+
+ TEST_UNSUPPORTED(".short 0xfa60,0x00f0")
+ TEST_UNSUPPORTED(".short 0xfa7f,0xffff")
+
+#define PARALLEL_ADD_SUB(op) \
+ TEST_RR( op"add16 r0, r",0, HH1,", r",1, HH2,"") \
+ TEST_RR( op"add16 r14, r",12,HH2,", r",10,HH1,"") \
+ TEST_RR( op"asx r0, r",0, HH1,", r",1, HH2,"") \
+ TEST_RR( op"asx r14, r",12,HH2,", r",10,HH1,"") \
+ TEST_RR( op"sax r0, r",0, HH1,", r",1, HH2,"") \
+ TEST_RR( op"sax r14, r",12,HH2,", r",10,HH1,"") \
+ TEST_RR( op"sub16 r0, r",0, HH1,", r",1, HH2,"") \
+ TEST_RR( op"sub16 r14, r",12,HH2,", r",10,HH1,"") \
+ TEST_RR( op"add8 r0, r",0, HH1,", r",1, HH2,"") \
+ TEST_RR( op"add8 r14, r",12,HH2,", r",10,HH1,"") \
+ TEST_RR( op"sub8 r0, r",0, HH1,", r",1, HH2,"") \
+ TEST_RR( op"sub8 r14, r",12,HH2,", r",10,HH1,"")
+
+ TEST_GROUP("Parallel addition and subtraction, signed")
+
+ PARALLEL_ADD_SUB("s")
+ PARALLEL_ADD_SUB("q")
+ PARALLEL_ADD_SUB("sh")
+
+ TEST_GROUP("Parallel addition and subtraction, unsigned")
+
+ PARALLEL_ADD_SUB("u")
+ PARALLEL_ADD_SUB("uq")
+ PARALLEL_ADD_SUB("uh")
+
+ TEST_GROUP("Miscellaneous operations")
+
+ TEST_RR("qadd r0, r",1, VAL1,", r",2, VAL2,"")
+ TEST_RR("qadd lr, r",9, VAL2,", r",8, VAL1,"")
+ TEST_RR("qsub r0, r",1, VAL1,", r",2, VAL2,"")
+ TEST_RR("qsub lr, r",9, VAL2,", r",8, VAL1,"")
+ TEST_RR("qdadd r0, r",1, VAL1,", r",2, VAL2,"")
+ TEST_RR("qdadd lr, r",9, VAL2,", r",8, VAL1,"")
+ TEST_RR("qdsub r0, r",1, VAL1,", r",2, VAL2,"")
+ TEST_RR("qdsub lr, r",9, VAL2,", r",8, VAL1,"")
+
+ TEST_R("rev.w r0, r",0, VAL1,"")
+ TEST_R("rev r14, r",12, VAL2,"")
+ TEST_R("rev16.w r0, r",0, VAL1,"")
+ TEST_R("rev16 r14, r",12, VAL2,"")
+ TEST_R("rbit r0, r",0, VAL1,"")
+ TEST_R("rbit r14, r",12, VAL2,"")
+ TEST_R("revsh.w r0, r",0, VAL1,"")
+ TEST_R("revsh r14, r",12, VAL2,"")
+
+ TEST_UNSUPPORTED(".short 0xfa9c,0xff8c @ rev pc, r12");
+ TEST_UNSUPPORTED(".short 0xfa9c,0xfd8c @ rev sp, r12");
+ TEST_UNSUPPORTED(".short 0xfa9f,0xfe8f @ rev r14, pc");
+ TEST_UNSUPPORTED(".short 0xfa9d,0xfe8d @ rev r14, sp");
+
+ TEST_RR("sel r0, r",0, VAL1,", r",1, VAL2,"")
+ TEST_RR("sel r14, r",12,VAL1,", r",10, VAL2,"")
+
+ TEST_R("clz r0, r",0, 0x0,"")
+ TEST_R("clz r7, r",14,0x1,"")
+ TEST_R("clz lr, r",7, 0xffffffff,"")
+
+ TEST_UNSUPPORTED(".short 0xfa80,0xf030") /* Unallocated space */
+ TEST_UNSUPPORTED(".short 0xfaff,0xff7f") /* Unallocated space */
+ TEST_UNSUPPORTED(".short 0xfab0,0xf000") /* Unallocated space */
+ TEST_UNSUPPORTED(".short 0xfaff,0xff7f") /* Unallocated space */
+
+ TEST_GROUP("Multiply, multiply accumulate, and absolute difference operations")
+
+ TEST_RR( "mul r0, r",1, VAL1,", r",2, VAL2,"")
+ TEST_RR( "mul r7, r",8, VAL2,", r",9, VAL2,"")
+ TEST_UNSUPPORTED(".short 0xfb08,0xff09 @ mul pc, r8, r9")
+ TEST_UNSUPPORTED(".short 0xfb08,0xfd09 @ mul sp, r8, r9")
+ TEST_UNSUPPORTED(".short 0xfb0f,0xf709 @ mul r7, pc, r9")
+ TEST_UNSUPPORTED(".short 0xfb0d,0xf709 @ mul r7, sp, r9")
+ TEST_UNSUPPORTED(".short 0xfb08,0xf70f @ mul r7, r8, pc")
+ TEST_UNSUPPORTED(".short 0xfb08,0xf70d @ mul r7, r8, sp")
+
+ TEST_RRR( "mla r0, r",1, VAL1,", r",2, VAL2,", r",3, VAL3,"")
+ TEST_RRR( "mla r7, r",8, VAL3,", r",9, VAL1,", r",10, VAL2,"")
+ TEST_UNSUPPORTED(".short 0xfb08,0xaf09 @ mla pc, r8, r9, r10");
+ TEST_UNSUPPORTED(".short 0xfb08,0xad09 @ mla sp, r8, r9, r10");
+ TEST_UNSUPPORTED(".short 0xfb0f,0xa709 @ mla r7, pc, r9, r10");
+ TEST_UNSUPPORTED(".short 0xfb0d,0xa709 @ mla r7, sp, r9, r10");
+ TEST_UNSUPPORTED(".short 0xfb08,0xa70f @ mla r7, r8, pc, r10");
+ TEST_UNSUPPORTED(".short 0xfb08,0xa70d @ mla r7, r8, sp, r10");
+ TEST_UNSUPPORTED(".short 0xfb08,0xd709 @ mla r7, r8, r9, sp");
+
+ TEST_RRR( "mls r0, r",1, VAL1,", r",2, VAL2,", r",3, VAL3,"")
+ TEST_RRR( "mls r7, r",8, VAL3,", r",9, VAL1,", r",10, VAL2,"")
+
+ TEST_RRR( "smlabb r0, r",1, VAL1,", r",2, VAL2,", r",3, VAL3,"")
+ TEST_RRR( "smlabb r7, r",8, VAL3,", r",9, VAL1,", r",10, VAL2,"")
+ TEST_RRR( "smlatb r0, r",1, VAL1,", r",2, VAL2,", r",3, VAL3,"")
+ TEST_RRR( "smlatb r7, r",8, VAL3,", r",9, VAL1,", r",10, VAL2,"")
+ TEST_RRR( "smlabt r0, r",1, VAL1,", r",2, VAL2,", r",3, VAL3,"")
+ TEST_RRR( "smlabt r7, r",8, VAL3,", r",9, VAL1,", r",10, VAL2,"")
+ TEST_RRR( "smlatt r0, r",1, VAL1,", r",2, VAL2,", r",3, VAL3,"")
+ TEST_RRR( "smlatt r7, r",8, VAL3,", r",9, VAL1,", r",10, VAL2,"")
+ TEST_RR( "smulbb r0, r",1, VAL1,", r",2, VAL2,"")
+ TEST_RR( "smulbb r7, r",8, VAL3,", r",9, VAL1,"")
+ TEST_RR( "smultb r0, r",1, VAL1,", r",2, VAL2,"")
+ TEST_RR( "smultb r7, r",8, VAL3,", r",9, VAL1,"")
+ TEST_RR( "smulbt r0, r",1, VAL1,", r",2, VAL2,"")
+ TEST_RR( "smulbt r7, r",8, VAL3,", r",9, VAL1,"")
+ TEST_RR( "smultt r0, r",1, VAL1,", r",2, VAL2,"")
+ TEST_RR( "smultt r7, r",8, VAL3,", r",9, VAL1,"")
+
+ TEST_RRR( "smlad r0, r",0, HH1,", r",1, HH2,", r",2, VAL1,"")
+ TEST_RRR( "smlad r14, r",12,HH2,", r",10,HH1,", r",8, VAL2,"")
+ TEST_RRR( "smladx r0, r",0, HH1,", r",1, HH2,", r",2, VAL1,"")
+ TEST_RRR( "smladx r14, r",12,HH2,", r",10,HH1,", r",8, VAL2,"")
+ TEST_RR( "smuad r0, r",0, HH1,", r",1, HH2,"")
+ TEST_RR( "smuad r14, r",12,HH2,", r",10,HH1,"")
+ TEST_RR( "smuadx r0, r",0, HH1,", r",1, HH2,"")
+ TEST_RR( "smuadx r14, r",12,HH2,", r",10,HH1,"")
+
+ TEST_RRR( "smlawb r0, r",1, VAL1,", r",2, VAL2,", r",3, VAL3,"")
+ TEST_RRR( "smlawb r7, r",8, VAL3,", r",9, VAL1,", r",10, VAL2,"")
+ TEST_RRR( "smlawt r0, r",1, VAL1,", r",2, VAL2,", r",3, VAL3,"")
+ TEST_RRR( "smlawt r7, r",8, VAL3,", r",9, VAL1,", r",10, VAL2,"")
+ TEST_RR( "smulwb r0, r",1, VAL1,", r",2, VAL2,"")
+ TEST_RR( "smulwb r7, r",8, VAL3,", r",9, VAL1,"")
+ TEST_RR( "smulwt r0, r",1, VAL1,", r",2, VAL2,"")
+ TEST_RR( "smulwt r7, r",8, VAL3,", r",9, VAL1,"")
+
+ TEST_RRR( "smlsd r0, r",0, HH1,", r",1, HH2,", r",2, VAL1,"")
+ TEST_RRR( "smlsd r14, r",12,HH2,", r",10,HH1,", r",8, VAL2,"")
+ TEST_RRR( "smlsdx r0, r",0, HH1,", r",1, HH2,", r",2, VAL1,"")
+ TEST_RRR( "smlsdx r14, r",12,HH2,", r",10,HH1,", r",8, VAL2,"")
+ TEST_RR( "smusd r0, r",0, HH1,", r",1, HH2,"")
+ TEST_RR( "smusd r14, r",12,HH2,", r",10,HH1,"")
+ TEST_RR( "smusdx r0, r",0, HH1,", r",1, HH2,"")
+ TEST_RR( "smusdx r14, r",12,HH2,", r",10,HH1,"")
+
+ TEST_RRR( "smmla r0, r",0, VAL1,", r",1, VAL2,", r",2, VAL1,"")
+ TEST_RRR( "smmla r14, r",12,VAL2,", r",10,VAL1,", r",8, VAL2,"")
+ TEST_RRR( "smmlar r0, r",0, VAL1,", r",1, VAL2,", r",2, VAL1,"")
+ TEST_RRR( "smmlar r14, r",12,VAL2,", r",10,VAL1,", r",8, VAL2,"")
+ TEST_RR( "smmul r0, r",0, VAL1,", r",1, VAL2,"")
+ TEST_RR( "smmul r14, r",12,VAL2,", r",10,VAL1,"")
+ TEST_RR( "smmulr r0, r",0, VAL1,", r",1, VAL2,"")
+ TEST_RR( "smmulr r14, r",12,VAL2,", r",10,VAL1,"")
+
+ TEST_RRR( "smmls r0, r",0, VAL1,", r",1, VAL2,", r",2, VAL1,"")
+ TEST_RRR( "smmls r14, r",12,VAL2,", r",10,VAL1,", r",8, VAL2,"")
+ TEST_RRR( "smmlsr r0, r",0, VAL1,", r",1, VAL2,", r",2, VAL1,"")
+ TEST_RRR( "smmlsr r14, r",12,VAL2,", r",10,VAL1,", r",8, VAL2,"")
+
+ TEST_RRR( "usada8 r0, r",0, VAL1,", r",1, VAL2,", r",2, VAL3,"")
+ TEST_RRR( "usada8 r14, r",12,VAL2,", r",10,VAL1,", r",8, VAL3,"")
+ TEST_RR( "usad8 r0, r",0, VAL1,", r",1, VAL2,"")
+ TEST_RR( "usad8 r14, r",12,VAL2,", r",10,VAL1,"")
+
+ TEST_UNSUPPORTED(".short 0xfb00,0xf010") /* Unallocated space */
+ TEST_UNSUPPORTED(".short 0xfb0f,0xff1f") /* Unallocated space */
+ TEST_UNSUPPORTED(".short 0xfb70,0xf010") /* Unallocated space */
+ TEST_UNSUPPORTED(".short 0xfb7f,0xff1f") /* Unallocated space */
+ TEST_UNSUPPORTED(".short 0xfb70,0x0010") /* Unallocated space */
+ TEST_UNSUPPORTED(".short 0xfb7f,0xff1f") /* Unallocated space */
+
+ TEST_GROUP("Long multiply, long multiply accumulate, and divide")
+
+ TEST_RR( "smull r0, r1, r",2, VAL1,", r",3, VAL2,"")
+ TEST_RR( "smull r7, r8, r",9, VAL2,", r",10, VAL1,"")
+ TEST_UNSUPPORTED(".short 0xfb89,0xf80a @ smull pc, r8, r9, r10");
+ TEST_UNSUPPORTED(".short 0xfb89,0xd80a @ smull sp, r8, r9, r10");
+ TEST_UNSUPPORTED(".short 0xfb89,0x7f0a @ smull r7, pc, r9, r10");
+ TEST_UNSUPPORTED(".short 0xfb89,0x7d0a @ smull r7, sp, r9, r10");
+ TEST_UNSUPPORTED(".short 0xfb8f,0x780a @ smull r7, r8, pc, r10");
+ TEST_UNSUPPORTED(".short 0xfb8d,0x780a @ smull r7, r8, sp, r10");
+ TEST_UNSUPPORTED(".short 0xfb89,0x780f @ smull r7, r8, r9, pc");
+ TEST_UNSUPPORTED(".short 0xfb89,0x780d @ smull r7, r8, r9, sp");
+
+ TEST_RR( "umull r0, r1, r",2, VAL1,", r",3, VAL2,"")
+ TEST_RR( "umull r7, r8, r",9, VAL2,", r",10, VAL1,"")
+
+ TEST_RRRR( "smlal r",0, VAL1,", r",1, VAL2,", r",2, VAL3,", r",3, VAL4)
+ TEST_RRRR( "smlal r",8, VAL4,", r",9, VAL1,", r",10,VAL2,", r",11,VAL3)
+
+ TEST_RRRR( "smlalbb r",0, VAL1,", r",1, VAL2,", r",2, VAL3,", r",3, VAL4)
+ TEST_RRRR( "smlalbb r",8, VAL4,", r",9, VAL1,", r",10,VAL2,", r",11,VAL3)
+ TEST_RRRR( "smlalbt r",0, VAL1,", r",1, VAL2,", r",2, VAL3,", r",3, VAL4)
+ TEST_RRRR( "smlalbt r",8, VAL4,", r",9, VAL1,", r",10,VAL2,", r",11,VAL3)
+ TEST_RRRR( "smlaltb r",0, VAL1,", r",1, VAL2,", r",2, VAL3,", r",3, VAL4)
+ TEST_RRRR( "smlaltb r",8, VAL4,", r",9, VAL1,", r",10,VAL2,", r",11,VAL3)
+ TEST_RRRR( "smlaltt r",0, VAL1,", r",1, VAL2,", r",2, VAL3,", r",3, VAL4)
+ TEST_RRRR( "smlaltt r",8, VAL4,", r",9, VAL1,", r",10,VAL2,", r",11,VAL3)
+
+ TEST_RRRR( "smlald r",0, VAL1,", r",1, VAL2, ", r",0, HH1,", r",1, HH2)
+ TEST_RRRR( "smlald r",11,VAL2,", r",10,VAL1, ", r",9, HH2,", r",8, HH1)
+ TEST_RRRR( "smlaldx r",0, VAL1,", r",1, VAL2, ", r",0, HH1,", r",1, HH2)
+ TEST_RRRR( "smlaldx r",11,VAL2,", r",10,VAL1, ", r",9, HH2,", r",8, HH1)
+
+ TEST_RRRR( "smlsld r",0, VAL1,", r",1, VAL2, ", r",0, HH1,", r",1, HH2)
+ TEST_RRRR( "smlsld r",11,VAL2,", r",10,VAL1, ", r",9, HH2,", r",8, HH1)
+ TEST_RRRR( "smlsldx r",0, VAL1,", r",1, VAL2, ", r",0, HH1,", r",1, HH2)
+ TEST_RRRR( "smlsldx r",11,VAL2,", r",10,VAL1, ", r",9, HH2,", r",8, HH1)
+
+ TEST_RRRR( "umlal r",0, VAL1,", r",1, VAL2,", r",2, VAL3,", r",3, VAL4)
+ TEST_RRRR( "umlal r",8, VAL4,", r",9, VAL1,", r",10,VAL2,", r",11,VAL3)
+ TEST_RRRR( "umaal r",0, VAL1,", r",1, VAL2,", r",2, VAL3,", r",3, VAL4)
+ TEST_RRRR( "umaal r",8, VAL4,", r",9, VAL1,", r",10,VAL2,", r",11,VAL3)
+
+ TEST_GROUP("Coprocessor instructions")
+
+ TEST_UNSUPPORTED(".short 0xfc00,0x0000")
+ TEST_UNSUPPORTED(".short 0xffff,0xffff")
+
+ TEST_GROUP("Testing instructions in IT blocks")
+
+ TEST_ITBLOCK("sub.w r0, r0")
+
+ verbose("\n");
+}
+
diff --git a/arch/arm/kernel/kprobes-test.c b/arch/arm/kernel/kprobes-test.c
new file mode 100644
index 0000000..e17cdd6
--- /dev/null
+++ b/arch/arm/kernel/kprobes-test.c
@@ -0,0 +1,1748 @@
+/*
+ * arch/arm/kernel/kprobes-test.c
+ *
+ * Copyright (C) 2011 Jon Medhurst <tixy@yxit.co.uk>.
+ *
+ * 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 file contains test code for ARM kprobes.
+ *
+ * The top level function run_all_tests() executes tests for all of the
+ * supported instruction sets: ARM, 16-bit Thumb, and 32-bit Thumb. These tests
+ * fall into two categories; run_api_tests() checks basic functionality of the
+ * kprobes API, and run_test_cases() is a comprehensive test for kprobes
+ * instruction decoding and simulation.
+ *
+ * run_test_cases() first checks the kprobes decoding table for self consistency
+ * (using table_test()) then executes a series of test cases for each of the CPU
+ * instruction forms. coverage_start() and coverage_end() are used to verify
+ * that these test cases cover all of the possible combinations of instructions
+ * described by the kprobes decoding tables.
+ *
+ * The individual test cases are in kprobes-test-arm.c and kprobes-test-thumb.c
+ * which use the macros defined in kprobes-test.h. The rest of this
+ * documentation will describe the operation of the framework used by these
+ * test cases.
+ */
+
+/*
+ * TESTING METHODOLOGY
+ * -------------------
+ *
+ * The methodology used to test an ARM instruction 'test_insn' is to use
+ * inline assembler like:
+ *
+ * test_before: nop
+ * test_case: test_insn
+ * test_after: nop
+ *
+ * When the test case is run a kprobe is placed of each nop. The
+ * post-handler of the test_before probe is used to modify the saved CPU
+ * register context to that which we require for the test case. The
+ * pre-handler of the of the test_after probe saves a copy of the CPU
+ * register context. In this way we can execute test_insn with a specific
+ * register context and see the results afterwards.
+ *
+ * To actually test the kprobes instruction emulation we perform the above
+ * step a second time but with an additional kprobe on the test_case
+ * instruction itself. If the emulation is accurate then the results seen
+ * by the test_after probe will be identical to the first run which didn't
+ * have a probe on test_case.
+ *
+ * Each test case is run several times with a variety of variations in the
+ * flags value of stored in CPSR, and for Thumb code, different ITState.
+ *
+ * For instructions which can modify PC, a second test_after probe is used
+ * like this:
+ *
+ * test_before: nop
+ * test_case: test_insn
+ * test_after: nop
+ * b test_done
+ * test_after2: nop
+ * test_done:
+ *
+ * The test case is constructed such that test_insn branches to
+ * test_after2, or, if testing a conditional instruction, it may just
+ * continue to test_after. The probes inserted at both locations let us
+ * determine which happened. A similar approach is used for testing
+ * backwards branches...
+ *
+ * b test_before
+ * b test_done @ helps to cope with off by 1 branches
+ * test_after2: nop
+ * b test_done
+ * test_before: nop
+ * test_case: test_insn
+ * test_after: nop
+ * test_done:
+ *
+ * The macros used to generate the assembler instructions describe above
+ * are TEST_INSTRUCTION, TEST_BRANCH_F (branch forwards) and TEST_BRANCH_B
+ * (branch backwards). In these, the local variables numbered 1, 50, 2 and
+ * 99 represent: test_before, test_case, test_after2 and test_done.
+ *
+ * FRAMEWORK
+ * ---------
+ *
+ * Each test case is wrapped between the pair of macros TESTCASE_START and
+ * TESTCASE_END. As well as performing the inline assembler boilerplate,
+ * these call out to the kprobes_test_case_start() and
+ * kprobes_test_case_end() functions which drive the execution of the test
+ * case. The specific arguments to use for each test case are stored as
+ * inline data constructed using the various TEST_ARG_* macros. Putting
+ * this all together, a simple test case may look like:
+ *
+ * TESTCASE_START("Testing mov r0, r7")
+ * TEST_ARG_REG(7, 0x12345678) // Set r7=0x12345678
+ * TEST_ARG_END("")
+ * TEST_INSTRUCTION("mov r0, r7")
+ * TESTCASE_END
+ *
+ * Note, in practice the single convenience macro TEST_R would be used for this
+ * instead.
+ *
+ * The above would expand to assembler looking something like:
+ *
+ * @ TESTCASE_START
+ * bl __kprobes_test_case_start
+ * @ start of inline data...
+ * .ascii "mov r0, r7" @ text title for test case
+ * .byte 0
+ * .align 2
+ *
+ * @ TEST_ARG_REG
+ * .byte ARG_TYPE_REG
+ * .byte 7
+ * .short 0
+ * .word 0x1234567
+ *
+ * @ TEST_ARG_END
+ * .byte ARG_TYPE_END
+ * .byte TEST_ISA @ flags, including ISA being tested
+ * .short 50f-0f @ offset of 'test_before'
+ * .short 2f-0f @ offset of 'test_after2' (if relevent)
+ * .short 99f-0f @ offset of 'test_done'
+ * @ start of test case code...
+ * 0:
+ * .code TEST_ISA @ switch to ISA being tested
+ *
+ * @ TEST_INSTRUCTION
+ * 50: nop @ location for 'test_before' probe
+ * 1: mov r0, r7 @ the test case instruction 'test_insn'
+ * nop @ location for 'test_after' probe
+ *
+ * // TESTCASE_END
+ * 2:
+ * 99: bl __kprobes_test_case_end_##TEST_ISA
+ * .code NONMAL_ISA
+ *
+ * When the above is execute the following happens...
+ *
+ * __kprobes_test_case_start() is an assembler wrapper which sets up space
+ * for a stack buffer and calls the C function kprobes_test_case_start().
+ * This C function will do some initial processing of the inline data and
+ * setup some global state. It then inserts the test_before and test_after
+ * kprobes and returns a value which causes the assembler wrapper to jump
+ * to the start of the test case code, (local label '0').
+ *
+ * When the test case code executes, the test_before probe will be hit and
+ * test_before_post_handler will call setup_test_context(). This fills the
+ * stack buffer and CPU registers with a test pattern and then processes
+ * the test case arguments. In our example there is one TEST_ARG_REG which
+ * indicates that R7 should be loaded with the value 0x12345678.
+ *
+ * When the test_before probe ends, the test case continues and executes
+ * the "mov r0, r7" instruction. It then hits the test_after probe and the
+ * pre-handler for this (test_after_pre_handler) will save a copy of the
+ * CPU register context. This should now have R0 holding the same value as
+ * R7.
+ *
+ * Finally we get to the call to __kprobes_test_case_end_{32,16}. This is
+ * an assembler wrapper which switches back to the ISA used by the test
+ * code and calls the C function kprobes_test_case_end().
+ *
+ * For each run through the test case, test_case_run_count is incremented
+ * by one. For even runs, kprobes_test_case_end() saves a copy of the
+ * register and stack buffer contents from the test case just run. It then
+ * inserts a kprobe on the test case instruction 'test_insn' and returns a
+ * value to cause the test case code to be re-run.
+ *
+ * For odd numbered runs, kprobes_test_case_end() compares the register and
+ * stack buffer contents to those that were saved on the previous even
+ * numbered run (the one without the kprobe on test_insn). These should be
+ * the same if the kprobe instruction simulation routine is correct.
+ *
+ * The pair of test case runs is repeated with different combinations of
+ * flag values in CPSR and, for Thumb, different ITState. This is
+ * controlled by test_context_cpsr().
+ *
+ * BUILDING TEST CASES
+ * -------------------
+ *
+ *
+ * As an aid to building test cases, the stack buffer is initialised with
+ * some special values:
+ *
+ * [SP+13*4] Contains SP+120. This can be used to test instructions
+ * which load a value into SP.
+ *
+ * [SP+15*4] When testing branching instructions using TEST_BRANCH_{F,B},
+ * this holds the target address of the branch, 'test_after2'.
+ * This can be used to test instructions which load a PC value
+ * from memory.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/kprobes.h>
+
+#include "kprobes.h"
+#include "kprobes-test.h"
+
+
+#define BENCHMARKING 1
+
+
+/*
+ * Test basic API
+ */
+
+static bool test_regs_ok;
+static int test_func_instance;
+static int pre_handler_called;
+static int post_handler_called;
+static int jprobe_func_called;
+static int kretprobe_handler_called;
+
+#define FUNC_ARG1 0x12345678
+#define FUNC_ARG2 0xabcdef
+
+
+#ifndef CONFIG_THUMB2_KERNEL
+
+long arm_func(long r0, long r1);
+
+static void __used __naked __arm_kprobes_test_func(void)
+{
+ __asm__ __volatile__ (
+ ".arm \n\t"
+ ".type arm_func, %%function \n\t"
+ "arm_func: \n\t"
+ "adds r0, r0, r1 \n\t"
+ "bx lr \n\t"
+ ".code "NORMAL_ISA /* Back to Thumb if necessary */
+ : : : "r0", "r1", "cc"
+ );
+}
+
+#else /* CONFIG_THUMB2_KERNEL */
+
+long thumb16_func(long r0, long r1);
+long thumb32even_func(long r0, long r1);
+long thumb32odd_func(long r0, long r1);
+
+static void __used __naked __thumb_kprobes_test_funcs(void)
+{
+ __asm__ __volatile__ (
+ ".type thumb16_func, %%function \n\t"
+ "thumb16_func: \n\t"
+ "adds.n r0, r0, r1 \n\t"
+ "bx lr \n\t"
+
+ ".align \n\t"
+ ".type thumb32even_func, %%function \n\t"
+ "thumb32even_func: \n\t"
+ "adds.w r0, r0, r1 \n\t"
+ "bx lr \n\t"
+
+ ".align \n\t"
+ "nop.n \n\t"
+ ".type thumb32odd_func, %%function \n\t"
+ "thumb32odd_func: \n\t"
+ "adds.w r0, r0, r1 \n\t"
+ "bx lr \n\t"
+
+ : : : "r0", "r1", "cc"
+ );
+}
+
+#endif /* CONFIG_THUMB2_KERNEL */
+
+
+static int call_test_func(long (*func)(long, long), bool check_test_regs)
+{
+ long ret;
+
+ ++test_func_instance;
+ test_regs_ok = false;
+
+ ret = (*func)(FUNC_ARG1, FUNC_ARG2);
+ if (ret != FUNC_ARG1 + FUNC_ARG2) {
+ pr_err("FAIL: call_test_func: func returned %lx\n", ret);
+ return false;
+ }
+
+ if (check_test_regs && !test_regs_ok) {
+ pr_err("FAIL: test regs not OK\n");
+ return false;
+ }
+
+ return true;
+}
+
+static int __kprobes pre_handler(struct kprobe *p, struct pt_regs *regs)
+{
+ pre_handler_called = test_func_instance;
+ if (regs->ARM_r0 == FUNC_ARG1 && regs->ARM_r1 == FUNC_ARG2)
+ test_regs_ok = true;
+ return 0;
+}
+
+static void __kprobes post_handler(struct kprobe *p, struct pt_regs *regs,
+ unsigned long flags)
+{
+ post_handler_called = test_func_instance;
+ if (regs->ARM_r0 != FUNC_ARG1 + FUNC_ARG2 || regs->ARM_r1 != FUNC_ARG2)
+ test_regs_ok = false;
+}
+
+static struct kprobe the_kprobe = {
+ .addr = 0,
+ .pre_handler = pre_handler,
+ .post_handler = post_handler
+};
+
+static int test_kprobe(long (*func)(long, long))
+{
+ int ret;
+
+ the_kprobe.addr = (kprobe_opcode_t *)func;
+ ret = register_kprobe(&the_kprobe);
+ if (ret < 0) {
+ pr_err("FAIL: register_kprobe failed with %d\n", ret);
+ return ret;
+ }
+
+ ret = call_test_func(func, true);
+
+ unregister_kprobe(&the_kprobe);
+ the_kprobe.flags = 0; /* Clear disable flag to allow reuse */
+
+ if (!ret)
+ return -EINVAL;
+ if (pre_handler_called != test_func_instance) {
+ pr_err("FAIL: kprobe pre_handler not called\n");
+ return -EINVAL;
+ }
+ if (post_handler_called != test_func_instance) {
+ pr_err("FAIL: kprobe post_handler not called\n");
+ return -EINVAL;
+ }
+ if (!call_test_func(func, false))
+ return -EINVAL;
+ if (pre_handler_called == test_func_instance ||
+ post_handler_called == test_func_instance) {
+ pr_err("FAIL: probe called after unregistering\n");
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static void __kprobes jprobe_func(long r0, long r1)
+{
+ jprobe_func_called = test_func_instance;
+ if (r0 == FUNC_ARG1 && r1 == FUNC_ARG2)
+ test_regs_ok = true;
+ jprobe_return();
+}
+
+static struct jprobe the_jprobe = {
+ .entry = jprobe_func,
+};
+
+static int test_jprobe(long (*func)(long, long))
+{
+ int ret;
+
+ the_jprobe.kp.addr = (kprobe_opcode_t *)func;
+ ret = register_jprobe(&the_jprobe);
+ if (ret < 0) {
+ pr_err("FAIL: register_jprobe failed with %d\n", ret);
+ return ret;
+ }
+
+ ret = call_test_func(func, true);
+
+ unregister_jprobe(&the_jprobe);
+ the_jprobe.kp.flags = 0; /* Clear disable flag to allow reuse */
+
+ if (!ret)
+ return -EINVAL;
+ if (jprobe_func_called != test_func_instance) {
+ pr_err("FAIL: jprobe handler function not called\n");
+ return -EINVAL;
+ }
+ if (!call_test_func(func, false))
+ return -EINVAL;
+ if (jprobe_func_called == test_func_instance) {
+ pr_err("FAIL: probe called after unregistering\n");
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int __kprobes
+kretprobe_handler(struct kretprobe_instance *ri, struct pt_regs *regs)
+{
+ kretprobe_handler_called = test_func_instance;
+ if (regs_return_value(regs) == FUNC_ARG1 + FUNC_ARG2)
+ test_regs_ok = true;
+ return 0;
+}
+
+static struct kretprobe the_kretprobe = {
+ .handler = kretprobe_handler,
+};
+
+static int test_kretprobe(long (*func)(long, long))
+{
+ int ret;
+
+ the_kretprobe.kp.addr = (kprobe_opcode_t *)func;
+ ret = register_kretprobe(&the_kretprobe);
+ if (ret < 0) {
+ pr_err("FAIL: register_kretprobe failed with %d\n", ret);
+ return ret;
+ }
+
+ ret = call_test_func(func, true);
+
+ unregister_kretprobe(&the_kretprobe);
+ the_kretprobe.kp.flags = 0; /* Clear disable flag to allow reuse */
+
+ if (!ret)
+ return -EINVAL;
+ if (kretprobe_handler_called != test_func_instance) {
+ pr_err("FAIL: kretprobe handler not called\n");
+ return -EINVAL;
+ }
+ if (!call_test_func(func, false))
+ return -EINVAL;
+ if (jprobe_func_called == test_func_instance) {
+ pr_err("FAIL: kretprobe called after unregistering\n");
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int run_api_tests(long (*func)(long, long))
+{
+ int ret;
+
+ pr_info(" kprobe\n");
+ ret = test_kprobe(func);
+ if (ret < 0)
+ return ret;
+
+ pr_info(" jprobe\n");
+ ret = test_jprobe(func);
+ if (ret < 0)
+ return ret;
+
+ pr_info(" kretprobe\n");
+ ret = test_kretprobe(func);
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
+
+/*
+ * Benchmarking
+ */
+
+#if BENCHMARKING
+
+static void __naked benchmark_nop(void)
+{
+ __asm__ __volatile__ (
+ "nop \n\t"
+ "bx lr"
+ );
+}
+
+#ifdef CONFIG_THUMB2_KERNEL
+#define wide ".w"
+#else
+#define wide
+#endif
+
+static void __naked benchmark_pushpop1(void)
+{
+ __asm__ __volatile__ (
+ "stmdb"wide" sp!, {r3-r11,lr} \n\t"
+ "ldmia"wide" sp!, {r3-r11,pc}"
+ );
+}
+
+static void __naked benchmark_pushpop2(void)
+{
+ __asm__ __volatile__ (
+ "stmdb"wide" sp!, {r0-r8,lr} \n\t"
+ "ldmia"wide" sp!, {r0-r8,pc}"
+ );
+}
+
+static void __naked benchmark_pushpop3(void)
+{
+ __asm__ __volatile__ (
+ "stmdb"wide" sp!, {r4,lr} \n\t"
+ "ldmia"wide" sp!, {r4,pc}"
+ );
+}
+
+static void __naked benchmark_pushpop4(void)
+{
+ __asm__ __volatile__ (
+ "stmdb"wide" sp!, {r0,lr} \n\t"
+ "ldmia"wide" sp!, {r0,pc}"
+ );
+}
+
+
+#ifdef CONFIG_THUMB2_KERNEL
+
+static void __naked benchmark_pushpop_thumb(void)
+{
+ __asm__ __volatile__ (
+ "push.n {r0-r7,lr} \n\t"
+ "pop.n {r0-r7,pc}"
+ );
+}
+
+#endif
+
+static int __kprobes
+benchmark_pre_handler(struct kprobe *p, struct pt_regs *regs)
+{
+ return 0;
+}
+
+static int benchmark(void(*fn)(void))
+{
+ unsigned n, i, t, t0;
+
+ for (n = 1000; ; n *= 2) {
+ t0 = sched_clock();
+ for (i = n; i > 0; --i)
+ fn();
+ t = sched_clock() - t0;
+ if (t >= 250000000)
+ break; /* Stop once we took more than 0.25 seconds */
+ }
+ return t / n; /* Time for one iteration in nanoseconds */
+};
+
+static int kprobe_benchmark(void(*fn)(void), unsigned offset)
+{
+ struct kprobe k = {
+ .addr = (kprobe_opcode_t *)((uintptr_t)fn + offset),
+ .pre_handler = benchmark_pre_handler,
+ };
+
+ int ret = register_kprobe(&k);
+ if (ret < 0) {
+ pr_err("FAIL: register_kprobe failed with %d\n", ret);
+ return ret;
+ }
+
+ ret = benchmark(fn);
+
+ unregister_kprobe(&k);
+ return ret;
+};
+
+struct benchmarks {
+ void (*fn)(void);
+ unsigned offset;
+ const char *title;
+};
+
+static int run_benchmarks(void)
+{
+ int ret;
+ struct benchmarks list[] = {
+ {&benchmark_nop, 0, "nop"},
+ /*
+ * benchmark_pushpop{1,3} will have the optimised
+ * instruction emulation, whilst benchmark_pushpop{2,4} will
+ * be the equivalent unoptimised instructions.
+ */
+ {&benchmark_pushpop1, 0, "stmdb sp!, {r3-r11,lr}"},
+ {&benchmark_pushpop1, 4, "ldmia sp!, {r3-r11,pc}"},
+ {&benchmark_pushpop2, 0, "stmdb sp!, {r0-r8,lr}"},
+ {&benchmark_pushpop2, 4, "ldmia sp!, {r0-r8,pc}"},
+ {&benchmark_pushpop3, 0, "stmdb sp!, {r4,lr}"},
+ {&benchmark_pushpop3, 4, "ldmia sp!, {r4,pc}"},
+ {&benchmark_pushpop4, 0, "stmdb sp!, {r0,lr}"},
+ {&benchmark_pushpop4, 4, "ldmia sp!, {r0,pc}"},
+#ifdef CONFIG_THUMB2_KERNEL
+ {&benchmark_pushpop_thumb, 0, "push.n {r0-r7,lr}"},
+ {&benchmark_pushpop_thumb, 2, "pop.n {r0-r7,pc}"},
+#endif
+ {0}
+ };
+
+ struct benchmarks *b;
+ for (b = list; b->fn; ++b) {
+ ret = kprobe_benchmark(b->fn, b->offset);
+ if (ret < 0)
+ return ret;
+ pr_info(" %dns for kprobe %s\n", ret, b->title);
+ }
+
+ pr_info("\n");
+ return 0;
+}
+
+#endif /* BENCHMARKING */
+
+
+/*
+ * Decoding table self-consistency tests
+ */
+
+static const int decode_struct_sizes[NUM_DECODE_TYPES] = {
+ [DECODE_TYPE_TABLE] = sizeof(struct decode_table),
+ [DECODE_TYPE_CUSTOM] = sizeof(struct decode_custom),
+ [DECODE_TYPE_SIMULATE] = sizeof(struct decode_simulate),
+ [DECODE_TYPE_EMULATE] = sizeof(struct decode_emulate),
+ [DECODE_TYPE_OR] = sizeof(struct decode_or),
+ [DECODE_TYPE_REJECT] = sizeof(struct decode_reject)
+};
+
+static int table_iter(const union decode_item *table,
+ int (*fn)(const struct decode_header *, void *),
+ void *args)
+{
+ const struct decode_header *h = (struct decode_header *)table;
+ int result;
+
+ for (;;) {
+ enum decode_type type = h->type_regs.bits & DECODE_TYPE_MASK;
+
+ if (type == DECODE_TYPE_END)
+ return 0;
+
+ result = fn(h, args);
+ if (result)
+ return result;
+
+ h = (struct decode_header *)
+ ((uintptr_t)h + decode_struct_sizes[type]);
+
+ }
+}
+
+static int table_test_fail(const struct decode_header *h, const char* message)
+{
+
+ pr_err("FAIL: kprobes test failure \"%s\" (mask %08x, value %08x)\n",
+ message, h->mask.bits, h->value.bits);
+ return -EINVAL;
+}
+
+struct table_test_args {
+ const union decode_item *root_table;
+ u32 parent_mask;
+ u32 parent_value;
+};
+
+static int table_test_fn(const struct decode_header *h, void *args)
+{
+ struct table_test_args *a = (struct table_test_args *)args;
+ enum decode_type type = h->type_regs.bits & DECODE_TYPE_MASK;
+
+ if (h->value.bits & ~h->mask.bits)
+ return table_test_fail(h, "Match value has bits not in mask");
+
+ if ((h->mask.bits & a->parent_mask) != a->parent_mask)
+ return table_test_fail(h, "Mask has bits not in parent mask");
+
+ if ((h->value.bits ^ a->parent_value) & a->parent_mask)
+ return table_test_fail(h, "Value is inconsistent with parent");
+
+ if (type == DECODE_TYPE_TABLE) {
+ struct decode_table *d = (struct decode_table *)h;
+ struct table_test_args args2 = *a;
+ args2.parent_mask = h->mask.bits;
+ args2.parent_value = h->value.bits;
+ return table_iter(d->table.table, table_test_fn, &args2);
+ }
+
+ return 0;
+}
+
+static int table_test(const union decode_item *table)
+{
+ struct table_test_args args = {
+ .root_table = table,
+ .parent_mask = 0,
+ .parent_value = 0
+ };
+ return table_iter(args.root_table, table_test_fn, &args);
+}
+
+
+/*
+ * Decoding table test coverage analysis
+ *
+ * coverage_start() builds a coverage_table which contains a list of
+ * coverage_entry's to match each entry in the specified kprobes instruction
+ * decoding table.
+ *
+ * When test cases are run, coverage_add() is called to process each case.
+ * This looks up the corresponding entry in the coverage_table and sets it as
+ * being matched, as well as clearing the regs flag appropriate for the test.
+ *
+ * After all test cases have been run, coverage_end() is called to check that
+ * all entries in coverage_table have been matched and that all regs flags are
+ * cleared. I.e. that all possible combinations of instructions described by
+ * the kprobes decoding tables have had a test case executed for them.
+ */
+
+bool coverage_fail;
+
+#define MAX_COVERAGE_ENTRIES 256
+
+struct coverage_entry {
+ const struct decode_header *header;
+ unsigned regs;
+ unsigned nesting;
+ char matched;
+};
+
+struct coverage_table {
+ struct coverage_entry *base;
+ unsigned num_entries;
+ unsigned nesting;
+};
+
+struct coverage_table coverage;
+
+#define COVERAGE_ANY_REG (1<<0)
+#define COVERAGE_SP (1<<1)
+#define COVERAGE_PC (1<<2)
+#define COVERAGE_PCWB (1<<3)
+
+static const char coverage_register_lookup[16] = {
+ [REG_TYPE_ANY] = COVERAGE_ANY_REG | COVERAGE_SP | COVERAGE_PC,
+ [REG_TYPE_SAMEAS16] = COVERAGE_ANY_REG,
+ [REG_TYPE_SP] = COVERAGE_SP,
+ [REG_TYPE_PC] = COVERAGE_PC,
+ [REG_TYPE_NOSP] = COVERAGE_ANY_REG | COVERAGE_SP,
+ [REG_TYPE_NOSPPC] = COVERAGE_ANY_REG | COVERAGE_SP | COVERAGE_PC,
+ [REG_TYPE_NOPC] = COVERAGE_ANY_REG | COVERAGE_PC,
+ [REG_TYPE_NOPCWB] = COVERAGE_ANY_REG | COVERAGE_PC | COVERAGE_PCWB,
+ [REG_TYPE_NOPCX] = COVERAGE_ANY_REG,
+ [REG_TYPE_NOSPPCX] = COVERAGE_ANY_REG | COVERAGE_SP,
+};
+
+unsigned coverage_start_registers(const struct decode_header *h)
+{
+ unsigned regs = 0;
+ int i;
+ for (i = 0; i < 20; i += 4) {
+ int r = (h->type_regs.bits >> (DECODE_TYPE_BITS + i)) & 0xf;
+ regs |= coverage_register_lookup[r] << i;
+ }
+ return regs;
+}
+
+static int coverage_start_fn(const struct decode_header *h, void *args)
+{
+ struct coverage_table *coverage = (struct coverage_table *)args;
+ enum decode_type type = h->type_regs.bits & DECODE_TYPE_MASK;
+ struct coverage_entry *entry = coverage->base + coverage->num_entries;
+
+ if (coverage->num_entries == MAX_COVERAGE_ENTRIES - 1) {
+ pr_err("FAIL: Out of space for test coverage data");
+ return -ENOMEM;
+ }
+
+ ++coverage->num_entries;
+
+ entry->header = h;
+ entry->regs = coverage_start_registers(h);
+ entry->nesting = coverage->nesting;
+ entry->matched = false;
+
+ if (type == DECODE_TYPE_TABLE) {
+ struct decode_table *d = (struct decode_table *)h;
+ int ret;
+ ++coverage->nesting;
+ ret = table_iter(d->table.table, coverage_start_fn, coverage);
+ --coverage->nesting;
+ return ret;
+ }
+
+ return 0;
+}
+
+static int coverage_start(const union decode_item *table)
+{
+ coverage.base = kmalloc(MAX_COVERAGE_ENTRIES *
+ sizeof(struct coverage_entry), GFP_KERNEL);
+ coverage.num_entries = 0;
+ coverage.nesting = 0;
+ return table_iter(table, coverage_start_fn, &coverage);
+}
+
+static void
+coverage_add_registers(struct coverage_entry *entry, kprobe_opcode_t insn)
+{
+ int regs = entry->header->type_regs.bits >> DECODE_TYPE_BITS;
+ int i;
+ for (i = 0; i < 20; i += 4) {
+ enum decode_reg_type reg_type = (regs >> i) & 0xf;
+ int reg = (insn >> i) & 0xf;
+ int flag;
+
+ if (!reg_type)
+ continue;
+
+ if (reg == 13)
+ flag = COVERAGE_SP;
+ else if (reg == 15)
+ flag = COVERAGE_PC;
+ else
+ flag = COVERAGE_ANY_REG;
+ entry->regs &= ~(flag << i);
+
+ switch (reg_type) {
+
+ case REG_TYPE_NONE:
+ case REG_TYPE_ANY:
+ case REG_TYPE_SAMEAS16:
+ break;
+
+ case REG_TYPE_SP:
+ if (reg != 13)
+ return;
+ break;
+
+ case REG_TYPE_PC:
+ if (reg != 15)
+ return;
+ break;
+
+ case REG_TYPE_NOSP:
+ if (reg == 13)
+ return;
+ break;
+
+ case REG_TYPE_NOSPPC:
+ case REG_TYPE_NOSPPCX:
+ if (reg == 13 || reg == 15)
+ return;
+ break;
+
+ case REG_TYPE_NOPCWB:
+ if (!is_writeback(insn))
+ break;
+ if (reg == 15) {
+ entry->regs &= ~(COVERAGE_PCWB << i);
+ return;
+ }
+ break;
+
+ case REG_TYPE_NOPC:
+ case REG_TYPE_NOPCX:
+ if (reg == 15)
+ return;
+ break;
+ }
+
+ }
+}
+
+static void coverage_add(kprobe_opcode_t insn)
+{
+ struct coverage_entry *entry = coverage.base;
+ struct coverage_entry *end = coverage.base + coverage.num_entries;
+ bool matched = false;
+ unsigned nesting = 0;
+
+ for (; entry < end; ++entry) {
+ const struct decode_header *h = entry->header;
+ enum decode_type type = h->type_regs.bits & DECODE_TYPE_MASK;
+
+ if (entry->nesting > nesting)
+ continue; /* Skip sub-table we didn't match */
+
+ if (entry->nesting < nesting)
+ break; /* End of sub-table we were scanning */
+
+ if (!matched) {
+ if ((insn & h->mask.bits) != h->value.bits)
+ continue;
+ entry->matched = true;
+ }
+
+ switch (type) {
+
+ case DECODE_TYPE_TABLE:
+ ++nesting;
+ break;
+
+ case DECODE_TYPE_CUSTOM:
+ case DECODE_TYPE_SIMULATE:
+ case DECODE_TYPE_EMULATE:
+ coverage_add_registers(entry, insn);
+ return;
+
+ case DECODE_TYPE_OR:
+ matched = true;
+ break;
+
+ case DECODE_TYPE_REJECT:
+ default:
+ return;
+ }
+
+ }
+}
+
+static void coverage_end(void)
+{
+ struct coverage_entry *entry = coverage.base;
+ struct coverage_entry *end = coverage.base + coverage.num_entries;
+
+ for (; entry < end; ++entry) {
+ u32 mask = entry->header->mask.bits;
+ u32 value = entry->header->value.bits;
+
+ if (entry->regs) {
+ pr_err("FAIL: Register test coverage missing for %08x %08x (%05x)\n",
+ mask, value, entry->regs);
+ coverage_fail = true;
+ }
+ if (!entry->matched) {
+ pr_err("FAIL: Test coverage entry missing for %08x %08x\n",
+ mask, value);
+ coverage_fail = true;
+ }
+ }
+
+ kfree(coverage.base);
+}
+
+
+/*
+ * Framework for instruction set test cases
+ */
+
+void __naked __kprobes_test_case_start(void)
+{
+ __asm__ __volatile__ (
+ "stmdb sp!, {r4-r11} \n\t"
+ "sub sp, sp, #"__stringify(TEST_MEMORY_SIZE)"\n\t"
+ "bic r0, lr, #1 @ r0 = inline title string \n\t"
+ "mov r1, sp \n\t"
+ "bl kprobes_test_case_start \n\t"
+ "bx r0 \n\t"
+ );
+}
+
+#ifndef CONFIG_THUMB2_KERNEL
+
+void __naked __kprobes_test_case_end_32(void)
+{
+ __asm__ __volatile__ (
+ "mov r4, lr \n\t"
+ "bl kprobes_test_case_end \n\t"
+ "cmp r0, #0 \n\t"
+ "movne pc, r0 \n\t"
+ "mov r0, r4 \n\t"
+ "add sp, sp, #"__stringify(TEST_MEMORY_SIZE)"\n\t"
+ "ldmia sp!, {r4-r11} \n\t"
+ "mov pc, r0 \n\t"
+ );
+}
+
+#else /* CONFIG_THUMB2_KERNEL */
+
+void __naked __kprobes_test_case_end_16(void)
+{
+ __asm__ __volatile__ (
+ "mov r4, lr \n\t"
+ "bl kprobes_test_case_end \n\t"
+ "cmp r0, #0 \n\t"
+ "bxne r0 \n\t"
+ "mov r0, r4 \n\t"
+ "add sp, sp, #"__stringify(TEST_MEMORY_SIZE)"\n\t"
+ "ldmia sp!, {r4-r11} \n\t"
+ "bx r0 \n\t"
+ );
+}
+
+void __naked __kprobes_test_case_end_32(void)
+{
+ __asm__ __volatile__ (
+ ".arm \n\t"
+ "orr lr, lr, #1 @ will return to Thumb code \n\t"
+ "ldr pc, 1f \n\t"
+ "1: \n\t"
+ ".word __kprobes_test_case_end_16 \n\t"
+ );
+}
+
+#endif
+
+
+int kprobe_test_flags;
+int kprobe_test_cc_position;
+
+static int test_try_count;
+static int test_pass_count;
+static int test_fail_count;
+
+static struct pt_regs initial_regs;
+static struct pt_regs expected_regs;
+static struct pt_regs result_regs;
+
+static u32 expected_memory[TEST_MEMORY_SIZE/sizeof(u32)];
+
+static const char *current_title;
+static struct test_arg *current_args;
+static u32 *current_stack;
+static uintptr_t current_branch_target;
+
+static uintptr_t current_code_start;
+static kprobe_opcode_t current_instruction;
+
+
+#define TEST_CASE_PASSED -1
+#define TEST_CASE_FAILED -2
+
+static int test_case_run_count;
+static bool test_case_is_thumb;
+static int test_instance;
+
+/*
+ * We ignore the state of the imprecise abort disable flag (CPSR.A) because this
+ * can change randomly as the kernel doesn't take care to preserve or initialise
+ * this across context switches. Also, with Security Extentions, the flag may
+ * not be under control of the kernel; for this reason we ignore the state of
+ * the FIQ disable flag CPSR.F as well.
+ */
+#define PSR_IGNORE_BITS (PSR_A_BIT | PSR_F_BIT)
+
+static unsigned long test_check_cc(int cc, unsigned long cpsr)
+{
+ unsigned long temp;
+
+ switch (cc) {
+ case 0x0: /* eq */
+ return cpsr & PSR_Z_BIT;
+
+ case 0x1: /* ne */
+ return (~cpsr) & PSR_Z_BIT;
+
+ case 0x2: /* cs */
+ return cpsr & PSR_C_BIT;
+
+ case 0x3: /* cc */
+ return (~cpsr) & PSR_C_BIT;
+
+ case 0x4: /* mi */
+ return cpsr & PSR_N_BIT;
+
+ case 0x5: /* pl */
+ return (~cpsr) & PSR_N_BIT;
+
+ case 0x6: /* vs */
+ return cpsr & PSR_V_BIT;
+
+ case 0x7: /* vc */
+ return (~cpsr) & PSR_V_BIT;
+
+ case 0x8: /* hi */
+ cpsr &= ~(cpsr >> 1); /* PSR_C_BIT &= ~PSR_Z_BIT */
+ return cpsr & PSR_C_BIT;
+
+ case 0x9: /* ls */
+ cpsr &= ~(cpsr >> 1); /* PSR_C_BIT &= ~PSR_Z_BIT */
+ return (~cpsr) & PSR_C_BIT;
+
+ case 0xa: /* ge */
+ cpsr ^= (cpsr << 3); /* PSR_N_BIT ^= PSR_V_BIT */
+ return (~cpsr) & PSR_N_BIT;
+
+ case 0xb: /* lt */
+ cpsr ^= (cpsr << 3); /* PSR_N_BIT ^= PSR_V_BIT */
+ return cpsr & PSR_N_BIT;
+
+ case 0xc: /* gt */
+ temp = cpsr ^ (cpsr << 3); /* PSR_N_BIT ^= PSR_V_BIT */
+ temp |= (cpsr << 1); /* PSR_N_BIT |= PSR_Z_BIT */
+ return (~temp) & PSR_N_BIT;
+
+ case 0xd: /* le */
+ temp = cpsr ^ (cpsr << 3); /* PSR_N_BIT ^= PSR_V_BIT */
+ temp |= (cpsr << 1); /* PSR_N_BIT |= PSR_Z_BIT */
+ return temp & PSR_N_BIT;
+
+ case 0xe: /* al */
+ case 0xf: /* unconditional */
+ return true;
+ }
+ BUG();
+ return false;
+}
+
+static int is_last_scenario;
+static int probe_should_run; /* 0 = no, 1 = yes, -1 = unknown */
+static int memory_needs_checking;
+
+static unsigned long test_context_cpsr(int scenario)
+{
+ unsigned long cpsr;
+
+ probe_should_run = 1;
+
+ /* Default case is that we cycle through 16 combinations of flags */
+ cpsr = (scenario & 0xf) << 28; /* N,Z,C,V flags */
+ cpsr |= (scenario & 0xf) << 16; /* GE flags */
+ cpsr |= (scenario & 0x1) << 27; /* Toggle Q flag */
+
+ if (!test_case_is_thumb) {
+ /* Testing ARM code */
+ probe_should_run = test_check_cc(current_instruction >> 28, cpsr) != 0;
+ if (scenario == 15)
+ is_last_scenario = true;
+
+ } else if (kprobe_test_flags & TEST_FLAG_NO_ITBLOCK) {
+ /* Testing Thumb code without setting ITSTATE */
+ if (kprobe_test_cc_position) {
+ int cc = (current_instruction >> kprobe_test_cc_position) & 0xf;
+ probe_should_run = test_check_cc(cc, cpsr) != 0;
+ }
+
+ if (scenario == 15)
+ is_last_scenario = true;
+
+ } else if (kprobe_test_flags & TEST_FLAG_FULL_ITBLOCK) {
+ /* Testing Thumb code with all combinations of ITSTATE */
+ unsigned x = (scenario >> 4);
+ unsigned cond_base = x % 7; /* ITSTATE<7:5> */
+ unsigned mask = x / 7 + 2; /* ITSTATE<4:0>, bits reversed */
+
+ if (mask > 0x1f) {
+ /* Finish by testing state from instruction 'itt al' */
+ cond_base = 7;
+ mask = 0x4;
+ if ((scenario & 0xf) == 0xf)
+ is_last_scenario = true;
+ }
+
+ cpsr |= cond_base << 13; /* ITSTATE<7:5> */
+ cpsr |= (mask & 0x1) << 12; /* ITSTATE<4> */
+ cpsr |= (mask & 0x2) << 10; /* ITSTATE<3> */
+ cpsr |= (mask & 0x4) << 8; /* ITSTATE<2> */
+ cpsr |= (mask & 0x8) << 23; /* ITSTATE<1> */
+ cpsr |= (mask & 0x10) << 21; /* ITSTATE<0> */
+
+ probe_should_run = test_check_cc((cpsr >> 12) & 0xf, cpsr) != 0;
+
+ } else {
+ /* Testing Thumb code with several combinations of ITSTATE */
+ switch (scenario) {
+ case 16: /* Clear NZCV flags and 'it eq' state (false as Z=0) */
+ cpsr = 0x00000800;
+ probe_should_run = 0;
+ break;
+ case 17: /* Set NZCV flags and 'it vc' state (false as V=1) */
+ cpsr = 0xf0007800;
+ probe_should_run = 0;
+ break;
+ case 18: /* Clear NZCV flags and 'it ls' state (true as C=0) */
+ cpsr = 0x00009800;
+ break;
+ case 19: /* Set NZCV flags and 'it cs' state (true as C=1) */
+ cpsr = 0xf0002800;
+ is_last_scenario = true;
+ break;
+ }
+ }
+
+ return cpsr;
+}
+
+static void setup_test_context(struct pt_regs *regs)
+{
+ int scenario = test_case_run_count>>1;
+ unsigned long val;
+ struct test_arg *args;
+ int i;
+
+ is_last_scenario = false;
+ memory_needs_checking = false;
+
+ /* Initialise test memory on stack */
+ val = (scenario & 1) ? VALM : ~VALM;
+ for (i = 0; i < TEST_MEMORY_SIZE / sizeof(current_stack[0]); ++i)
+ current_stack[i] = val + (i << 8);
+ /* Put target of branch on stack for tests which load PC from memory */
+ if (current_branch_target)
+ current_stack[15] = current_branch_target;
+ /* Put a value for SP on stack for tests which load SP from memory */
+ current_stack[13] = (u32)current_stack + 120;
+
+ /* Initialise register values to their default state */
+ val = (scenario & 2) ? VALR : ~VALR;
+ for (i = 0; i < 13; ++i)
+ regs->uregs[i] = val ^ (i << 8);
+ regs->ARM_lr = val ^ (14 << 8);
+ regs->ARM_cpsr &= ~(APSR_MASK | PSR_IT_MASK);
+ regs->ARM_cpsr |= test_context_cpsr(scenario);
+
+ /* Perform testcase specific register setup */
+ args = current_args;
+ for (; args[0].type != ARG_TYPE_END; ++args)
+ switch (args[0].type) {
+ case ARG_TYPE_REG: {
+ struct test_arg_regptr *arg =
+ (struct test_arg_regptr *)args;
+ regs->uregs[arg->reg] = arg->val;
+ break;
+ }
+ case ARG_TYPE_PTR: {
+ struct test_arg_regptr *arg =
+ (struct test_arg_regptr *)args;
+ regs->uregs[arg->reg] =
+ (unsigned long)current_stack + arg->val;
+ memory_needs_checking = true;
+ break;
+ }
+ case ARG_TYPE_MEM: {
+ struct test_arg_mem *arg = (struct test_arg_mem *)args;
+ current_stack[arg->index] = arg->val;
+ break;
+ }
+ default:
+ break;
+ }
+}
+
+struct test_probe {
+ struct kprobe kprobe;
+ bool registered;
+ int hit;
+};
+
+static void unregister_test_probe(struct test_probe *probe)
+{
+ if (probe->registered) {
+ unregister_kprobe(&probe->kprobe);
+ probe->kprobe.flags = 0; /* Clear disable flag to allow reuse */
+ }
+ probe->registered = false;
+}
+
+static int register_test_probe(struct test_probe *probe)
+{
+ int ret;
+
+ if (probe->registered)
+ BUG();
+
+ ret = register_kprobe(&probe->kprobe);
+ if (ret >= 0) {
+ probe->registered = true;
+ probe->hit = -1;
+ }
+ return ret;
+}
+
+static int __kprobes
+test_before_pre_handler(struct kprobe *p, struct pt_regs *regs)
+{
+ container_of(p, struct test_probe, kprobe)->hit = test_instance;
+ return 0;
+}
+
+static void __kprobes
+test_before_post_handler(struct kprobe *p, struct pt_regs *regs,
+ unsigned long flags)
+{
+ setup_test_context(regs);
+ initial_regs = *regs;
+ initial_regs.ARM_cpsr &= ~PSR_IGNORE_BITS;
+}
+
+static int __kprobes
+test_case_pre_handler(struct kprobe *p, struct pt_regs *regs)
+{
+ container_of(p, struct test_probe, kprobe)->hit = test_instance;
+ return 0;
+}
+
+static int __kprobes
+test_after_pre_handler(struct kprobe *p, struct pt_regs *regs)
+{
+ if (container_of(p, struct test_probe, kprobe)->hit == test_instance)
+ return 0; /* Already run for this test instance */
+
+ result_regs = *regs;
+ result_regs.ARM_cpsr &= ~PSR_IGNORE_BITS;
+
+ /* Undo any changes done to SP by the test case */
+ regs->ARM_sp = (unsigned long)current_stack;
+
+ container_of(p, struct test_probe, kprobe)->hit = test_instance;
+ return 0;
+}
+
+static struct test_probe test_before_probe = {
+ .kprobe.pre_handler = test_before_pre_handler,
+ .kprobe.post_handler = test_before_post_handler,
+};
+
+static struct test_probe test_case_probe = {
+ .kprobe.pre_handler = test_case_pre_handler,
+};
+
+static struct test_probe test_after_probe = {
+ .kprobe.pre_handler = test_after_pre_handler,
+};
+
+static struct test_probe test_after2_probe = {
+ .kprobe.pre_handler = test_after_pre_handler,
+};
+
+static void test_case_cleanup(void)
+{
+ unregister_test_probe(&test_before_probe);
+ unregister_test_probe(&test_case_probe);
+ unregister_test_probe(&test_after_probe);
+ unregister_test_probe(&test_after2_probe);
+}
+
+static void print_registers(struct pt_regs *regs)
+{
+ pr_err("r0 %08lx | r1 %08lx | r2 %08lx | r3 %08lx\n",
+ regs->ARM_r0, regs->ARM_r1, regs->ARM_r2, regs->ARM_r3);
+ pr_err("r4 %08lx | r5 %08lx | r6 %08lx | r7 %08lx\n",
+ regs->ARM_r4, regs->ARM_r5, regs->ARM_r6, regs->ARM_r7);
+ pr_err("r8 %08lx | r9 %08lx | r10 %08lx | r11 %08lx\n",
+ regs->ARM_r8, regs->ARM_r9, regs->ARM_r10, regs->ARM_fp);
+ pr_err("r12 %08lx | sp %08lx | lr %08lx | pc %08lx\n",
+ regs->ARM_ip, regs->ARM_sp, regs->ARM_lr, regs->ARM_pc);
+ pr_err("cpsr %08lx\n", regs->ARM_cpsr);
+}
+
+static void print_memory(u32 *mem, size_t size)
+{
+ int i;
+ for (i = 0; i < size / sizeof(u32); i += 4)
+ pr_err("%08x %08x %08x %08x\n", mem[i], mem[i+1],
+ mem[i+2], mem[i+3]);
+}
+
+static size_t expected_memory_size(u32 *sp)
+{
+ size_t size = sizeof(expected_memory);
+ int offset = (uintptr_t)sp - (uintptr_t)current_stack;
+ if (offset > 0)
+ size -= offset;
+ return size;
+}
+
+static void test_case_failed(const char *message)
+{
+ test_case_cleanup();
+
+ pr_err("FAIL: %s\n", message);
+ pr_err("FAIL: Test %s\n", current_title);
+ pr_err("FAIL: Scenario %d\n", test_case_run_count >> 1);
+}
+
+static unsigned long next_instruction(unsigned long pc)
+{
+#ifdef CONFIG_THUMB2_KERNEL
+ if ((pc & 1) && !is_wide_instruction(*(u16 *)(pc - 1)))
+ return pc + 2;
+ else
+#endif
+ return pc + 4;
+}
+
+static uintptr_t __used kprobes_test_case_start(const char *title, void *stack)
+{
+ struct test_arg *args;
+ struct test_arg_end *end_arg;
+ unsigned long test_code;
+
+ args = (struct test_arg *)PTR_ALIGN(title + strlen(title) + 1, 4);
+
+ current_title = title;
+ current_args = args;
+ current_stack = stack;
+
+ ++test_try_count;
+
+ while (args->type != ARG_TYPE_END)
+ ++args;
+ end_arg = (struct test_arg_end *)args;
+
+ test_code = (unsigned long)(args + 1); /* Code starts after args */
+
+ test_case_is_thumb = end_arg->flags & ARG_FLAG_THUMB;
+ if (test_case_is_thumb)
+ test_code |= 1;
+
+ current_code_start = test_code;
+
+ current_branch_target = 0;
+ if (end_arg->branch_offset != end_arg->end_offset)
+ current_branch_target = test_code + end_arg->branch_offset;
+
+ test_code += end_arg->code_offset;
+ test_before_probe.kprobe.addr = (kprobe_opcode_t *)test_code;
+
+ test_code = next_instruction(test_code);
+ test_case_probe.kprobe.addr = (kprobe_opcode_t *)test_code;
+
+ if (test_case_is_thumb) {
+ u16 *p = (u16 *)(test_code & ~1);
+ current_instruction = p[0];
+ if (is_wide_instruction(current_instruction)) {
+ current_instruction <<= 16;
+ current_instruction |= p[1];
+ }
+ } else {
+ current_instruction = *(u32 *)test_code;
+ }
+
+ if (current_title[0] == '.')
+ verbose("%s\n", current_title);
+ else
+ verbose("%s\t@ %0*x\n", current_title,
+ test_case_is_thumb ? 4 : 8,
+ current_instruction);
+
+ test_code = next_instruction(test_code);
+ test_after_probe.kprobe.addr = (kprobe_opcode_t *)test_code;
+
+ if (kprobe_test_flags & TEST_FLAG_NARROW_INSTR) {
+ if (!test_case_is_thumb ||
+ is_wide_instruction(current_instruction)) {
+ test_case_failed("expected 16-bit instruction");
+ goto fail;
+ }
+ } else {
+ if (test_case_is_thumb &&
+ !is_wide_instruction(current_instruction)) {
+ test_case_failed("expected 32-bit instruction");
+ goto fail;
+ }
+ }
+
+ coverage_add(current_instruction);
+
+ if (end_arg->flags & ARG_FLAG_UNSUPPORTED) {
+ if (register_test_probe(&test_case_probe) < 0)
+ goto pass;
+ test_case_failed("registered probe for unsupported instruction");
+ goto fail;
+ }
+
+ if (end_arg->flags & ARG_FLAG_SUPPORTED) {
+ if (register_test_probe(&test_case_probe) >= 0)
+ goto pass;
+ test_case_failed("couldn't register probe for supported instruction");
+ goto fail;
+ }
+
+ if (register_test_probe(&test_before_probe) < 0) {
+ test_case_failed("register test_before_probe failed");
+ goto fail;
+ }
+ if (register_test_probe(&test_after_probe) < 0) {
+ test_case_failed("register test_after_probe failed");
+ goto fail;
+ }
+ if (current_branch_target) {
+ test_after2_probe.kprobe.addr =
+ (kprobe_opcode_t *)current_branch_target;
+ if (register_test_probe(&test_after2_probe) < 0) {
+ test_case_failed("register test_after2_probe failed");
+ goto fail;
+ }
+ }
+
+ /* Start first run of test case */
+ test_case_run_count = 0;
+ ++test_instance;
+ return current_code_start;
+pass:
+ test_case_run_count = TEST_CASE_PASSED;
+ return (uintptr_t)test_after_probe.kprobe.addr;
+fail:
+ test_case_run_count = TEST_CASE_FAILED;
+ return (uintptr_t)test_after_probe.kprobe.addr;
+}
+
+static bool check_test_results(void)
+{
+ size_t mem_size = 0;
+ u32 *mem = 0;
+
+ if (memcmp(&expected_regs, &result_regs, sizeof(expected_regs))) {
+ test_case_failed("registers differ");
+ goto fail;
+ }
+
+ if (memory_needs_checking) {
+ mem = (u32 *)result_regs.ARM_sp;
+ mem_size = expected_memory_size(mem);
+ if (memcmp(expected_memory, mem, mem_size)) {
+ test_case_failed("test memory differs");
+ goto fail;
+ }
+ }
+
+ return true;
+
+fail:
+ pr_err("initial_regs:\n");
+ print_registers(&initial_regs);
+ pr_err("expected_regs:\n");
+ print_registers(&expected_regs);
+ pr_err("result_regs:\n");
+ print_registers(&result_regs);
+
+ if (mem) {
+ pr_err("current_stack=%p\n", current_stack);
+ pr_err("expected_memory:\n");
+ print_memory(expected_memory, mem_size);
+ pr_err("result_memory:\n");
+ print_memory(mem, mem_size);
+ }
+
+ return false;
+}
+
+static uintptr_t __used kprobes_test_case_end(void)
+{
+ if (test_case_run_count < 0) {
+ if (test_case_run_count == TEST_CASE_PASSED)
+ /* kprobes_test_case_start did all the needed testing */
+ goto pass;
+ else
+ /* kprobes_test_case_start failed */
+ goto fail;
+ }
+
+ if (test_before_probe.hit != test_instance) {
+ test_case_failed("test_before_handler not run");
+ goto fail;
+ }
+
+ if (test_after_probe.hit != test_instance &&
+ test_after2_probe.hit != test_instance) {
+ test_case_failed("test_after_handler not run");
+ goto fail;
+ }
+
+ /*
+ * Even numbered test runs ran without a probe on the test case so
+ * we can gather reference results. The subsequent odd numbered run
+ * will have the probe inserted.
+ */
+ if ((test_case_run_count & 1) == 0) {
+ /* Save results from run without probe */
+ u32 *mem = (u32 *)result_regs.ARM_sp;
+ expected_regs = result_regs;
+ memcpy(expected_memory, mem, expected_memory_size(mem));
+
+ /* Insert probe onto test case instruction */
+ if (register_test_probe(&test_case_probe) < 0) {
+ test_case_failed("register test_case_probe failed");
+ goto fail;
+ }
+ } else {
+ /* Check probe ran as expected */
+ if (probe_should_run == 1) {
+ if (test_case_probe.hit != test_instance) {
+ test_case_failed("test_case_handler not run");
+ goto fail;
+ }
+ } else if (probe_should_run == 0) {
+ if (test_case_probe.hit == test_instance) {
+ test_case_failed("test_case_handler ran");
+ goto fail;
+ }
+ }
+
+ /* Remove probe for any subsequent reference run */
+ unregister_test_probe(&test_case_probe);
+
+ if (!check_test_results())
+ goto fail;
+
+ if (is_last_scenario)
+ goto pass;
+ }
+
+ /* Do next test run */
+ ++test_case_run_count;
+ ++test_instance;
+ return current_code_start;
+fail:
+ ++test_fail_count;
+ goto end;
+pass:
+ ++test_pass_count;
+end:
+ test_case_cleanup();
+ return 0;
+}
+
+
+/*
+ * Top level test functions
+ */
+
+static int run_test_cases(void (*tests)(void), const union decode_item *table)
+{
+ int ret;
+
+ pr_info(" Check decoding tables\n");
+ ret = table_test(table);
+ if (ret)
+ return ret;
+
+ pr_info(" Run test cases\n");
+ ret = coverage_start(table);
+ if (ret)
+ return ret;
+
+ tests();
+
+ coverage_end();
+ return 0;
+}
+
+
+static int __init run_all_tests(void)
+{
+ int ret = 0;
+
+ pr_info("Begining kprobe tests...\n");
+
+#ifndef CONFIG_THUMB2_KERNEL
+
+ pr_info("Probe ARM code\n");
+ ret = run_api_tests(arm_func);
+ if (ret)
+ goto out;
+
+ pr_info("ARM instruction simulation\n");
+ ret = run_test_cases(kprobe_arm_test_cases, kprobe_decode_arm_table);
+ if (ret)
+ goto out;
+
+#else /* CONFIG_THUMB2_KERNEL */
+
+ pr_info("Probe 16-bit Thumb code\n");
+ ret = run_api_tests(thumb16_func);
+ if (ret)
+ goto out;
+
+ pr_info("Probe 32-bit Thumb code, even halfword\n");
+ ret = run_api_tests(thumb32even_func);
+ if (ret)
+ goto out;
+
+ pr_info("Probe 32-bit Thumb code, odd halfword\n");
+ ret = run_api_tests(thumb32odd_func);
+ if (ret)
+ goto out;
+
+ pr_info("16-bit Thumb instruction simulation\n");
+ ret = run_test_cases(kprobe_thumb16_test_cases,
+ kprobe_decode_thumb16_table);
+ if (ret)
+ goto out;
+
+ pr_info("32-bit Thumb instruction simulation\n");
+ ret = run_test_cases(kprobe_thumb32_test_cases,
+ kprobe_decode_thumb32_table);
+ if (ret)
+ goto out;
+#endif
+
+ pr_info("Total instruction simulation tests=%d, pass=%d fail=%d\n",
+ test_try_count, test_pass_count, test_fail_count);
+ if (test_fail_count) {
+ ret = -EINVAL;
+ goto out;
+ }
+
+#if BENCHMARKING
+ pr_info("Benchmarks\n");
+ ret = run_benchmarks();
+ if (ret)
+ goto out;
+#endif
+
+#if __LINUX_ARM_ARCH__ >= 7
+ /* We are able to run all test cases so coverage should be complete */
+ if (coverage_fail) {
+ pr_err("FAIL: Test coverage checks failed\n");
+ ret = -EINVAL;
+ goto out;
+ }
+#endif
+
+out:
+ if (ret == 0)
+ pr_info("Finished kprobe tests OK\n");
+ else
+ pr_err("kprobe tests failed\n");
+
+ return ret;
+}
+
+
+/*
+ * Module setup
+ */
+
+#ifdef MODULE
+
+static void __exit kprobe_test_exit(void)
+{
+}
+
+module_init(run_all_tests)
+module_exit(kprobe_test_exit)
+MODULE_LICENSE("GPL");
+
+#else /* !MODULE */
+
+late_initcall(run_all_tests);
+
+#endif
diff --git a/arch/arm/kernel/kprobes-test.h b/arch/arm/kernel/kprobes-test.h
new file mode 100644
index 0000000..0dc5d77
--- /dev/null
+++ b/arch/arm/kernel/kprobes-test.h
@@ -0,0 +1,392 @@
+/*
+ * arch/arm/kernel/kprobes-test.h
+ *
+ * Copyright (C) 2011 Jon Medhurst <tixy@yxit.co.uk>.
+ *
+ * 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.
+ */
+
+#define VERBOSE 0 /* Set to '1' for more logging of test cases */
+
+#ifdef CONFIG_THUMB2_KERNEL
+#define NORMAL_ISA "16"
+#else
+#define NORMAL_ISA "32"
+#endif
+
+
+/* Flags used in kprobe_test_flags */
+#define TEST_FLAG_NO_ITBLOCK (1<<0)
+#define TEST_FLAG_FULL_ITBLOCK (1<<1)
+#define TEST_FLAG_NARROW_INSTR (1<<2)
+
+extern int kprobe_test_flags;
+extern int kprobe_test_cc_position;
+
+
+#define TEST_MEMORY_SIZE 256
+
+
+/*
+ * Test case structures.
+ *
+ * The arguments given to test cases can be one of three types.
+ *
+ * ARG_TYPE_REG
+ * Load a register with the given value.
+ *
+ * ARG_TYPE_PTR
+ * Load a register with a pointer into the stack buffer (SP + given value).
+ *
+ * ARG_TYPE_MEM
+ * Store the given value into the stack buffer at [SP+index].
+ *
+ */
+
+#define ARG_TYPE_END 0
+#define ARG_TYPE_REG 1
+#define ARG_TYPE_PTR 2
+#define ARG_TYPE_MEM 3
+
+#define ARG_FLAG_UNSUPPORTED 0x01
+#define ARG_FLAG_SUPPORTED 0x02
+#define ARG_FLAG_THUMB 0x10 /* Must be 16 so TEST_ISA can be used */
+#define ARG_FLAG_ARM 0x20 /* Must be 32 so TEST_ISA can be used */
+
+struct test_arg {
+ u8 type; /* ARG_TYPE_x */
+ u8 _padding[7];
+};
+
+struct test_arg_regptr {
+ u8 type; /* ARG_TYPE_REG or ARG_TYPE_PTR */
+ u8 reg;
+ u8 _padding[2];
+ u32 val;
+};
+
+struct test_arg_mem {
+ u8 type; /* ARG_TYPE_MEM */
+ u8 index;
+ u8 _padding[2];
+ u32 val;
+};
+
+struct test_arg_end {
+ u8 type; /* ARG_TYPE_END */
+ u8 flags; /* ARG_FLAG_x */
+ u16 code_offset;
+ u16 branch_offset;
+ u16 end_offset;
+};
+
+
+/*
+ * Building blocks for test cases.
+ *
+ * Each test case is wrapped between TESTCASE_START and TESTCASE_END.
+ *
+ * To specify arguments for a test case the TEST_ARG_{REG,PTR,MEM} macros are
+ * used followed by a terminating TEST_ARG_END.
+ *
+ * After this, the instruction to be tested is defined with TEST_INSTRUCTION.
+ * Or for branches, TEST_BRANCH_B and TEST_BRANCH_F (branch forwards/backwards).
+ *
+ * Some specific test cases may make use of other custom constructs.
+ */
+
+#if VERBOSE
+#define verbose(fmt, ...) pr_info(fmt, ##__VA_ARGS__)
+#else
+#define verbose(fmt, ...)
+#endif
+
+#define TEST_GROUP(title) \
+ verbose("\n"); \
+ verbose(title"\n"); \
+ verbose("---------------------------------------------------------\n");
+
+#define TESTCASE_START(title) \
+ __asm__ __volatile__ ( \
+ "bl __kprobes_test_case_start \n\t" \
+ /* don't use .asciz here as 'title' may be */ \
+ /* multiple strings to be concatenated. */ \
+ ".ascii "#title" \n\t" \
+ ".byte 0 \n\t" \
+ ".align 2 \n\t"
+
+#define TEST_ARG_REG(reg, val) \
+ ".byte "__stringify(ARG_TYPE_REG)" \n\t" \
+ ".byte "#reg" \n\t" \
+ ".short 0 \n\t" \
+ ".word "#val" \n\t"
+
+#define TEST_ARG_PTR(reg, val) \
+ ".byte "__stringify(ARG_TYPE_PTR)" \n\t" \
+ ".byte "#reg" \n\t" \
+ ".short 0 \n\t" \
+ ".word "#val" \n\t"
+
+#define TEST_ARG_MEM(index, val) \
+ ".byte "__stringify(ARG_TYPE_MEM)" \n\t" \
+ ".byte "#index" \n\t" \
+ ".short 0 \n\t" \
+ ".word "#val" \n\t"
+
+#define TEST_ARG_END(flags) \
+ ".byte "__stringify(ARG_TYPE_END)" \n\t" \
+ ".byte "TEST_ISA flags" \n\t" \
+ ".short 50f-0f \n\t" \
+ ".short 2f-0f \n\t" \
+ ".short 99f-0f \n\t" \
+ ".code "TEST_ISA" \n\t" \
+ "0: \n\t"
+
+#define TEST_INSTRUCTION(instruction) \
+ "50: nop \n\t" \
+ "1: "instruction" \n\t" \
+ " nop \n\t"
+
+#define TEST_BRANCH_F(instruction, xtra_dist) \
+ TEST_INSTRUCTION(instruction) \
+ ".if "#xtra_dist" \n\t" \
+ " b 99f \n\t" \
+ ".space "#xtra_dist" \n\t" \
+ ".endif \n\t" \
+ " b 99f \n\t" \
+ "2: nop \n\t"
+
+#define TEST_BRANCH_B(instruction, xtra_dist) \
+ " b 50f \n\t" \
+ " b 99f \n\t" \
+ "2: nop \n\t" \
+ " b 99f \n\t" \
+ ".if "#xtra_dist" \n\t" \
+ ".space "#xtra_dist" \n\t" \
+ ".endif \n\t" \
+ TEST_INSTRUCTION(instruction)
+
+#define TESTCASE_END \
+ "2: \n\t" \
+ "99: \n\t" \
+ " bl __kprobes_test_case_end_"TEST_ISA" \n\t" \
+ ".code "NORMAL_ISA" \n\t" \
+ : : \
+ : "r0", "r1", "r2", "r3", "ip", "lr", "memory", "cc" \
+ );
+
+
+/*
+ * Macros to define test cases.
+ *
+ * Those of the form TEST_{R,P,M}* can be used to define test cases
+ * which take combinations of the three basic types of arguments. E.g.
+ *
+ * TEST_R One register argument
+ * TEST_RR Two register arguments
+ * TEST_RPR A register, a pointer, then a register argument
+ *
+ * For testing instructions which may branch, there are macros TEST_BF_*
+ * and TEST_BB_* for branching forwards and backwards.
+ *
+ * TEST_SUPPORTED and TEST_UNSUPPORTED don't cause the code to be executed,
+ * the just verify that a kprobe is or is not allowed on the given instruction.
+ */
+
+#define TEST(code) \
+ TESTCASE_START(code) \
+ TEST_ARG_END("") \
+ TEST_INSTRUCTION(code) \
+ TESTCASE_END
+
+#define TEST_UNSUPPORTED(code) \
+ TESTCASE_START(code) \
+ TEST_ARG_END("|"__stringify(ARG_FLAG_UNSUPPORTED)) \
+ TEST_INSTRUCTION(code) \
+ TESTCASE_END
+
+#define TEST_SUPPORTED(code) \
+ TESTCASE_START(code) \
+ TEST_ARG_END("|"__stringify(ARG_FLAG_SUPPORTED)) \
+ TEST_INSTRUCTION(code) \
+ TESTCASE_END
+
+#define TEST_R(code1, reg, val, code2) \
+ TESTCASE_START(code1 #reg code2) \
+ TEST_ARG_REG(reg, val) \
+ TEST_ARG_END("") \
+ TEST_INSTRUCTION(code1 #reg code2) \
+ TESTCASE_END
+
+#define TEST_RR(code1, reg1, val1, code2, reg2, val2, code3) \
+ TESTCASE_START(code1 #reg1 code2 #reg2 code3) \
+ TEST_ARG_REG(reg1, val1) \
+ TEST_ARG_REG(reg2, val2) \
+ TEST_ARG_END("") \
+ TEST_INSTRUCTION(code1 #reg1 code2 #reg2 code3) \
+ TESTCASE_END
+
+#define TEST_RRR(code1, reg1, val1, code2, reg2, val2, code3, reg3, val3, code4)\
+ TESTCASE_START(code1 #reg1 code2 #reg2 code3 #reg3 code4) \
+ TEST_ARG_REG(reg1, val1) \
+ TEST_ARG_REG(reg2, val2) \
+ TEST_ARG_REG(reg3, val3) \
+ TEST_ARG_END("") \
+ TEST_INSTRUCTION(code1 #reg1 code2 #reg2 code3 #reg3 code4) \
+ TESTCASE_END
+
+#define TEST_RRRR(code1, reg1, val1, code2, reg2, val2, code3, reg3, val3, code4, reg4, val4) \
+ TESTCASE_START(code1 #reg1 code2 #reg2 code3 #reg3 code4 #reg4) \
+ TEST_ARG_REG(reg1, val1) \
+ TEST_ARG_REG(reg2, val2) \
+ TEST_ARG_REG(reg3, val3) \
+ TEST_ARG_REG(reg4, val4) \
+ TEST_ARG_END("") \
+ TEST_INSTRUCTION(code1 #reg1 code2 #reg2 code3 #reg3 code4 #reg4) \
+ TESTCASE_END
+
+#define TEST_P(code1, reg1, val1, code2) \
+ TESTCASE_START(code1 #reg1 code2) \
+ TEST_ARG_PTR(reg1, val1) \
+ TEST_ARG_END("") \
+ TEST_INSTRUCTION(code1 #reg1 code2) \
+ TESTCASE_END
+
+#define TEST_PR(code1, reg1, val1, code2, reg2, val2, code3) \
+ TESTCASE_START(code1 #reg1 code2 #reg2 code3) \
+ TEST_ARG_PTR(reg1, val1) \
+ TEST_ARG_REG(reg2, val2) \
+ TEST_ARG_END("") \
+ TEST_INSTRUCTION(code1 #reg1 code2 #reg2 code3) \
+ TESTCASE_END
+
+#define TEST_RP(code1, reg1, val1, code2, reg2, val2, code3) \
+ TESTCASE_START(code1 #reg1 code2 #reg2 code3) \
+ TEST_ARG_REG(reg1, val1) \
+ TEST_ARG_PTR(reg2, val2) \
+ TEST_ARG_END("") \
+ TEST_INSTRUCTION(code1 #reg1 code2 #reg2 code3) \
+ TESTCASE_END
+
+#define TEST_PRR(code1, reg1, val1, code2, reg2, val2, code3, reg3, val3, code4)\
+ TESTCASE_START(code1 #reg1 code2 #reg2 code3 #reg3 code4) \
+ TEST_ARG_PTR(reg1, val1) \
+ TEST_ARG_REG(reg2, val2) \
+ TEST_ARG_REG(reg3, val3) \
+ TEST_ARG_END("") \
+ TEST_INSTRUCTION(code1 #reg1 code2 #reg2 code3 #reg3 code4) \
+ TESTCASE_END
+
+#define TEST_RPR(code1, reg1, val1, code2, reg2, val2, code3, reg3, val3, code4)\
+ TESTCASE_START(code1 #reg1 code2 #reg2 code3 #reg3 code4) \
+ TEST_ARG_REG(reg1, val1) \
+ TEST_ARG_PTR(reg2, val2) \
+ TEST_ARG_REG(reg3, val3) \
+ TEST_ARG_END("") \
+ TEST_INSTRUCTION(code1 #reg1 code2 #reg2 code3 #reg3 code4) \
+ TESTCASE_END
+
+#define TEST_RRP(code1, reg1, val1, code2, reg2, val2, code3, reg3, val3, code4)\
+ TESTCASE_START(code1 #reg1 code2 #reg2 code3 #reg3 code4) \
+ TEST_ARG_REG(reg1, val1) \
+ TEST_ARG_REG(reg2, val2) \
+ TEST_ARG_PTR(reg3, val3) \
+ TEST_ARG_END("") \
+ TEST_INSTRUCTION(code1 #reg1 code2 #reg2 code3 #reg3 code4) \
+ TESTCASE_END
+
+#define TEST_BF_P(code1, reg1, val1, code2) \
+ TESTCASE_START(code1 #reg1 code2) \
+ TEST_ARG_PTR(reg1, val1) \
+ TEST_ARG_END("") \
+ TEST_BRANCH_F(code1 #reg1 code2, 0) \
+ TESTCASE_END
+
+#define TEST_BF_X(code, xtra_dist) \
+ TESTCASE_START(code) \
+ TEST_ARG_END("") \
+ TEST_BRANCH_F(code, xtra_dist) \
+ TESTCASE_END
+
+#define TEST_BB_X(code, xtra_dist) \
+ TESTCASE_START(code) \
+ TEST_ARG_END("") \
+ TEST_BRANCH_B(code, xtra_dist) \
+ TESTCASE_END
+
+#define TEST_BF_RX(code1, reg, val, code2, xtra_dist) \
+ TESTCASE_START(code1 #reg code2) \
+ TEST_ARG_REG(reg, val) \
+ TEST_ARG_END("") \
+ TEST_BRANCH_F(code1 #reg code2, xtra_dist) \
+ TESTCASE_END
+
+#define TEST_BB_RX(code1, reg, val, code2, xtra_dist) \
+ TESTCASE_START(code1 #reg code2) \
+ TEST_ARG_REG(reg, val) \
+ TEST_ARG_END("") \
+ TEST_BRANCH_B(code1 #reg code2, xtra_dist) \
+ TESTCASE_END
+
+#define TEST_BF(code) TEST_BF_X(code, 0)
+#define TEST_BB(code) TEST_BB_X(code, 0)
+
+#define TEST_BF_R(code1, reg, val, code2) TEST_BF_RX(code1, reg, val, code2, 0)
+#define TEST_BB_R(code1, reg, val, code2) TEST_BB_RX(code1, reg, val, code2, 0)
+
+#define TEST_BF_RR(code1, reg1, val1, code2, reg2, val2, code3) \
+ TESTCASE_START(code1 #reg1 code2 #reg2 code3) \
+ TEST_ARG_REG(reg1, val1) \
+ TEST_ARG_REG(reg2, val2) \
+ TEST_ARG_END("") \
+ TEST_BRANCH_F(code1 #reg1 code2 #reg2 code3, 0) \
+ TESTCASE_END
+
+#define TEST_X(code, codex) \
+ TESTCASE_START(code) \
+ TEST_ARG_END("") \
+ TEST_INSTRUCTION(code) \
+ " b 99f \n\t" \
+ " "codex" \n\t" \
+ TESTCASE_END
+
+#define TEST_RX(code1, reg, val, code2, codex) \
+ TESTCASE_START(code1 #reg code2) \
+ TEST_ARG_REG(reg, val) \
+ TEST_ARG_END("") \
+ TEST_INSTRUCTION(code1 __stringify(reg) code2) \
+ " b 99f \n\t" \
+ " "codex" \n\t" \
+ TESTCASE_END
+
+#define TEST_RRX(code1, reg1, val1, code2, reg2, val2, code3, codex) \
+ TESTCASE_START(code1 #reg1 code2 #reg2 code3) \
+ TEST_ARG_REG(reg1, val1) \
+ TEST_ARG_REG(reg2, val2) \
+ TEST_ARG_END("") \
+ TEST_INSTRUCTION(code1 __stringify(reg1) code2 __stringify(reg2) code3) \
+ " b 99f \n\t" \
+ " "codex" \n\t" \
+ TESTCASE_END
+
+
+/* Various values used in test cases... */
+#define N(val) (val ^ 0xffffffff)
+#define VAL1 0x12345678
+#define VAL2 N(VAL1)
+#define VAL3 0xa5f801
+#define VAL4 N(VAL3)
+#define VALM 0x456789ab
+#define VALR 0xdeaddead
+#define HH1 0x0123fecb
+#define HH2 0xa9874567
+
+
+#ifdef CONFIG_THUMB2_KERNEL
+void kprobe_thumb16_test_cases(void);
+void kprobe_thumb32_test_cases(void);
+#else
+void kprobe_arm_test_cases(void);
+#endif
diff --git a/arch/arm/kernel/kprobes-thumb.c b/arch/arm/kernel/kprobes-thumb.c
index 902ca59..8f96ec7 100644
--- a/arch/arm/kernel/kprobes-thumb.c
+++ b/arch/arm/kernel/kprobes-thumb.c
@@ -10,6 +10,7 @@
#include <linux/kernel.h>
#include <linux/kprobes.h>
+#include <linux/module.h>
#include "kprobes.h"
@@ -943,6 +944,9 @@
*/
DECODE_END
};
+#ifdef CONFIG_ARM_KPROBES_TEST_MODULE
+EXPORT_SYMBOL_GPL(kprobe_decode_thumb32_table);
+#endif
static void __kprobes
t16_simulate_bxblx(struct kprobe *p, struct pt_regs *regs)
@@ -1423,6 +1427,9 @@
DECODE_END
};
+#ifdef CONFIG_ARM_KPROBES_TEST_MODULE
+EXPORT_SYMBOL_GPL(kprobe_decode_thumb16_table);
+#endif
static unsigned long __kprobes thumb_check_cc(unsigned long cpsr)
{
diff --git a/arch/arm/kernel/kprobes.h b/arch/arm/kernel/kprobes.h
index a6aeda0..38945f7 100644
--- a/arch/arm/kernel/kprobes.h
+++ b/arch/arm/kernel/kprobes.h
@@ -413,6 +413,14 @@
DECODE_HEADER(DECODE_TYPE_REJECT, _mask, _value, 0)
+#ifdef CONFIG_THUMB2_KERNEL
+extern const union decode_item kprobe_decode_thumb16_table[];
+extern const union decode_item kprobe_decode_thumb32_table[];
+#else
+extern const union decode_item kprobe_decode_arm_table[];
+#endif
+
+
int kprobe_decode_insn(kprobe_opcode_t insn, struct arch_specific_insn *asi,
const union decode_item *table, bool thumb16);
diff --git a/arch/arm/kernel/perf_event.c b/arch/arm/kernel/perf_event.c
index 53c9c26..e6e5d7c 100644
--- a/arch/arm/kernel/perf_event.c
+++ b/arch/arm/kernel/perf_event.c
@@ -12,6 +12,7 @@
*/
#define pr_fmt(fmt) "hw perfevents: " fmt
+#include <linux/bitmap.h>
#include <linux/interrupt.h>
#include <linux/kernel.h>
#include <linux/module.h>
@@ -26,16 +27,8 @@
#include <asm/pmu.h>
#include <asm/stacktrace.h>
-static struct platform_device *pmu_device;
-
/*
- * Hardware lock to serialize accesses to PMU registers. Needed for the
- * read/modify/write sequences.
- */
-static DEFINE_RAW_SPINLOCK(pmu_lock);
-
-/*
- * ARMv6 supports a maximum of 3 events, starting from index 1. If we add
+ * ARMv6 supports a maximum of 3 events, starting from index 0. If we add
* another platform that supports more, we need to increase this to be the
* largest of all platforms.
*
@@ -43,62 +36,24 @@
* cycle counter CCNT + 31 events counters CNT0..30.
* Cortex-A8 has 1+4 counters, Cortex-A9 has 1+6 counters.
*/
-#define ARMPMU_MAX_HWEVENTS 33
+#define ARMPMU_MAX_HWEVENTS 32
-/* The events for a given CPU. */
-struct cpu_hw_events {
- /*
- * The events that are active on the CPU for the given index. Index 0
- * is reserved.
- */
- struct perf_event *events[ARMPMU_MAX_HWEVENTS];
+static DEFINE_PER_CPU(struct perf_event * [ARMPMU_MAX_HWEVENTS], hw_events);
+static DEFINE_PER_CPU(unsigned long [BITS_TO_LONGS(ARMPMU_MAX_HWEVENTS)], used_mask);
+static DEFINE_PER_CPU(struct pmu_hw_events, cpu_hw_events);
- /*
- * A 1 bit for an index indicates that the counter is being used for
- * an event. A 0 means that the counter can be used.
- */
- unsigned long used_mask[BITS_TO_LONGS(ARMPMU_MAX_HWEVENTS)];
-
- /*
- * A 1 bit for an index indicates that the counter is actively being
- * used.
- */
- unsigned long active_mask[BITS_TO_LONGS(ARMPMU_MAX_HWEVENTS)];
-};
-static DEFINE_PER_CPU(struct cpu_hw_events, cpu_hw_events);
-
-struct arm_pmu {
- enum arm_perf_pmu_ids id;
- const char *name;
- irqreturn_t (*handle_irq)(int irq_num, void *dev);
- void (*enable)(struct hw_perf_event *evt, int idx);
- void (*disable)(struct hw_perf_event *evt, int idx);
- int (*get_event_idx)(struct cpu_hw_events *cpuc,
- struct hw_perf_event *hwc);
- u32 (*read_counter)(int idx);
- void (*write_counter)(int idx, u32 val);
- void (*start)(void);
- void (*stop)(void);
- void (*reset)(void *);
- const unsigned (*cache_map)[PERF_COUNT_HW_CACHE_MAX]
- [PERF_COUNT_HW_CACHE_OP_MAX]
- [PERF_COUNT_HW_CACHE_RESULT_MAX];
- const unsigned (*event_map)[PERF_COUNT_HW_MAX];
- u32 raw_event_mask;
- int num_events;
- u64 max_period;
-};
+#define to_arm_pmu(p) (container_of(p, struct arm_pmu, pmu))
/* Set at runtime when we know what CPU type we are. */
-static const struct arm_pmu *armpmu;
+static struct arm_pmu *cpu_pmu;
enum arm_perf_pmu_ids
armpmu_get_pmu_id(void)
{
int id = -ENODEV;
- if (armpmu != NULL)
- id = armpmu->id;
+ if (cpu_pmu != NULL)
+ id = cpu_pmu->id;
return id;
}
@@ -109,8 +64,8 @@
{
int max_events = 0;
- if (armpmu != NULL)
- max_events = armpmu->num_events;
+ if (cpu_pmu != NULL)
+ max_events = cpu_pmu->num_events;
return max_events;
}
@@ -130,7 +85,11 @@
#define CACHE_OP_UNSUPPORTED 0xFFFF
static int
-armpmu_map_cache_event(u64 config)
+armpmu_map_cache_event(const unsigned (*cache_map)
+ [PERF_COUNT_HW_CACHE_MAX]
+ [PERF_COUNT_HW_CACHE_OP_MAX]
+ [PERF_COUNT_HW_CACHE_RESULT_MAX],
+ u64 config)
{
unsigned int cache_type, cache_op, cache_result, ret;
@@ -146,7 +105,7 @@
if (cache_result >= PERF_COUNT_HW_CACHE_RESULT_MAX)
return -EINVAL;
- ret = (int)(*armpmu->cache_map)[cache_type][cache_op][cache_result];
+ ret = (int)(*cache_map)[cache_type][cache_op][cache_result];
if (ret == CACHE_OP_UNSUPPORTED)
return -ENOENT;
@@ -155,23 +114,46 @@
}
static int
-armpmu_map_event(u64 config)
+armpmu_map_event(const unsigned (*event_map)[PERF_COUNT_HW_MAX], u64 config)
{
- int mapping = (*armpmu->event_map)[config];
- return mapping == HW_OP_UNSUPPORTED ? -EOPNOTSUPP : mapping;
+ int mapping = (*event_map)[config];
+ return mapping == HW_OP_UNSUPPORTED ? -ENOENT : mapping;
}
static int
-armpmu_map_raw_event(u64 config)
+armpmu_map_raw_event(u32 raw_event_mask, u64 config)
{
- return (int)(config & armpmu->raw_event_mask);
+ return (int)(config & raw_event_mask);
}
-static int
+static int map_cpu_event(struct perf_event *event,
+ const unsigned (*event_map)[PERF_COUNT_HW_MAX],
+ const unsigned (*cache_map)
+ [PERF_COUNT_HW_CACHE_MAX]
+ [PERF_COUNT_HW_CACHE_OP_MAX]
+ [PERF_COUNT_HW_CACHE_RESULT_MAX],
+ u32 raw_event_mask)
+{
+ u64 config = event->attr.config;
+
+ switch (event->attr.type) {
+ case PERF_TYPE_HARDWARE:
+ return armpmu_map_event(event_map, config);
+ case PERF_TYPE_HW_CACHE:
+ return armpmu_map_cache_event(cache_map, config);
+ case PERF_TYPE_RAW:
+ return armpmu_map_raw_event(raw_event_mask, config);
+ }
+
+ return -ENOENT;
+}
+
+int
armpmu_event_set_period(struct perf_event *event,
struct hw_perf_event *hwc,
int idx)
{
+ struct arm_pmu *armpmu = to_arm_pmu(event->pmu);
s64 left = local64_read(&hwc->period_left);
s64 period = hwc->sample_period;
int ret = 0;
@@ -202,11 +184,12 @@
return ret;
}
-static u64
+u64
armpmu_event_update(struct perf_event *event,
struct hw_perf_event *hwc,
int idx, int overflow)
{
+ struct arm_pmu *armpmu = to_arm_pmu(event->pmu);
u64 delta, prev_raw_count, new_raw_count;
again:
@@ -246,11 +229,9 @@
static void
armpmu_stop(struct perf_event *event, int flags)
{
+ struct arm_pmu *armpmu = to_arm_pmu(event->pmu);
struct hw_perf_event *hwc = &event->hw;
- if (!armpmu)
- return;
-
/*
* ARM pmu always has to update the counter, so ignore
* PERF_EF_UPDATE, see comments in armpmu_start().
@@ -266,11 +247,9 @@
static void
armpmu_start(struct perf_event *event, int flags)
{
+ struct arm_pmu *armpmu = to_arm_pmu(event->pmu);
struct hw_perf_event *hwc = &event->hw;
- if (!armpmu)
- return;
-
/*
* ARM pmu always has to reprogram the period, so ignore
* PERF_EF_RELOAD, see the comment below.
@@ -293,16 +272,16 @@
static void
armpmu_del(struct perf_event *event, int flags)
{
- struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events);
+ struct arm_pmu *armpmu = to_arm_pmu(event->pmu);
+ struct pmu_hw_events *hw_events = armpmu->get_hw_events();
struct hw_perf_event *hwc = &event->hw;
int idx = hwc->idx;
WARN_ON(idx < 0);
- clear_bit(idx, cpuc->active_mask);
armpmu_stop(event, PERF_EF_UPDATE);
- cpuc->events[idx] = NULL;
- clear_bit(idx, cpuc->used_mask);
+ hw_events->events[idx] = NULL;
+ clear_bit(idx, hw_events->used_mask);
perf_event_update_userpage(event);
}
@@ -310,7 +289,8 @@
static int
armpmu_add(struct perf_event *event, int flags)
{
- struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events);
+ struct arm_pmu *armpmu = to_arm_pmu(event->pmu);
+ struct pmu_hw_events *hw_events = armpmu->get_hw_events();
struct hw_perf_event *hwc = &event->hw;
int idx;
int err = 0;
@@ -318,7 +298,7 @@
perf_pmu_disable(event->pmu);
/* If we don't have a space for the counter then finish early. */
- idx = armpmu->get_event_idx(cpuc, hwc);
+ idx = armpmu->get_event_idx(hw_events, hwc);
if (idx < 0) {
err = idx;
goto out;
@@ -330,8 +310,7 @@
*/
event->hw.idx = idx;
armpmu->disable(hwc, idx);
- cpuc->events[idx] = event;
- set_bit(idx, cpuc->active_mask);
+ hw_events->events[idx] = event;
hwc->state = PERF_HES_STOPPED | PERF_HES_UPTODATE;
if (flags & PERF_EF_START)
@@ -345,25 +324,25 @@
return err;
}
-static struct pmu pmu;
-
static int
-validate_event(struct cpu_hw_events *cpuc,
+validate_event(struct pmu_hw_events *hw_events,
struct perf_event *event)
{
+ struct arm_pmu *armpmu = to_arm_pmu(event->pmu);
struct hw_perf_event fake_event = event->hw;
+ struct pmu *leader_pmu = event->group_leader->pmu;
- if (event->pmu != &pmu || event->state <= PERF_EVENT_STATE_OFF)
+ if (event->pmu != leader_pmu || event->state <= PERF_EVENT_STATE_OFF)
return 1;
- return armpmu->get_event_idx(cpuc, &fake_event) >= 0;
+ return armpmu->get_event_idx(hw_events, &fake_event) >= 0;
}
static int
validate_group(struct perf_event *event)
{
struct perf_event *sibling, *leader = event->group_leader;
- struct cpu_hw_events fake_pmu;
+ struct pmu_hw_events fake_pmu;
memset(&fake_pmu, 0, sizeof(fake_pmu));
@@ -383,110 +362,119 @@
static irqreturn_t armpmu_platform_irq(int irq, void *dev)
{
- struct arm_pmu_platdata *plat = dev_get_platdata(&pmu_device->dev);
+ struct arm_pmu *armpmu = (struct arm_pmu *) dev;
+ struct platform_device *plat_device = armpmu->plat_device;
+ struct arm_pmu_platdata *plat = dev_get_platdata(&plat_device->dev);
return plat->handle_irq(irq, dev, armpmu->handle_irq);
}
+static void
+armpmu_release_hardware(struct arm_pmu *armpmu)
+{
+ int i, irq, irqs;
+ struct platform_device *pmu_device = armpmu->plat_device;
+
+ irqs = min(pmu_device->num_resources, num_possible_cpus());
+
+ for (i = 0; i < irqs; ++i) {
+ if (!cpumask_test_and_clear_cpu(i, &armpmu->active_irqs))
+ continue;
+ irq = platform_get_irq(pmu_device, i);
+ if (irq >= 0)
+ free_irq(irq, armpmu);
+ }
+
+ release_pmu(armpmu->type);
+}
+
static int
-armpmu_reserve_hardware(void)
+armpmu_reserve_hardware(struct arm_pmu *armpmu)
{
struct arm_pmu_platdata *plat;
irq_handler_t handle_irq;
- int i, err = -ENODEV, irq;
+ int i, err, irq, irqs;
+ struct platform_device *pmu_device = armpmu->plat_device;
- pmu_device = reserve_pmu(ARM_PMU_DEVICE_CPU);
- if (IS_ERR(pmu_device)) {
+ err = reserve_pmu(armpmu->type);
+ if (err) {
pr_warning("unable to reserve pmu\n");
- return PTR_ERR(pmu_device);
+ return err;
}
- init_pmu(ARM_PMU_DEVICE_CPU);
-
plat = dev_get_platdata(&pmu_device->dev);
if (plat && plat->handle_irq)
handle_irq = armpmu_platform_irq;
else
handle_irq = armpmu->handle_irq;
- if (pmu_device->num_resources < 1) {
+ irqs = min(pmu_device->num_resources, num_possible_cpus());
+ if (irqs < 1) {
pr_err("no irqs for PMUs defined\n");
return -ENODEV;
}
- for (i = 0; i < pmu_device->num_resources; ++i) {
+ for (i = 0; i < irqs; ++i) {
+ err = 0;
irq = platform_get_irq(pmu_device, i);
if (irq < 0)
continue;
+ /*
+ * If we have a single PMU interrupt that we can't shift,
+ * assume that we're running on a uniprocessor machine and
+ * continue. Otherwise, continue without this interrupt.
+ */
+ if (irq_set_affinity(irq, cpumask_of(i)) && irqs > 1) {
+ pr_warning("unable to set irq affinity (irq=%d, cpu=%u)\n",
+ irq, i);
+ continue;
+ }
+
err = request_irq(irq, handle_irq,
IRQF_DISABLED | IRQF_NOBALANCING,
- "armpmu", NULL);
+ "arm-pmu", armpmu);
if (err) {
- pr_warning("unable to request IRQ%d for ARM perf "
- "counters\n", irq);
- break;
+ pr_err("unable to request IRQ%d for ARM PMU counters\n",
+ irq);
+ armpmu_release_hardware(armpmu);
+ return err;
}
+
+ cpumask_set_cpu(i, &armpmu->active_irqs);
}
- if (err) {
- for (i = i - 1; i >= 0; --i) {
- irq = platform_get_irq(pmu_device, i);
- if (irq >= 0)
- free_irq(irq, NULL);
- }
- release_pmu(ARM_PMU_DEVICE_CPU);
- pmu_device = NULL;
- }
-
- return err;
+ return 0;
}
static void
-armpmu_release_hardware(void)
-{
- int i, irq;
-
- for (i = pmu_device->num_resources - 1; i >= 0; --i) {
- irq = platform_get_irq(pmu_device, i);
- if (irq >= 0)
- free_irq(irq, NULL);
- }
- armpmu->stop();
-
- release_pmu(ARM_PMU_DEVICE_CPU);
- pmu_device = NULL;
-}
-
-static atomic_t active_events = ATOMIC_INIT(0);
-static DEFINE_MUTEX(pmu_reserve_mutex);
-
-static void
hw_perf_event_destroy(struct perf_event *event)
{
- if (atomic_dec_and_mutex_lock(&active_events, &pmu_reserve_mutex)) {
- armpmu_release_hardware();
- mutex_unlock(&pmu_reserve_mutex);
+ struct arm_pmu *armpmu = to_arm_pmu(event->pmu);
+ atomic_t *active_events = &armpmu->active_events;
+ struct mutex *pmu_reserve_mutex = &armpmu->reserve_mutex;
+
+ if (atomic_dec_and_mutex_lock(active_events, pmu_reserve_mutex)) {
+ armpmu_release_hardware(armpmu);
+ mutex_unlock(pmu_reserve_mutex);
}
}
static int
+event_requires_mode_exclusion(struct perf_event_attr *attr)
+{
+ return attr->exclude_idle || attr->exclude_user ||
+ attr->exclude_kernel || attr->exclude_hv;
+}
+
+static int
__hw_perf_event_init(struct perf_event *event)
{
+ struct arm_pmu *armpmu = to_arm_pmu(event->pmu);
struct hw_perf_event *hwc = &event->hw;
int mapping, err;
- /* Decode the generic type into an ARM event identifier. */
- if (PERF_TYPE_HARDWARE == event->attr.type) {
- mapping = armpmu_map_event(event->attr.config);
- } else if (PERF_TYPE_HW_CACHE == event->attr.type) {
- mapping = armpmu_map_cache_event(event->attr.config);
- } else if (PERF_TYPE_RAW == event->attr.type) {
- mapping = armpmu_map_raw_event(event->attr.config);
- } else {
- pr_debug("event type %x not supported\n", event->attr.type);
- return -EOPNOTSUPP;
- }
+ mapping = armpmu->map_event(event);
if (mapping < 0) {
pr_debug("event %x:%llx not supported\n", event->attr.type,
@@ -495,34 +483,31 @@
}
/*
- * Check whether we need to exclude the counter from certain modes.
- * The ARM performance counters are on all of the time so if someone
- * has asked us for some excludes then we have to fail.
+ * We don't assign an index until we actually place the event onto
+ * hardware. Use -1 to signify that we haven't decided where to put it
+ * yet. For SMP systems, each core has it's own PMU so we can't do any
+ * clever allocation or constraints checking at this point.
*/
- if (event->attr.exclude_kernel || event->attr.exclude_user ||
- event->attr.exclude_hv || event->attr.exclude_idle) {
+ hwc->idx = -1;
+ hwc->config_base = 0;
+ hwc->config = 0;
+ hwc->event_base = 0;
+
+ /*
+ * Check whether we need to exclude the counter from certain modes.
+ */
+ if ((!armpmu->set_event_filter ||
+ armpmu->set_event_filter(hwc, &event->attr)) &&
+ event_requires_mode_exclusion(&event->attr)) {
pr_debug("ARM performance counters do not support "
"mode exclusion\n");
return -EPERM;
}
/*
- * We don't assign an index until we actually place the event onto
- * hardware. Use -1 to signify that we haven't decided where to put it
- * yet. For SMP systems, each core has it's own PMU so we can't do any
- * clever allocation or constraints checking at this point.
+ * Store the event encoding into the config_base field.
*/
- hwc->idx = -1;
-
- /*
- * Store the event encoding into the config_base field. config and
- * event_base are unused as the only 2 things we need to know are
- * the event mapping and the counter to use. The counter to use is
- * also the indx and the config_base is the event type.
- */
- hwc->config_base = (unsigned long)mapping;
- hwc->config = 0;
- hwc->event_base = 0;
+ hwc->config_base |= (unsigned long)mapping;
if (!hwc->sample_period) {
hwc->sample_period = armpmu->max_period;
@@ -542,32 +527,23 @@
static int armpmu_event_init(struct perf_event *event)
{
+ struct arm_pmu *armpmu = to_arm_pmu(event->pmu);
int err = 0;
+ atomic_t *active_events = &armpmu->active_events;
- switch (event->attr.type) {
- case PERF_TYPE_RAW:
- case PERF_TYPE_HARDWARE:
- case PERF_TYPE_HW_CACHE:
- break;
-
- default:
+ if (armpmu->map_event(event) == -ENOENT)
return -ENOENT;
- }
-
- if (!armpmu)
- return -ENODEV;
event->destroy = hw_perf_event_destroy;
- if (!atomic_inc_not_zero(&active_events)) {
- mutex_lock(&pmu_reserve_mutex);
- if (atomic_read(&active_events) == 0) {
- err = armpmu_reserve_hardware();
- }
+ if (!atomic_inc_not_zero(active_events)) {
+ mutex_lock(&armpmu->reserve_mutex);
+ if (atomic_read(active_events) == 0)
+ err = armpmu_reserve_hardware(armpmu);
if (!err)
- atomic_inc(&active_events);
- mutex_unlock(&pmu_reserve_mutex);
+ atomic_inc(active_events);
+ mutex_unlock(&armpmu->reserve_mutex);
}
if (err)
@@ -582,22 +558,9 @@
static void armpmu_enable(struct pmu *pmu)
{
- /* Enable all of the perf events on hardware. */
- int idx, enabled = 0;
- struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events);
-
- if (!armpmu)
- return;
-
- for (idx = 0; idx <= armpmu->num_events; ++idx) {
- struct perf_event *event = cpuc->events[idx];
-
- if (!event)
- continue;
-
- armpmu->enable(&event->hw, idx);
- enabled = 1;
- }
+ struct arm_pmu *armpmu = to_arm_pmu(pmu);
+ struct pmu_hw_events *hw_events = armpmu->get_hw_events();
+ int enabled = bitmap_weight(hw_events->used_mask, armpmu->num_events);
if (enabled)
armpmu->start();
@@ -605,20 +568,32 @@
static void armpmu_disable(struct pmu *pmu)
{
- if (armpmu)
- armpmu->stop();
+ struct arm_pmu *armpmu = to_arm_pmu(pmu);
+ armpmu->stop();
}
-static struct pmu pmu = {
- .pmu_enable = armpmu_enable,
- .pmu_disable = armpmu_disable,
- .event_init = armpmu_event_init,
- .add = armpmu_add,
- .del = armpmu_del,
- .start = armpmu_start,
- .stop = armpmu_stop,
- .read = armpmu_read,
-};
+static void __init armpmu_init(struct arm_pmu *armpmu)
+{
+ atomic_set(&armpmu->active_events, 0);
+ mutex_init(&armpmu->reserve_mutex);
+
+ armpmu->pmu = (struct pmu) {
+ .pmu_enable = armpmu_enable,
+ .pmu_disable = armpmu_disable,
+ .event_init = armpmu_event_init,
+ .add = armpmu_add,
+ .del = armpmu_del,
+ .start = armpmu_start,
+ .stop = armpmu_stop,
+ .read = armpmu_read,
+ };
+}
+
+int __init armpmu_register(struct arm_pmu *armpmu, char *name, int type)
+{
+ armpmu_init(armpmu);
+ return perf_pmu_register(&armpmu->pmu, name, type);
+}
/* Include the PMU-specific implementations. */
#include "perf_event_xscale.c"
@@ -630,14 +605,72 @@
* This requires SMP to be available, so exists as a separate initcall.
*/
static int __init
-armpmu_reset(void)
+cpu_pmu_reset(void)
{
- if (armpmu && armpmu->reset)
- return on_each_cpu(armpmu->reset, NULL, 1);
+ if (cpu_pmu && cpu_pmu->reset)
+ return on_each_cpu(cpu_pmu->reset, NULL, 1);
return 0;
}
-arch_initcall(armpmu_reset);
+arch_initcall(cpu_pmu_reset);
+/*
+ * PMU platform driver and devicetree bindings.
+ */
+static struct of_device_id armpmu_of_device_ids[] = {
+ {.compatible = "arm,cortex-a9-pmu"},
+ {.compatible = "arm,cortex-a8-pmu"},
+ {.compatible = "arm,arm1136-pmu"},
+ {.compatible = "arm,arm1176-pmu"},
+ {},
+};
+
+static struct platform_device_id armpmu_plat_device_ids[] = {
+ {.name = "arm-pmu"},
+ {},
+};
+
+static int __devinit armpmu_device_probe(struct platform_device *pdev)
+{
+ cpu_pmu->plat_device = pdev;
+ return 0;
+}
+
+static struct platform_driver armpmu_driver = {
+ .driver = {
+ .name = "arm-pmu",
+ .of_match_table = armpmu_of_device_ids,
+ },
+ .probe = armpmu_device_probe,
+ .id_table = armpmu_plat_device_ids,
+};
+
+static int __init register_pmu_driver(void)
+{
+ return platform_driver_register(&armpmu_driver);
+}
+device_initcall(register_pmu_driver);
+
+static struct pmu_hw_events *armpmu_get_cpu_events(void)
+{
+ return &__get_cpu_var(cpu_hw_events);
+}
+
+static void __init cpu_pmu_init(struct arm_pmu *armpmu)
+{
+ int cpu;
+ for_each_possible_cpu(cpu) {
+ struct pmu_hw_events *events = &per_cpu(cpu_hw_events, cpu);
+ events->events = per_cpu(hw_events, cpu);
+ events->used_mask = per_cpu(used_mask, cpu);
+ raw_spin_lock_init(&events->pmu_lock);
+ }
+ armpmu->get_hw_events = armpmu_get_cpu_events;
+ armpmu->type = ARM_PMU_DEVICE_CPU;
+}
+
+/*
+ * CPU PMU identification and registration.
+ */
static int __init
init_hw_perf_events(void)
{
@@ -651,22 +684,22 @@
case 0xB360: /* ARM1136 */
case 0xB560: /* ARM1156 */
case 0xB760: /* ARM1176 */
- armpmu = armv6pmu_init();
+ cpu_pmu = armv6pmu_init();
break;
case 0xB020: /* ARM11mpcore */
- armpmu = armv6mpcore_pmu_init();
+ cpu_pmu = armv6mpcore_pmu_init();
break;
case 0xC080: /* Cortex-A8 */
- armpmu = armv7_a8_pmu_init();
+ cpu_pmu = armv7_a8_pmu_init();
break;
case 0xC090: /* Cortex-A9 */
- armpmu = armv7_a9_pmu_init();
+ cpu_pmu = armv7_a9_pmu_init();
break;
case 0xC050: /* Cortex-A5 */
- armpmu = armv7_a5_pmu_init();
+ cpu_pmu = armv7_a5_pmu_init();
break;
case 0xC0F0: /* Cortex-A15 */
- armpmu = armv7_a15_pmu_init();
+ cpu_pmu = armv7_a15_pmu_init();
break;
}
/* Intel CPUs [xscale]. */
@@ -674,23 +707,23 @@
part_number = (cpuid >> 13) & 0x7;
switch (part_number) {
case 1:
- armpmu = xscale1pmu_init();
+ cpu_pmu = xscale1pmu_init();
break;
case 2:
- armpmu = xscale2pmu_init();
+ cpu_pmu = xscale2pmu_init();
break;
}
}
- if (armpmu) {
+ if (cpu_pmu) {
pr_info("enabled with %s PMU driver, %d counters available\n",
- armpmu->name, armpmu->num_events);
+ cpu_pmu->name, cpu_pmu->num_events);
+ cpu_pmu_init(cpu_pmu);
+ armpmu_register(cpu_pmu, "cpu", PERF_TYPE_RAW);
} else {
pr_info("no hardware support available\n");
}
- perf_pmu_register(&pmu, "cpu", PERF_TYPE_RAW);
-
return 0;
}
early_initcall(init_hw_perf_events);
diff --git a/arch/arm/kernel/perf_event_v6.c b/arch/arm/kernel/perf_event_v6.c
index dd7f3b9..e63d811 100644
--- a/arch/arm/kernel/perf_event_v6.c
+++ b/arch/arm/kernel/perf_event_v6.c
@@ -54,7 +54,7 @@
};
enum armv6_counters {
- ARMV6_CYCLE_COUNTER = 1,
+ ARMV6_CYCLE_COUNTER = 0,
ARMV6_COUNTER0,
ARMV6_COUNTER1,
};
@@ -433,6 +433,7 @@
int idx)
{
unsigned long val, mask, evt, flags;
+ struct pmu_hw_events *events = cpu_pmu->get_hw_events();
if (ARMV6_CYCLE_COUNTER == idx) {
mask = 0;
@@ -454,12 +455,29 @@
* Mask out the current event and set the counter to count the event
* that we're interested in.
*/
- raw_spin_lock_irqsave(&pmu_lock, flags);
+ raw_spin_lock_irqsave(&events->pmu_lock, flags);
val = armv6_pmcr_read();
val &= ~mask;
val |= evt;
armv6_pmcr_write(val);
- raw_spin_unlock_irqrestore(&pmu_lock, flags);
+ raw_spin_unlock_irqrestore(&events->pmu_lock, flags);
+}
+
+static int counter_is_active(unsigned long pmcr, int idx)
+{
+ unsigned long mask = 0;
+ if (idx == ARMV6_CYCLE_COUNTER)
+ mask = ARMV6_PMCR_CCOUNT_IEN;
+ else if (idx == ARMV6_COUNTER0)
+ mask = ARMV6_PMCR_COUNT0_IEN;
+ else if (idx == ARMV6_COUNTER1)
+ mask = ARMV6_PMCR_COUNT1_IEN;
+
+ if (mask)
+ return pmcr & mask;
+
+ WARN_ONCE(1, "invalid counter number (%d)\n", idx);
+ return 0;
}
static irqreturn_t
@@ -468,7 +486,7 @@
{
unsigned long pmcr = armv6_pmcr_read();
struct perf_sample_data data;
- struct cpu_hw_events *cpuc;
+ struct pmu_hw_events *cpuc;
struct pt_regs *regs;
int idx;
@@ -487,11 +505,11 @@
perf_sample_data_init(&data, 0);
cpuc = &__get_cpu_var(cpu_hw_events);
- for (idx = 0; idx <= armpmu->num_events; ++idx) {
+ for (idx = 0; idx < cpu_pmu->num_events; ++idx) {
struct perf_event *event = cpuc->events[idx];
struct hw_perf_event *hwc;
- if (!test_bit(idx, cpuc->active_mask))
+ if (!counter_is_active(pmcr, idx))
continue;
/*
@@ -508,7 +526,7 @@
continue;
if (perf_event_overflow(event, &data, regs))
- armpmu->disable(hwc, idx);
+ cpu_pmu->disable(hwc, idx);
}
/*
@@ -527,28 +545,30 @@
armv6pmu_start(void)
{
unsigned long flags, val;
+ struct pmu_hw_events *events = cpu_pmu->get_hw_events();
- raw_spin_lock_irqsave(&pmu_lock, flags);
+ raw_spin_lock_irqsave(&events->pmu_lock, flags);
val = armv6_pmcr_read();
val |= ARMV6_PMCR_ENABLE;
armv6_pmcr_write(val);
- raw_spin_unlock_irqrestore(&pmu_lock, flags);
+ raw_spin_unlock_irqrestore(&events->pmu_lock, flags);
}
static void
armv6pmu_stop(void)
{
unsigned long flags, val;
+ struct pmu_hw_events *events = cpu_pmu->get_hw_events();
- raw_spin_lock_irqsave(&pmu_lock, flags);
+ raw_spin_lock_irqsave(&events->pmu_lock, flags);
val = armv6_pmcr_read();
val &= ~ARMV6_PMCR_ENABLE;
armv6_pmcr_write(val);
- raw_spin_unlock_irqrestore(&pmu_lock, flags);
+ raw_spin_unlock_irqrestore(&events->pmu_lock, flags);
}
static int
-armv6pmu_get_event_idx(struct cpu_hw_events *cpuc,
+armv6pmu_get_event_idx(struct pmu_hw_events *cpuc,
struct hw_perf_event *event)
{
/* Always place a cycle counter into the cycle counter. */
@@ -578,6 +598,7 @@
int idx)
{
unsigned long val, mask, evt, flags;
+ struct pmu_hw_events *events = cpu_pmu->get_hw_events();
if (ARMV6_CYCLE_COUNTER == idx) {
mask = ARMV6_PMCR_CCOUNT_IEN;
@@ -598,12 +619,12 @@
* of ETM bus signal assertion cycles. The external reporting should
* be disabled and so this should never increment.
*/
- raw_spin_lock_irqsave(&pmu_lock, flags);
+ raw_spin_lock_irqsave(&events->pmu_lock, flags);
val = armv6_pmcr_read();
val &= ~mask;
val |= evt;
armv6_pmcr_write(val);
- raw_spin_unlock_irqrestore(&pmu_lock, flags);
+ raw_spin_unlock_irqrestore(&events->pmu_lock, flags);
}
static void
@@ -611,6 +632,7 @@
int idx)
{
unsigned long val, mask, flags, evt = 0;
+ struct pmu_hw_events *events = cpu_pmu->get_hw_events();
if (ARMV6_CYCLE_COUNTER == idx) {
mask = ARMV6_PMCR_CCOUNT_IEN;
@@ -627,15 +649,21 @@
* Unlike UP ARMv6, we don't have a way of stopping the counters. We
* simply disable the interrupt reporting.
*/
- raw_spin_lock_irqsave(&pmu_lock, flags);
+ raw_spin_lock_irqsave(&events->pmu_lock, flags);
val = armv6_pmcr_read();
val &= ~mask;
val |= evt;
armv6_pmcr_write(val);
- raw_spin_unlock_irqrestore(&pmu_lock, flags);
+ raw_spin_unlock_irqrestore(&events->pmu_lock, flags);
}
-static const struct arm_pmu armv6pmu = {
+static int armv6_map_event(struct perf_event *event)
+{
+ return map_cpu_event(event, &armv6_perf_map,
+ &armv6_perf_cache_map, 0xFF);
+}
+
+static struct arm_pmu armv6pmu = {
.id = ARM_PERF_PMU_ID_V6,
.name = "v6",
.handle_irq = armv6pmu_handle_irq,
@@ -646,14 +674,12 @@
.get_event_idx = armv6pmu_get_event_idx,
.start = armv6pmu_start,
.stop = armv6pmu_stop,
- .cache_map = &armv6_perf_cache_map,
- .event_map = &armv6_perf_map,
- .raw_event_mask = 0xFF,
+ .map_event = armv6_map_event,
.num_events = 3,
.max_period = (1LLU << 32) - 1,
};
-static const struct arm_pmu *__init armv6pmu_init(void)
+static struct arm_pmu *__init armv6pmu_init(void)
{
return &armv6pmu;
}
@@ -665,7 +691,14 @@
* disable the interrupt reporting and update the event. When unthrottling we
* reset the period and enable the interrupt reporting.
*/
-static const struct arm_pmu armv6mpcore_pmu = {
+
+static int armv6mpcore_map_event(struct perf_event *event)
+{
+ return map_cpu_event(event, &armv6mpcore_perf_map,
+ &armv6mpcore_perf_cache_map, 0xFF);
+}
+
+static struct arm_pmu armv6mpcore_pmu = {
.id = ARM_PERF_PMU_ID_V6MP,
.name = "v6mpcore",
.handle_irq = armv6pmu_handle_irq,
@@ -676,24 +709,22 @@
.get_event_idx = armv6pmu_get_event_idx,
.start = armv6pmu_start,
.stop = armv6pmu_stop,
- .cache_map = &armv6mpcore_perf_cache_map,
- .event_map = &armv6mpcore_perf_map,
- .raw_event_mask = 0xFF,
+ .map_event = armv6mpcore_map_event,
.num_events = 3,
.max_period = (1LLU << 32) - 1,
};
-static const struct arm_pmu *__init armv6mpcore_pmu_init(void)
+static struct arm_pmu *__init armv6mpcore_pmu_init(void)
{
return &armv6mpcore_pmu;
}
#else
-static const struct arm_pmu *__init armv6pmu_init(void)
+static struct arm_pmu *__init armv6pmu_init(void)
{
return NULL;
}
-static const struct arm_pmu *__init armv6mpcore_pmu_init(void)
+static struct arm_pmu *__init armv6mpcore_pmu_init(void)
{
return NULL;
}
diff --git a/arch/arm/kernel/perf_event_v7.c b/arch/arm/kernel/perf_event_v7.c
index 4c85183..98b7573 100644
--- a/arch/arm/kernel/perf_event_v7.c
+++ b/arch/arm/kernel/perf_event_v7.c
@@ -17,6 +17,9 @@
*/
#ifdef CONFIG_CPU_V7
+
+static struct arm_pmu armv7pmu;
+
/*
* Common ARMv7 event types
*
@@ -676,25 +679,26 @@
};
/*
- * Perf Events counters
+ * Perf Events' indices
*/
-enum armv7_counters {
- ARMV7_CYCLE_COUNTER = 1, /* Cycle counter */
- ARMV7_COUNTER0 = 2, /* First event counter */
-};
+#define ARMV7_IDX_CYCLE_COUNTER 0
+#define ARMV7_IDX_COUNTER0 1
+#define ARMV7_IDX_COUNTER_LAST (ARMV7_IDX_CYCLE_COUNTER + cpu_pmu->num_events - 1)
-/*
- * The cycle counter is ARMV7_CYCLE_COUNTER.
- * The first event counter is ARMV7_COUNTER0.
- * The last event counter is (ARMV7_COUNTER0 + armpmu->num_events - 1).
- */
-#define ARMV7_COUNTER_LAST (ARMV7_COUNTER0 + armpmu->num_events - 1)
+#define ARMV7_MAX_COUNTERS 32
+#define ARMV7_COUNTER_MASK (ARMV7_MAX_COUNTERS - 1)
/*
* ARMv7 low level PMNC access
*/
/*
+ * Perf Event to low level counters mapping
+ */
+#define ARMV7_IDX_TO_COUNTER(x) \
+ (((x) - ARMV7_IDX_COUNTER0) & ARMV7_COUNTER_MASK)
+
+/*
* Per-CPU PMNC: config reg
*/
#define ARMV7_PMNC_E (1 << 0) /* Enable all counters */
@@ -708,103 +712,76 @@
#define ARMV7_PMNC_MASK 0x3f /* Mask for writable bits */
/*
- * Available counters
- */
-#define ARMV7_CNT0 0 /* First event counter */
-#define ARMV7_CCNT 31 /* Cycle counter */
-
-/* Perf Event to low level counters mapping */
-#define ARMV7_EVENT_CNT_TO_CNTx (ARMV7_COUNTER0 - ARMV7_CNT0)
-
-/*
- * CNTENS: counters enable reg
- */
-#define ARMV7_CNTENS_P(idx) (1 << (idx - ARMV7_EVENT_CNT_TO_CNTx))
-#define ARMV7_CNTENS_C (1 << ARMV7_CCNT)
-
-/*
- * CNTENC: counters disable reg
- */
-#define ARMV7_CNTENC_P(idx) (1 << (idx - ARMV7_EVENT_CNT_TO_CNTx))
-#define ARMV7_CNTENC_C (1 << ARMV7_CCNT)
-
-/*
- * INTENS: counters overflow interrupt enable reg
- */
-#define ARMV7_INTENS_P(idx) (1 << (idx - ARMV7_EVENT_CNT_TO_CNTx))
-#define ARMV7_INTENS_C (1 << ARMV7_CCNT)
-
-/*
- * INTENC: counters overflow interrupt disable reg
- */
-#define ARMV7_INTENC_P(idx) (1 << (idx - ARMV7_EVENT_CNT_TO_CNTx))
-#define ARMV7_INTENC_C (1 << ARMV7_CCNT)
-
-/*
- * EVTSEL: Event selection reg
- */
-#define ARMV7_EVTSEL_MASK 0xff /* Mask for writable bits */
-
-/*
- * SELECT: Counter selection reg
- */
-#define ARMV7_SELECT_MASK 0x1f /* Mask for writable bits */
-
-/*
* FLAG: counters overflow flag status reg
*/
-#define ARMV7_FLAG_P(idx) (1 << (idx - ARMV7_EVENT_CNT_TO_CNTx))
-#define ARMV7_FLAG_C (1 << ARMV7_CCNT)
#define ARMV7_FLAG_MASK 0xffffffff /* Mask for writable bits */
#define ARMV7_OVERFLOWED_MASK ARMV7_FLAG_MASK
-static inline unsigned long armv7_pmnc_read(void)
+/*
+ * PMXEVTYPER: Event selection reg
+ */
+#define ARMV7_EVTYPE_MASK 0xc00000ff /* Mask for writable bits */
+#define ARMV7_EVTYPE_EVENT 0xff /* Mask for EVENT bits */
+
+/*
+ * Event filters for PMUv2
+ */
+#define ARMV7_EXCLUDE_PL1 (1 << 31)
+#define ARMV7_EXCLUDE_USER (1 << 30)
+#define ARMV7_INCLUDE_HYP (1 << 27)
+
+static inline u32 armv7_pmnc_read(void)
{
u32 val;
asm volatile("mrc p15, 0, %0, c9, c12, 0" : "=r"(val));
return val;
}
-static inline void armv7_pmnc_write(unsigned long val)
+static inline void armv7_pmnc_write(u32 val)
{
val &= ARMV7_PMNC_MASK;
isb();
asm volatile("mcr p15, 0, %0, c9, c12, 0" : : "r"(val));
}
-static inline int armv7_pmnc_has_overflowed(unsigned long pmnc)
+static inline int armv7_pmnc_has_overflowed(u32 pmnc)
{
return pmnc & ARMV7_OVERFLOWED_MASK;
}
-static inline int armv7_pmnc_counter_has_overflowed(unsigned long pmnc,
- enum armv7_counters counter)
+static inline int armv7_pmnc_counter_valid(int idx)
+{
+ return idx >= ARMV7_IDX_CYCLE_COUNTER && idx <= ARMV7_IDX_COUNTER_LAST;
+}
+
+static inline int armv7_pmnc_counter_has_overflowed(u32 pmnc, int idx)
{
int ret = 0;
+ u32 counter;
- if (counter == ARMV7_CYCLE_COUNTER)
- ret = pmnc & ARMV7_FLAG_C;
- else if ((counter >= ARMV7_COUNTER0) && (counter <= ARMV7_COUNTER_LAST))
- ret = pmnc & ARMV7_FLAG_P(counter);
- else
+ if (!armv7_pmnc_counter_valid(idx)) {
pr_err("CPU%u checking wrong counter %d overflow status\n",
- smp_processor_id(), counter);
+ smp_processor_id(), idx);
+ } else {
+ counter = ARMV7_IDX_TO_COUNTER(idx);
+ ret = pmnc & BIT(counter);
+ }
return ret;
}
-static inline int armv7_pmnc_select_counter(unsigned int idx)
+static inline int armv7_pmnc_select_counter(int idx)
{
- u32 val;
+ u32 counter;
- if ((idx < ARMV7_COUNTER0) || (idx > ARMV7_COUNTER_LAST)) {
- pr_err("CPU%u selecting wrong PMNC counter"
- " %d\n", smp_processor_id(), idx);
- return -1;
+ if (!armv7_pmnc_counter_valid(idx)) {
+ pr_err("CPU%u selecting wrong PMNC counter %d\n",
+ smp_processor_id(), idx);
+ return -EINVAL;
}
- val = (idx - ARMV7_EVENT_CNT_TO_CNTx) & ARMV7_SELECT_MASK;
- asm volatile("mcr p15, 0, %0, c9, c12, 5" : : "r" (val));
+ counter = ARMV7_IDX_TO_COUNTER(idx);
+ asm volatile("mcr p15, 0, %0, c9, c12, 5" : : "r" (counter));
isb();
return idx;
@@ -812,124 +789,95 @@
static inline u32 armv7pmu_read_counter(int idx)
{
- unsigned long value = 0;
+ u32 value = 0;
- if (idx == ARMV7_CYCLE_COUNTER)
- asm volatile("mrc p15, 0, %0, c9, c13, 0" : "=r" (value));
- else if ((idx >= ARMV7_COUNTER0) && (idx <= ARMV7_COUNTER_LAST)) {
- if (armv7_pmnc_select_counter(idx) == idx)
- asm volatile("mrc p15, 0, %0, c9, c13, 2"
- : "=r" (value));
- } else
+ if (!armv7_pmnc_counter_valid(idx))
pr_err("CPU%u reading wrong counter %d\n",
smp_processor_id(), idx);
+ else if (idx == ARMV7_IDX_CYCLE_COUNTER)
+ asm volatile("mrc p15, 0, %0, c9, c13, 0" : "=r" (value));
+ else if (armv7_pmnc_select_counter(idx) == idx)
+ asm volatile("mrc p15, 0, %0, c9, c13, 2" : "=r" (value));
return value;
}
static inline void armv7pmu_write_counter(int idx, u32 value)
{
- if (idx == ARMV7_CYCLE_COUNTER)
- asm volatile("mcr p15, 0, %0, c9, c13, 0" : : "r" (value));
- else if ((idx >= ARMV7_COUNTER0) && (idx <= ARMV7_COUNTER_LAST)) {
- if (armv7_pmnc_select_counter(idx) == idx)
- asm volatile("mcr p15, 0, %0, c9, c13, 2"
- : : "r" (value));
- } else
+ if (!armv7_pmnc_counter_valid(idx))
pr_err("CPU%u writing wrong counter %d\n",
smp_processor_id(), idx);
+ else if (idx == ARMV7_IDX_CYCLE_COUNTER)
+ asm volatile("mcr p15, 0, %0, c9, c13, 0" : : "r" (value));
+ else if (armv7_pmnc_select_counter(idx) == idx)
+ asm volatile("mcr p15, 0, %0, c9, c13, 2" : : "r" (value));
}
-static inline void armv7_pmnc_write_evtsel(unsigned int idx, u32 val)
+static inline void armv7_pmnc_write_evtsel(int idx, u32 val)
{
if (armv7_pmnc_select_counter(idx) == idx) {
- val &= ARMV7_EVTSEL_MASK;
+ val &= ARMV7_EVTYPE_MASK;
asm volatile("mcr p15, 0, %0, c9, c13, 1" : : "r" (val));
}
}
-static inline u32 armv7_pmnc_enable_counter(unsigned int idx)
+static inline int armv7_pmnc_enable_counter(int idx)
{
- u32 val;
+ u32 counter;
- if ((idx != ARMV7_CYCLE_COUNTER) &&
- ((idx < ARMV7_COUNTER0) || (idx > ARMV7_COUNTER_LAST))) {
- pr_err("CPU%u enabling wrong PMNC counter"
- " %d\n", smp_processor_id(), idx);
- return -1;
+ if (!armv7_pmnc_counter_valid(idx)) {
+ pr_err("CPU%u enabling wrong PMNC counter %d\n",
+ smp_processor_id(), idx);
+ return -EINVAL;
}
- if (idx == ARMV7_CYCLE_COUNTER)
- val = ARMV7_CNTENS_C;
- else
- val = ARMV7_CNTENS_P(idx);
-
- asm volatile("mcr p15, 0, %0, c9, c12, 1" : : "r" (val));
-
+ counter = ARMV7_IDX_TO_COUNTER(idx);
+ asm volatile("mcr p15, 0, %0, c9, c12, 1" : : "r" (BIT(counter)));
return idx;
}
-static inline u32 armv7_pmnc_disable_counter(unsigned int idx)
+static inline int armv7_pmnc_disable_counter(int idx)
{
- u32 val;
+ u32 counter;
-
- if ((idx != ARMV7_CYCLE_COUNTER) &&
- ((idx < ARMV7_COUNTER0) || (idx > ARMV7_COUNTER_LAST))) {
- pr_err("CPU%u disabling wrong PMNC counter"
- " %d\n", smp_processor_id(), idx);
- return -1;
+ if (!armv7_pmnc_counter_valid(idx)) {
+ pr_err("CPU%u disabling wrong PMNC counter %d\n",
+ smp_processor_id(), idx);
+ return -EINVAL;
}
- if (idx == ARMV7_CYCLE_COUNTER)
- val = ARMV7_CNTENC_C;
- else
- val = ARMV7_CNTENC_P(idx);
-
- asm volatile("mcr p15, 0, %0, c9, c12, 2" : : "r" (val));
-
+ counter = ARMV7_IDX_TO_COUNTER(idx);
+ asm volatile("mcr p15, 0, %0, c9, c12, 2" : : "r" (BIT(counter)));
return idx;
}
-static inline u32 armv7_pmnc_enable_intens(unsigned int idx)
+static inline int armv7_pmnc_enable_intens(int idx)
{
- u32 val;
+ u32 counter;
- if ((idx != ARMV7_CYCLE_COUNTER) &&
- ((idx < ARMV7_COUNTER0) || (idx > ARMV7_COUNTER_LAST))) {
- pr_err("CPU%u enabling wrong PMNC counter"
- " interrupt enable %d\n", smp_processor_id(), idx);
- return -1;
+ if (!armv7_pmnc_counter_valid(idx)) {
+ pr_err("CPU%u enabling wrong PMNC counter IRQ enable %d\n",
+ smp_processor_id(), idx);
+ return -EINVAL;
}
- if (idx == ARMV7_CYCLE_COUNTER)
- val = ARMV7_INTENS_C;
- else
- val = ARMV7_INTENS_P(idx);
-
- asm volatile("mcr p15, 0, %0, c9, c14, 1" : : "r" (val));
-
+ counter = ARMV7_IDX_TO_COUNTER(idx);
+ asm volatile("mcr p15, 0, %0, c9, c14, 1" : : "r" (BIT(counter)));
return idx;
}
-static inline u32 armv7_pmnc_disable_intens(unsigned int idx)
+static inline int armv7_pmnc_disable_intens(int idx)
{
- u32 val;
+ u32 counter;
- if ((idx != ARMV7_CYCLE_COUNTER) &&
- ((idx < ARMV7_COUNTER0) || (idx > ARMV7_COUNTER_LAST))) {
- pr_err("CPU%u disabling wrong PMNC counter"
- " interrupt enable %d\n", smp_processor_id(), idx);
- return -1;
+ if (!armv7_pmnc_counter_valid(idx)) {
+ pr_err("CPU%u disabling wrong PMNC counter IRQ enable %d\n",
+ smp_processor_id(), idx);
+ return -EINVAL;
}
- if (idx == ARMV7_CYCLE_COUNTER)
- val = ARMV7_INTENC_C;
- else
- val = ARMV7_INTENC_P(idx);
-
- asm volatile("mcr p15, 0, %0, c9, c14, 2" : : "r" (val));
-
+ counter = ARMV7_IDX_TO_COUNTER(idx);
+ asm volatile("mcr p15, 0, %0, c9, c14, 2" : : "r" (BIT(counter)));
return idx;
}
@@ -973,14 +921,14 @@
asm volatile("mrc p15, 0, %0, c9, c13, 0" : "=r" (val));
printk(KERN_INFO "CCNT =0x%08x\n", val);
- for (cnt = ARMV7_COUNTER0; cnt < ARMV7_COUNTER_LAST; cnt++) {
+ for (cnt = ARMV7_IDX_COUNTER0; cnt <= ARMV7_IDX_COUNTER_LAST; cnt++) {
armv7_pmnc_select_counter(cnt);
asm volatile("mrc p15, 0, %0, c9, c13, 2" : "=r" (val));
printk(KERN_INFO "CNT[%d] count =0x%08x\n",
- cnt-ARMV7_EVENT_CNT_TO_CNTx, val);
+ ARMV7_IDX_TO_COUNTER(cnt), val);
asm volatile("mrc p15, 0, %0, c9, c13, 1" : "=r" (val));
printk(KERN_INFO "CNT[%d] evtsel=0x%08x\n",
- cnt-ARMV7_EVENT_CNT_TO_CNTx, val);
+ ARMV7_IDX_TO_COUNTER(cnt), val);
}
}
#endif
@@ -988,12 +936,13 @@
static void armv7pmu_enable_event(struct hw_perf_event *hwc, int idx)
{
unsigned long flags;
+ struct pmu_hw_events *events = cpu_pmu->get_hw_events();
/*
* Enable counter and interrupt, and set the counter to count
* the event that we're interested in.
*/
- raw_spin_lock_irqsave(&pmu_lock, flags);
+ raw_spin_lock_irqsave(&events->pmu_lock, flags);
/*
* Disable counter
@@ -1002,9 +951,10 @@
/*
* Set event (if destined for PMNx counters)
- * We don't need to set the event if it's a cycle count
+ * We only need to set the event for the cycle counter if we
+ * have the ability to perform event filtering.
*/
- if (idx != ARMV7_CYCLE_COUNTER)
+ if (armv7pmu.set_event_filter || idx != ARMV7_IDX_CYCLE_COUNTER)
armv7_pmnc_write_evtsel(idx, hwc->config_base);
/*
@@ -1017,17 +967,18 @@
*/
armv7_pmnc_enable_counter(idx);
- raw_spin_unlock_irqrestore(&pmu_lock, flags);
+ raw_spin_unlock_irqrestore(&events->pmu_lock, flags);
}
static void armv7pmu_disable_event(struct hw_perf_event *hwc, int idx)
{
unsigned long flags;
+ struct pmu_hw_events *events = cpu_pmu->get_hw_events();
/*
* Disable counter and interrupt
*/
- raw_spin_lock_irqsave(&pmu_lock, flags);
+ raw_spin_lock_irqsave(&events->pmu_lock, flags);
/*
* Disable counter
@@ -1039,14 +990,14 @@
*/
armv7_pmnc_disable_intens(idx);
- raw_spin_unlock_irqrestore(&pmu_lock, flags);
+ raw_spin_unlock_irqrestore(&events->pmu_lock, flags);
}
static irqreturn_t armv7pmu_handle_irq(int irq_num, void *dev)
{
- unsigned long pmnc;
+ u32 pmnc;
struct perf_sample_data data;
- struct cpu_hw_events *cpuc;
+ struct pmu_hw_events *cpuc;
struct pt_regs *regs;
int idx;
@@ -1069,13 +1020,10 @@
perf_sample_data_init(&data, 0);
cpuc = &__get_cpu_var(cpu_hw_events);
- for (idx = 0; idx <= armpmu->num_events; ++idx) {
+ for (idx = 0; idx < cpu_pmu->num_events; ++idx) {
struct perf_event *event = cpuc->events[idx];
struct hw_perf_event *hwc;
- if (!test_bit(idx, cpuc->active_mask))
- continue;
-
/*
* We have a single interrupt for all counters. Check that
* each counter has overflowed before we process it.
@@ -1090,7 +1038,7 @@
continue;
if (perf_event_overflow(event, &data, regs))
- armpmu->disable(hwc, idx);
+ cpu_pmu->disable(hwc, idx);
}
/*
@@ -1108,61 +1056,114 @@
static void armv7pmu_start(void)
{
unsigned long flags;
+ struct pmu_hw_events *events = cpu_pmu->get_hw_events();
- raw_spin_lock_irqsave(&pmu_lock, flags);
+ raw_spin_lock_irqsave(&events->pmu_lock, flags);
/* Enable all counters */
armv7_pmnc_write(armv7_pmnc_read() | ARMV7_PMNC_E);
- raw_spin_unlock_irqrestore(&pmu_lock, flags);
+ raw_spin_unlock_irqrestore(&events->pmu_lock, flags);
}
static void armv7pmu_stop(void)
{
unsigned long flags;
+ struct pmu_hw_events *events = cpu_pmu->get_hw_events();
- raw_spin_lock_irqsave(&pmu_lock, flags);
+ raw_spin_lock_irqsave(&events->pmu_lock, flags);
/* Disable all counters */
armv7_pmnc_write(armv7_pmnc_read() & ~ARMV7_PMNC_E);
- raw_spin_unlock_irqrestore(&pmu_lock, flags);
+ raw_spin_unlock_irqrestore(&events->pmu_lock, flags);
}
-static int armv7pmu_get_event_idx(struct cpu_hw_events *cpuc,
+static int armv7pmu_get_event_idx(struct pmu_hw_events *cpuc,
struct hw_perf_event *event)
{
int idx;
+ unsigned long evtype = event->config_base & ARMV7_EVTYPE_EVENT;
/* Always place a cycle counter into the cycle counter. */
- if (event->config_base == ARMV7_PERFCTR_CPU_CYCLES) {
- if (test_and_set_bit(ARMV7_CYCLE_COUNTER, cpuc->used_mask))
+ if (evtype == ARMV7_PERFCTR_CPU_CYCLES) {
+ if (test_and_set_bit(ARMV7_IDX_CYCLE_COUNTER, cpuc->used_mask))
return -EAGAIN;
- return ARMV7_CYCLE_COUNTER;
- } else {
- /*
- * For anything other than a cycle counter, try and use
- * the events counters
- */
- for (idx = ARMV7_COUNTER0; idx <= armpmu->num_events; ++idx) {
- if (!test_and_set_bit(idx, cpuc->used_mask))
- return idx;
- }
-
- /* The counters are all in use. */
- return -EAGAIN;
+ return ARMV7_IDX_CYCLE_COUNTER;
}
+
+ /*
+ * For anything other than a cycle counter, try and use
+ * the events counters
+ */
+ for (idx = ARMV7_IDX_COUNTER0; idx < cpu_pmu->num_events; ++idx) {
+ if (!test_and_set_bit(idx, cpuc->used_mask))
+ return idx;
+ }
+
+ /* The counters are all in use. */
+ return -EAGAIN;
+}
+
+/*
+ * Add an event filter to a given event. This will only work for PMUv2 PMUs.
+ */
+static int armv7pmu_set_event_filter(struct hw_perf_event *event,
+ struct perf_event_attr *attr)
+{
+ unsigned long config_base = 0;
+
+ if (attr->exclude_idle)
+ return -EPERM;
+ if (attr->exclude_user)
+ config_base |= ARMV7_EXCLUDE_USER;
+ if (attr->exclude_kernel)
+ config_base |= ARMV7_EXCLUDE_PL1;
+ if (!attr->exclude_hv)
+ config_base |= ARMV7_INCLUDE_HYP;
+
+ /*
+ * Install the filter into config_base as this is used to
+ * construct the event type.
+ */
+ event->config_base = config_base;
+
+ return 0;
}
static void armv7pmu_reset(void *info)
{
- u32 idx, nb_cnt = armpmu->num_events;
+ u32 idx, nb_cnt = cpu_pmu->num_events;
/* The counter and interrupt enable registers are unknown at reset. */
- for (idx = 1; idx < nb_cnt; ++idx)
+ for (idx = ARMV7_IDX_CYCLE_COUNTER; idx < nb_cnt; ++idx)
armv7pmu_disable_event(NULL, idx);
/* Initialize & Reset PMNC: C and P bits */
armv7_pmnc_write(ARMV7_PMNC_P | ARMV7_PMNC_C);
}
+static int armv7_a8_map_event(struct perf_event *event)
+{
+ return map_cpu_event(event, &armv7_a8_perf_map,
+ &armv7_a8_perf_cache_map, 0xFF);
+}
+
+static int armv7_a9_map_event(struct perf_event *event)
+{
+ return map_cpu_event(event, &armv7_a9_perf_map,
+ &armv7_a9_perf_cache_map, 0xFF);
+}
+
+static int armv7_a5_map_event(struct perf_event *event)
+{
+ return map_cpu_event(event, &armv7_a5_perf_map,
+ &armv7_a5_perf_cache_map, 0xFF);
+}
+
+static int armv7_a15_map_event(struct perf_event *event)
+{
+ return map_cpu_event(event, &armv7_a15_perf_map,
+ &armv7_a15_perf_cache_map, 0xFF);
+}
+
static struct arm_pmu armv7pmu = {
.handle_irq = armv7pmu_handle_irq,
.enable = armv7pmu_enable_event,
@@ -1173,7 +1174,6 @@
.start = armv7pmu_start,
.stop = armv7pmu_stop,
.reset = armv7pmu_reset,
- .raw_event_mask = 0xFF,
.max_period = (1LLU << 32) - 1,
};
@@ -1188,62 +1188,59 @@
return nb_cnt + 1;
}
-static const struct arm_pmu *__init armv7_a8_pmu_init(void)
+static struct arm_pmu *__init armv7_a8_pmu_init(void)
{
armv7pmu.id = ARM_PERF_PMU_ID_CA8;
armv7pmu.name = "ARMv7 Cortex-A8";
- armv7pmu.cache_map = &armv7_a8_perf_cache_map;
- armv7pmu.event_map = &armv7_a8_perf_map;
+ armv7pmu.map_event = armv7_a8_map_event;
armv7pmu.num_events = armv7_read_num_pmnc_events();
return &armv7pmu;
}
-static const struct arm_pmu *__init armv7_a9_pmu_init(void)
+static struct arm_pmu *__init armv7_a9_pmu_init(void)
{
armv7pmu.id = ARM_PERF_PMU_ID_CA9;
armv7pmu.name = "ARMv7 Cortex-A9";
- armv7pmu.cache_map = &armv7_a9_perf_cache_map;
- armv7pmu.event_map = &armv7_a9_perf_map;
+ armv7pmu.map_event = armv7_a9_map_event;
armv7pmu.num_events = armv7_read_num_pmnc_events();
return &armv7pmu;
}
-static const struct arm_pmu *__init armv7_a5_pmu_init(void)
+static struct arm_pmu *__init armv7_a5_pmu_init(void)
{
armv7pmu.id = ARM_PERF_PMU_ID_CA5;
armv7pmu.name = "ARMv7 Cortex-A5";
- armv7pmu.cache_map = &armv7_a5_perf_cache_map;
- armv7pmu.event_map = &armv7_a5_perf_map;
+ armv7pmu.map_event = armv7_a5_map_event;
armv7pmu.num_events = armv7_read_num_pmnc_events();
return &armv7pmu;
}
-static const struct arm_pmu *__init armv7_a15_pmu_init(void)
+static struct arm_pmu *__init armv7_a15_pmu_init(void)
{
armv7pmu.id = ARM_PERF_PMU_ID_CA15;
armv7pmu.name = "ARMv7 Cortex-A15";
- armv7pmu.cache_map = &armv7_a15_perf_cache_map;
- armv7pmu.event_map = &armv7_a15_perf_map;
+ armv7pmu.map_event = armv7_a15_map_event;
armv7pmu.num_events = armv7_read_num_pmnc_events();
+ armv7pmu.set_event_filter = armv7pmu_set_event_filter;
return &armv7pmu;
}
#else
-static const struct arm_pmu *__init armv7_a8_pmu_init(void)
+static struct arm_pmu *__init armv7_a8_pmu_init(void)
{
return NULL;
}
-static const struct arm_pmu *__init armv7_a9_pmu_init(void)
+static struct arm_pmu *__init armv7_a9_pmu_init(void)
{
return NULL;
}
-static const struct arm_pmu *__init armv7_a5_pmu_init(void)
+static struct arm_pmu *__init armv7_a5_pmu_init(void)
{
return NULL;
}
-static const struct arm_pmu *__init armv7_a15_pmu_init(void)
+static struct arm_pmu *__init armv7_a15_pmu_init(void)
{
return NULL;
}
diff --git a/arch/arm/kernel/perf_event_xscale.c b/arch/arm/kernel/perf_event_xscale.c
index 3c43974..e0cca10 100644
--- a/arch/arm/kernel/perf_event_xscale.c
+++ b/arch/arm/kernel/perf_event_xscale.c
@@ -40,7 +40,7 @@
};
enum xscale_counters {
- XSCALE_CYCLE_COUNTER = 1,
+ XSCALE_CYCLE_COUNTER = 0,
XSCALE_COUNTER0,
XSCALE_COUNTER1,
XSCALE_COUNTER2,
@@ -222,7 +222,7 @@
{
unsigned long pmnc;
struct perf_sample_data data;
- struct cpu_hw_events *cpuc;
+ struct pmu_hw_events *cpuc;
struct pt_regs *regs;
int idx;
@@ -249,13 +249,10 @@
perf_sample_data_init(&data, 0);
cpuc = &__get_cpu_var(cpu_hw_events);
- for (idx = 0; idx <= armpmu->num_events; ++idx) {
+ for (idx = 0; idx < cpu_pmu->num_events; ++idx) {
struct perf_event *event = cpuc->events[idx];
struct hw_perf_event *hwc;
- if (!test_bit(idx, cpuc->active_mask))
- continue;
-
if (!xscale1_pmnc_counter_has_overflowed(pmnc, idx))
continue;
@@ -266,7 +263,7 @@
continue;
if (perf_event_overflow(event, &data, regs))
- armpmu->disable(hwc, idx);
+ cpu_pmu->disable(hwc, idx);
}
irq_work_run();
@@ -284,6 +281,7 @@
xscale1pmu_enable_event(struct hw_perf_event *hwc, int idx)
{
unsigned long val, mask, evt, flags;
+ struct pmu_hw_events *events = cpu_pmu->get_hw_events();
switch (idx) {
case XSCALE_CYCLE_COUNTER:
@@ -305,18 +303,19 @@
return;
}
- raw_spin_lock_irqsave(&pmu_lock, flags);
+ raw_spin_lock_irqsave(&events->pmu_lock, flags);
val = xscale1pmu_read_pmnc();
val &= ~mask;
val |= evt;
xscale1pmu_write_pmnc(val);
- raw_spin_unlock_irqrestore(&pmu_lock, flags);
+ raw_spin_unlock_irqrestore(&events->pmu_lock, flags);
}
static void
xscale1pmu_disable_event(struct hw_perf_event *hwc, int idx)
{
unsigned long val, mask, evt, flags;
+ struct pmu_hw_events *events = cpu_pmu->get_hw_events();
switch (idx) {
case XSCALE_CYCLE_COUNTER:
@@ -336,16 +335,16 @@
return;
}
- raw_spin_lock_irqsave(&pmu_lock, flags);
+ raw_spin_lock_irqsave(&events->pmu_lock, flags);
val = xscale1pmu_read_pmnc();
val &= ~mask;
val |= evt;
xscale1pmu_write_pmnc(val);
- raw_spin_unlock_irqrestore(&pmu_lock, flags);
+ raw_spin_unlock_irqrestore(&events->pmu_lock, flags);
}
static int
-xscale1pmu_get_event_idx(struct cpu_hw_events *cpuc,
+xscale1pmu_get_event_idx(struct pmu_hw_events *cpuc,
struct hw_perf_event *event)
{
if (XSCALE_PERFCTR_CCNT == event->config_base) {
@@ -368,24 +367,26 @@
xscale1pmu_start(void)
{
unsigned long flags, val;
+ struct pmu_hw_events *events = cpu_pmu->get_hw_events();
- raw_spin_lock_irqsave(&pmu_lock, flags);
+ raw_spin_lock_irqsave(&events->pmu_lock, flags);
val = xscale1pmu_read_pmnc();
val |= XSCALE_PMU_ENABLE;
xscale1pmu_write_pmnc(val);
- raw_spin_unlock_irqrestore(&pmu_lock, flags);
+ raw_spin_unlock_irqrestore(&events->pmu_lock, flags);
}
static void
xscale1pmu_stop(void)
{
unsigned long flags, val;
+ struct pmu_hw_events *events = cpu_pmu->get_hw_events();
- raw_spin_lock_irqsave(&pmu_lock, flags);
+ raw_spin_lock_irqsave(&events->pmu_lock, flags);
val = xscale1pmu_read_pmnc();
val &= ~XSCALE_PMU_ENABLE;
xscale1pmu_write_pmnc(val);
- raw_spin_unlock_irqrestore(&pmu_lock, flags);
+ raw_spin_unlock_irqrestore(&events->pmu_lock, flags);
}
static inline u32
@@ -424,7 +425,13 @@
}
}
-static const struct arm_pmu xscale1pmu = {
+static int xscale_map_event(struct perf_event *event)
+{
+ return map_cpu_event(event, &xscale_perf_map,
+ &xscale_perf_cache_map, 0xFF);
+}
+
+static struct arm_pmu xscale1pmu = {
.id = ARM_PERF_PMU_ID_XSCALE1,
.name = "xscale1",
.handle_irq = xscale1pmu_handle_irq,
@@ -435,14 +442,12 @@
.get_event_idx = xscale1pmu_get_event_idx,
.start = xscale1pmu_start,
.stop = xscale1pmu_stop,
- .cache_map = &xscale_perf_cache_map,
- .event_map = &xscale_perf_map,
- .raw_event_mask = 0xFF,
+ .map_event = xscale_map_event,
.num_events = 3,
.max_period = (1LLU << 32) - 1,
};
-static const struct arm_pmu *__init xscale1pmu_init(void)
+static struct arm_pmu *__init xscale1pmu_init(void)
{
return &xscale1pmu;
}
@@ -560,7 +565,7 @@
{
unsigned long pmnc, of_flags;
struct perf_sample_data data;
- struct cpu_hw_events *cpuc;
+ struct pmu_hw_events *cpuc;
struct pt_regs *regs;
int idx;
@@ -581,13 +586,10 @@
perf_sample_data_init(&data, 0);
cpuc = &__get_cpu_var(cpu_hw_events);
- for (idx = 0; idx <= armpmu->num_events; ++idx) {
+ for (idx = 0; idx < cpu_pmu->num_events; ++idx) {
struct perf_event *event = cpuc->events[idx];
struct hw_perf_event *hwc;
- if (!test_bit(idx, cpuc->active_mask))
- continue;
-
if (!xscale2_pmnc_counter_has_overflowed(pmnc, idx))
continue;
@@ -598,7 +600,7 @@
continue;
if (perf_event_overflow(event, &data, regs))
- armpmu->disable(hwc, idx);
+ cpu_pmu->disable(hwc, idx);
}
irq_work_run();
@@ -616,6 +618,7 @@
xscale2pmu_enable_event(struct hw_perf_event *hwc, int idx)
{
unsigned long flags, ien, evtsel;
+ struct pmu_hw_events *events = cpu_pmu->get_hw_events();
ien = xscale2pmu_read_int_enable();
evtsel = xscale2pmu_read_event_select();
@@ -649,16 +652,17 @@
return;
}
- raw_spin_lock_irqsave(&pmu_lock, flags);
+ raw_spin_lock_irqsave(&events->pmu_lock, flags);
xscale2pmu_write_event_select(evtsel);
xscale2pmu_write_int_enable(ien);
- raw_spin_unlock_irqrestore(&pmu_lock, flags);
+ raw_spin_unlock_irqrestore(&events->pmu_lock, flags);
}
static void
xscale2pmu_disable_event(struct hw_perf_event *hwc, int idx)
{
unsigned long flags, ien, evtsel;
+ struct pmu_hw_events *events = cpu_pmu->get_hw_events();
ien = xscale2pmu_read_int_enable();
evtsel = xscale2pmu_read_event_select();
@@ -692,14 +696,14 @@
return;
}
- raw_spin_lock_irqsave(&pmu_lock, flags);
+ raw_spin_lock_irqsave(&events->pmu_lock, flags);
xscale2pmu_write_event_select(evtsel);
xscale2pmu_write_int_enable(ien);
- raw_spin_unlock_irqrestore(&pmu_lock, flags);
+ raw_spin_unlock_irqrestore(&events->pmu_lock, flags);
}
static int
-xscale2pmu_get_event_idx(struct cpu_hw_events *cpuc,
+xscale2pmu_get_event_idx(struct pmu_hw_events *cpuc,
struct hw_perf_event *event)
{
int idx = xscale1pmu_get_event_idx(cpuc, event);
@@ -718,24 +722,26 @@
xscale2pmu_start(void)
{
unsigned long flags, val;
+ struct pmu_hw_events *events = cpu_pmu->get_hw_events();
- raw_spin_lock_irqsave(&pmu_lock, flags);
+ raw_spin_lock_irqsave(&events->pmu_lock, flags);
val = xscale2pmu_read_pmnc() & ~XSCALE_PMU_CNT64;
val |= XSCALE_PMU_ENABLE;
xscale2pmu_write_pmnc(val);
- raw_spin_unlock_irqrestore(&pmu_lock, flags);
+ raw_spin_unlock_irqrestore(&events->pmu_lock, flags);
}
static void
xscale2pmu_stop(void)
{
unsigned long flags, val;
+ struct pmu_hw_events *events = cpu_pmu->get_hw_events();
- raw_spin_lock_irqsave(&pmu_lock, flags);
+ raw_spin_lock_irqsave(&events->pmu_lock, flags);
val = xscale2pmu_read_pmnc();
val &= ~XSCALE_PMU_ENABLE;
xscale2pmu_write_pmnc(val);
- raw_spin_unlock_irqrestore(&pmu_lock, flags);
+ raw_spin_unlock_irqrestore(&events->pmu_lock, flags);
}
static inline u32
@@ -786,7 +792,7 @@
}
}
-static const struct arm_pmu xscale2pmu = {
+static struct arm_pmu xscale2pmu = {
.id = ARM_PERF_PMU_ID_XSCALE2,
.name = "xscale2",
.handle_irq = xscale2pmu_handle_irq,
@@ -797,24 +803,22 @@
.get_event_idx = xscale2pmu_get_event_idx,
.start = xscale2pmu_start,
.stop = xscale2pmu_stop,
- .cache_map = &xscale_perf_cache_map,
- .event_map = &xscale_perf_map,
- .raw_event_mask = 0xFF,
+ .map_event = xscale_map_event,
.num_events = 5,
.max_period = (1LLU << 32) - 1,
};
-static const struct arm_pmu *__init xscale2pmu_init(void)
+static struct arm_pmu *__init xscale2pmu_init(void)
{
return &xscale2pmu;
}
#else
-static const struct arm_pmu *__init xscale1pmu_init(void)
+static struct arm_pmu *__init xscale1pmu_init(void)
{
return NULL;
}
-static const struct arm_pmu *__init xscale2pmu_init(void)
+static struct arm_pmu *__init xscale2pmu_init(void)
{
return NULL;
}
diff --git a/arch/arm/kernel/pmu.c b/arch/arm/kernel/pmu.c
index 2b70709..2c3407e 100644
--- a/arch/arm/kernel/pmu.c
+++ b/arch/arm/kernel/pmu.c
@@ -10,192 +10,26 @@
*
*/
-#define pr_fmt(fmt) "PMU: " fmt
-
-#include <linux/cpumask.h>
#include <linux/err.h>
-#include <linux/interrupt.h>
#include <linux/kernel.h>
#include <linux/module.h>
-#include <linux/of_device.h>
-#include <linux/platform_device.h>
#include <asm/pmu.h>
-static volatile long pmu_lock;
+/*
+ * PMU locking to ensure mutual exclusion between different subsystems.
+ */
+static unsigned long pmu_lock[BITS_TO_LONGS(ARM_NUM_PMU_DEVICES)];
-static struct platform_device *pmu_devices[ARM_NUM_PMU_DEVICES];
-
-static int __devinit pmu_register(struct platform_device *pdev,
- enum arm_pmu_type type)
+int
+reserve_pmu(enum arm_pmu_type type)
{
- if (type < 0 || type >= ARM_NUM_PMU_DEVICES) {
- pr_warning("received registration request for unknown "
- "device %d\n", type);
- return -EINVAL;
- }
-
- if (pmu_devices[type]) {
- pr_warning("rejecting duplicate registration of PMU device "
- "type %d.", type);
- return -ENOSPC;
- }
-
- pr_info("registered new PMU device of type %d\n", type);
- pmu_devices[type] = pdev;
- return 0;
-}
-
-#define OF_MATCH_PMU(_name, _type) { \
- .compatible = _name, \
- .data = (void *)_type, \
-}
-
-#define OF_MATCH_CPU(name) OF_MATCH_PMU(name, ARM_PMU_DEVICE_CPU)
-
-static struct of_device_id armpmu_of_device_ids[] = {
- OF_MATCH_CPU("arm,cortex-a9-pmu"),
- OF_MATCH_CPU("arm,cortex-a8-pmu"),
- OF_MATCH_CPU("arm,arm1136-pmu"),
- OF_MATCH_CPU("arm,arm1176-pmu"),
- {},
-};
-
-#define PLAT_MATCH_PMU(_name, _type) { \
- .name = _name, \
- .driver_data = _type, \
-}
-
-#define PLAT_MATCH_CPU(_name) PLAT_MATCH_PMU(_name, ARM_PMU_DEVICE_CPU)
-
-static struct platform_device_id armpmu_plat_device_ids[] = {
- PLAT_MATCH_CPU("arm-pmu"),
- {},
-};
-
-enum arm_pmu_type armpmu_device_type(struct platform_device *pdev)
-{
- const struct of_device_id *of_id;
- const struct platform_device_id *pdev_id;
-
- /* provided by of_device_id table */
- if (pdev->dev.of_node) {
- of_id = of_match_device(armpmu_of_device_ids, &pdev->dev);
- BUG_ON(!of_id);
- return (enum arm_pmu_type)of_id->data;
- }
-
- /* Provided by platform_device_id table */
- pdev_id = platform_get_device_id(pdev);
- BUG_ON(!pdev_id);
- return pdev_id->driver_data;
-}
-
-static int __devinit armpmu_device_probe(struct platform_device *pdev)
-{
- return pmu_register(pdev, armpmu_device_type(pdev));
-}
-
-static struct platform_driver armpmu_driver = {
- .driver = {
- .name = "arm-pmu",
- .of_match_table = armpmu_of_device_ids,
- },
- .probe = armpmu_device_probe,
- .id_table = armpmu_plat_device_ids,
-};
-
-static int __init register_pmu_driver(void)
-{
- return platform_driver_register(&armpmu_driver);
-}
-device_initcall(register_pmu_driver);
-
-struct platform_device *
-reserve_pmu(enum arm_pmu_type device)
-{
- struct platform_device *pdev;
-
- if (test_and_set_bit_lock(device, &pmu_lock)) {
- pdev = ERR_PTR(-EBUSY);
- } else if (pmu_devices[device] == NULL) {
- clear_bit_unlock(device, &pmu_lock);
- pdev = ERR_PTR(-ENODEV);
- } else {
- pdev = pmu_devices[device];
- }
-
- return pdev;
+ return test_and_set_bit_lock(type, pmu_lock) ? -EBUSY : 0;
}
EXPORT_SYMBOL_GPL(reserve_pmu);
-int
-release_pmu(enum arm_pmu_type device)
+void
+release_pmu(enum arm_pmu_type type)
{
- if (WARN_ON(!pmu_devices[device]))
- return -EINVAL;
- clear_bit_unlock(device, &pmu_lock);
- return 0;
+ clear_bit_unlock(type, pmu_lock);
}
-EXPORT_SYMBOL_GPL(release_pmu);
-
-static int
-set_irq_affinity(int irq,
- unsigned int cpu)
-{
-#ifdef CONFIG_SMP
- int err = irq_set_affinity(irq, cpumask_of(cpu));
- if (err)
- pr_warning("unable to set irq affinity (irq=%d, cpu=%u)\n",
- irq, cpu);
- return err;
-#else
- return -EINVAL;
-#endif
-}
-
-static int
-init_cpu_pmu(void)
-{
- int i, irqs, err = 0;
- struct platform_device *pdev = pmu_devices[ARM_PMU_DEVICE_CPU];
-
- if (!pdev)
- return -ENODEV;
-
- irqs = pdev->num_resources;
-
- /*
- * If we have a single PMU interrupt that we can't shift, assume that
- * we're running on a uniprocessor machine and continue.
- */
- if (irqs == 1 && !irq_can_set_affinity(platform_get_irq(pdev, 0)))
- return 0;
-
- for (i = 0; i < irqs; ++i) {
- err = set_irq_affinity(platform_get_irq(pdev, i), i);
- if (err)
- break;
- }
-
- return err;
-}
-
-int
-init_pmu(enum arm_pmu_type device)
-{
- int err = 0;
-
- switch (device) {
- case ARM_PMU_DEVICE_CPU:
- err = init_cpu_pmu();
- break;
- default:
- pr_warning("attempt to initialise unknown device %d\n",
- device);
- err = -EINVAL;
- }
-
- return err;
-}
-EXPORT_SYMBOL_GPL(init_pmu);
diff --git a/arch/arm/kernel/relocate_kernel.S b/arch/arm/kernel/relocate_kernel.S
index 9cf4cbf..d0cdedf 100644
--- a/arch/arm/kernel/relocate_kernel.S
+++ b/arch/arm/kernel/relocate_kernel.S
@@ -57,7 +57,8 @@
mov r0,#0
ldr r1,kexec_mach_type
ldr r2,kexec_boot_atags
- mov pc,lr
+ ARM( mov pc, lr )
+ THUMB( bx lr )
.align
diff --git a/arch/arm/kernel/setup.c b/arch/arm/kernel/setup.c
index 78d197d..6136144 100644
--- a/arch/arm/kernel/setup.c
+++ b/arch/arm/kernel/setup.c
@@ -280,18 +280,19 @@
if (arch >= CPU_ARCH_ARMv6) {
if ((cachetype & (7 << 29)) == 4 << 29) {
/* ARMv7 register format */
+ arch = CPU_ARCH_ARMv7;
cacheid = CACHEID_VIPT_NONALIASING;
if ((cachetype & (3 << 14)) == 1 << 14)
cacheid |= CACHEID_ASID_TAGGED;
- else if (cpu_has_aliasing_icache(CPU_ARCH_ARMv7))
- cacheid |= CACHEID_VIPT_I_ALIASING;
- } else if (cachetype & (1 << 23)) {
- cacheid = CACHEID_VIPT_ALIASING;
} else {
- cacheid = CACHEID_VIPT_NONALIASING;
- if (cpu_has_aliasing_icache(CPU_ARCH_ARMv6))
- cacheid |= CACHEID_VIPT_I_ALIASING;
+ arch = CPU_ARCH_ARMv6;
+ if (cachetype & (1 << 23))
+ cacheid = CACHEID_VIPT_ALIASING;
+ else
+ cacheid = CACHEID_VIPT_NONALIASING;
}
+ if (cpu_has_aliasing_icache(arch))
+ cacheid |= CACHEID_VIPT_I_ALIASING;
} else {
cacheid = CACHEID_VIVT;
}
diff --git a/arch/arm/kernel/sleep.S b/arch/arm/kernel/sleep.S
index dc902f2..020e99c 100644
--- a/arch/arm/kernel/sleep.S
+++ b/arch/arm/kernel/sleep.S
@@ -8,92 +8,61 @@
.text
/*
- * Save CPU state for a suspend
- * r1 = v:p offset
- * r2 = suspend function arg0
- * r3 = suspend function
+ * Save CPU state for a suspend. This saves the CPU general purpose
+ * registers, and allocates space on the kernel stack to save the CPU
+ * specific registers and some other data for resume.
+ * r0 = suspend function arg0
+ * r1 = suspend function
*/
ENTRY(__cpu_suspend)
stmfd sp!, {r4 - r11, lr}
#ifdef MULTI_CPU
ldr r10, =processor
- ldr r5, [r10, #CPU_SLEEP_SIZE] @ size of CPU sleep state
- ldr ip, [r10, #CPU_DO_RESUME] @ virtual resume function
+ ldr r4, [r10, #CPU_SLEEP_SIZE] @ size of CPU sleep state
#else
- ldr r5, =cpu_suspend_size
- ldr ip, =cpu_do_resume
+ ldr r4, =cpu_suspend_size
#endif
- mov r6, sp @ current virtual SP
- sub sp, sp, r5 @ allocate CPU state on stack
- mov r0, sp @ save pointer to CPU save block
- add ip, ip, r1 @ convert resume fn to phys
- stmfd sp!, {r1, r6, ip} @ save v:p, virt SP, phys resume fn
- ldr r5, =sleep_save_sp
- add r6, sp, r1 @ convert SP to phys
- stmfd sp!, {r2, r3} @ save suspend func arg and pointer
+ mov r5, sp @ current virtual SP
+ add r4, r4, #12 @ Space for pgd, virt sp, phys resume fn
+ sub sp, sp, r4 @ allocate CPU state on stack
+ stmfd sp!, {r0, r1} @ save suspend func arg and pointer
+ add r0, sp, #8 @ save pointer to save block
+ mov r1, r4 @ size of save block
+ mov r2, r5 @ virtual SP
+ ldr r3, =sleep_save_sp
#ifdef CONFIG_SMP
ALT_SMP(mrc p15, 0, lr, c0, c0, 5)
ALT_UP(mov lr, #0)
and lr, lr, #15
- str r6, [r5, lr, lsl #2] @ save phys SP
-#else
- str r6, [r5] @ save phys SP
+ add r3, r3, lr, lsl #2
#endif
-#ifdef MULTI_CPU
- mov lr, pc
- ldr pc, [r10, #CPU_DO_SUSPEND] @ save CPU state
-#else
- bl cpu_do_suspend
-#endif
-
- @ flush data cache
-#ifdef MULTI_CACHE
- ldr r10, =cpu_cache
- mov lr, pc
- ldr pc, [r10, #CACHE_FLUSH_KERN_ALL]
-#else
- bl __cpuc_flush_kern_all
-#endif
+ bl __cpu_suspend_save
adr lr, BSYM(cpu_suspend_abort)
ldmfd sp!, {r0, pc} @ call suspend fn
ENDPROC(__cpu_suspend)
.ltorg
cpu_suspend_abort:
- ldmia sp!, {r1 - r3} @ pop v:p, virt SP, phys resume fn
+ ldmia sp!, {r1 - r3} @ pop phys pgd, virt SP, phys resume fn
+ teq r0, #0
+ moveq r0, #1 @ force non-zero value
mov sp, r2
ldmfd sp!, {r4 - r11, pc}
ENDPROC(cpu_suspend_abort)
/*
* r0 = control register value
- * r1 = v:p offset (preserved by cpu_do_resume)
- * r2 = phys page table base
- * r3 = L1 section flags
*/
-ENTRY(cpu_resume_mmu)
- adr r4, cpu_resume_turn_mmu_on
- mov r4, r4, lsr #20
- orr r3, r3, r4, lsl #20
- ldr r5, [r2, r4, lsl #2] @ save old mapping
- str r3, [r2, r4, lsl #2] @ setup 1:1 mapping for mmu code
- sub r2, r2, r1
- ldr r3, =cpu_resume_after_mmu
- bic r1, r0, #CR_C @ ensure D-cache is disabled
- b cpu_resume_turn_mmu_on
-ENDPROC(cpu_resume_mmu)
- .ltorg
.align 5
-cpu_resume_turn_mmu_on:
- mcr p15, 0, r1, c1, c0, 0 @ turn on MMU, I-cache, etc
- mrc p15, 0, r1, c0, c0, 0 @ read id reg
- mov r1, r1
- mov r1, r1
+ENTRY(cpu_resume_mmu)
+ ldr r3, =cpu_resume_after_mmu
+ mcr p15, 0, r0, c1, c0, 0 @ turn on MMU, I-cache, etc
+ mrc p15, 0, r0, c0, c0, 0 @ read id reg
+ mov r0, r0
+ mov r0, r0
mov pc, r3 @ jump to virtual address
-ENDPROC(cpu_resume_turn_mmu_on)
+ENDPROC(cpu_resume_mmu)
cpu_resume_after_mmu:
- str r5, [r2, r4, lsl #2] @ restore old mapping
- mcr p15, 0, r0, c1, c0, 0 @ turn on D-cache
bl cpu_init @ restore the und/abt/irq banked regs
mov r0, #0 @ return zero on success
ldmfd sp!, {r4 - r11, pc}
@@ -119,7 +88,7 @@
ldr r0, sleep_save_sp @ stack phys addr
#endif
setmode PSR_I_BIT | PSR_F_BIT | SVC_MODE, r1 @ set SVC, irqs off
- @ load v:p, stack, resume fn
+ @ load phys pgd, stack, resume fn
ARM( ldmia r0!, {r1, sp, pc} )
THUMB( ldmia r0!, {r1, r2, r3} )
THUMB( mov sp, r2 )
diff --git a/arch/arm/kernel/smp_twd.c b/arch/arm/kernel/smp_twd.c
index 2c277d4..01c1862 100644
--- a/arch/arm/kernel/smp_twd.c
+++ b/arch/arm/kernel/smp_twd.c
@@ -137,8 +137,8 @@
clk->max_delta_ns = clockevent_delta2ns(0xffffffff, clk);
clk->min_delta_ns = clockevent_delta2ns(0xf, clk);
+ clockevents_register_device(clk);
+
/* Make sure our local interrupt controller has this enabled */
gic_enable_ppi(clk->irq);
-
- clockevents_register_device(clk);
}
diff --git a/arch/arm/kernel/suspend.c b/arch/arm/kernel/suspend.c
new file mode 100644
index 0000000..93a22d2
--- /dev/null
+++ b/arch/arm/kernel/suspend.c
@@ -0,0 +1,72 @@
+#include <linux/init.h>
+
+#include <asm/pgalloc.h>
+#include <asm/pgtable.h>
+#include <asm/memory.h>
+#include <asm/suspend.h>
+#include <asm/tlbflush.h>
+
+static pgd_t *suspend_pgd;
+
+extern int __cpu_suspend(unsigned long, int (*)(unsigned long));
+extern void cpu_resume_mmu(void);
+
+/*
+ * This is called by __cpu_suspend() to save the state, and do whatever
+ * flushing is required to ensure that when the CPU goes to sleep we have
+ * the necessary data available when the caches are not searched.
+ */
+void __cpu_suspend_save(u32 *ptr, u32 ptrsz, u32 sp, u32 *save_ptr)
+{
+ *save_ptr = virt_to_phys(ptr);
+
+ /* This must correspond to the LDM in cpu_resume() assembly */
+ *ptr++ = virt_to_phys(suspend_pgd);
+ *ptr++ = sp;
+ *ptr++ = virt_to_phys(cpu_do_resume);
+
+ cpu_do_suspend(ptr);
+
+ flush_cache_all();
+ outer_clean_range(*save_ptr, *save_ptr + ptrsz);
+ outer_clean_range(virt_to_phys(save_ptr),
+ virt_to_phys(save_ptr) + sizeof(*save_ptr));
+}
+
+/*
+ * Hide the first two arguments to __cpu_suspend - these are an implementation
+ * detail which platform code shouldn't have to know about.
+ */
+int cpu_suspend(unsigned long arg, int (*fn)(unsigned long))
+{
+ struct mm_struct *mm = current->active_mm;
+ int ret;
+
+ if (!suspend_pgd)
+ return -EINVAL;
+
+ /*
+ * Provide a temporary page table with an identity mapping for
+ * the MMU-enable code, required for resuming. On successful
+ * resume (indicated by a zero return code), we need to switch
+ * back to the correct page tables.
+ */
+ ret = __cpu_suspend(arg, fn);
+ if (ret == 0) {
+ cpu_switch_mm(mm->pgd, mm);
+ local_flush_tlb_all();
+ }
+
+ return ret;
+}
+
+static int __init cpu_suspend_init(void)
+{
+ suspend_pgd = pgd_alloc(&init_mm);
+ if (suspend_pgd) {
+ unsigned long addr = virt_to_phys(cpu_resume_mmu);
+ identity_mapping_add(suspend_pgd, addr, addr + SECTION_SIZE);
+ }
+ return suspend_pgd ? 0 : -ENOMEM;
+}
+core_initcall(cpu_suspend_init);
diff --git a/arch/arm/mach-at91/at91sam9261.c b/arch/arm/mach-at91/at91sam9261.c
index d522b47..6c8e3b5 100644
--- a/arch/arm/mach-at91/at91sam9261.c
+++ b/arch/arm/mach-at91/at91sam9261.c
@@ -157,7 +157,7 @@
CLKDEV_CON_DEV_ID("spi_clk", "atmel_spi.1", &spi1_clk),
CLKDEV_CON_DEV_ID("t0_clk", "atmel_tcb.0", &tc0_clk),
CLKDEV_CON_DEV_ID("t1_clk", "atmel_tcb.0", &tc1_clk),
- CLKDEV_CON_DEV_ID("t2_clk", "atmel_tcb.0", &tc1_clk),
+ CLKDEV_CON_DEV_ID("t2_clk", "atmel_tcb.0", &tc2_clk),
CLKDEV_CON_DEV_ID("pclk", "ssc.0", &ssc0_clk),
CLKDEV_CON_DEV_ID("pclk", "ssc.1", &ssc1_clk),
CLKDEV_CON_DEV_ID("pclk", "ssc.2", &ssc2_clk),
diff --git a/arch/arm/mach-cns3xxx/include/mach/entry-macro.S b/arch/arm/mach-cns3xxx/include/mach/entry-macro.S
index 6bd83ed..d87bfc3 100644
--- a/arch/arm/mach-cns3xxx/include/mach/entry-macro.S
+++ b/arch/arm/mach-cns3xxx/include/mach/entry-macro.S
@@ -8,7 +8,6 @@
* published by the Free Software Foundation.
*/
-#include <mach/hardware.h>
#include <asm/hardware/entry-macro-gic.S>
.macro disable_fiq
diff --git a/arch/arm/mach-cns3xxx/include/mach/system.h b/arch/arm/mach-cns3xxx/include/mach/system.h
index 58bb03a..4f16c9b 100644
--- a/arch/arm/mach-cns3xxx/include/mach/system.h
+++ b/arch/arm/mach-cns3xxx/include/mach/system.h
@@ -13,7 +13,6 @@
#include <linux/io.h>
#include <asm/proc-fns.h>
-#include <mach/hardware.h>
static inline void arch_idle(void)
{
diff --git a/arch/arm/mach-cns3xxx/include/mach/uncompress.h b/arch/arm/mach-cns3xxx/include/mach/uncompress.h
index de8ead9..a91b605 100644
--- a/arch/arm/mach-cns3xxx/include/mach/uncompress.h
+++ b/arch/arm/mach-cns3xxx/include/mach/uncompress.h
@@ -8,7 +8,6 @@
*/
#include <asm/mach-types.h>
-#include <mach/hardware.h>
#include <mach/cns3xxx.h>
#define AMBA_UART_DR(base) (*(volatile unsigned char *)((base) + 0x00))
diff --git a/arch/arm/mach-cns3xxx/pcie.c b/arch/arm/mach-cns3xxx/pcie.c
index 06fd25d..0f8fca4 100644
--- a/arch/arm/mach-cns3xxx/pcie.c
+++ b/arch/arm/mach-cns3xxx/pcie.c
@@ -49,7 +49,7 @@
return &cns3xxx_pcie[root->domain];
}
-static struct cns3xxx_pcie *pdev_to_cnspci(struct pci_dev *dev)
+static struct cns3xxx_pcie *pdev_to_cnspci(const struct pci_dev *dev)
{
return sysdata_to_cnspci(dev->sysdata);
}
diff --git a/arch/arm/mach-davinci/board-da850-evm.c b/arch/arm/mach-davinci/board-da850-evm.c
index 85a2c7e..6e41cb5 100644
--- a/arch/arm/mach-davinci/board-da850-evm.c
+++ b/arch/arm/mach-davinci/board-da850-evm.c
@@ -115,6 +115,32 @@
},
};
+#ifdef CONFIG_MTD
+static void da850_evm_m25p80_notify_add(struct mtd_info *mtd)
+{
+ char *mac_addr = davinci_soc_info.emac_pdata->mac_addr;
+ size_t retlen;
+
+ if (!strcmp(mtd->name, "MAC-Address")) {
+ mtd->read(mtd, 0, ETH_ALEN, &retlen, mac_addr);
+ if (retlen == ETH_ALEN)
+ pr_info("Read MAC addr from SPI Flash: %pM\n",
+ mac_addr);
+ }
+}
+
+static struct mtd_notifier da850evm_spi_notifier = {
+ .add = da850_evm_m25p80_notify_add,
+};
+
+static void da850_evm_setup_mac_addr(void)
+{
+ register_mtd_user(&da850evm_spi_notifier);
+}
+#else
+static void da850_evm_setup_mac_addr(void) { }
+#endif
+
static struct mtd_partition da850_evm_norflash_partition[] = {
{
.name = "bootloaders + env",
@@ -1244,6 +1270,8 @@
if (ret)
pr_warning("da850_evm_init: sata registration failed: %d\n",
ret);
+
+ da850_evm_setup_mac_addr();
}
#ifdef CONFIG_SERIAL_8250_CONSOLE
diff --git a/arch/arm/mach-davinci/include/mach/psc.h b/arch/arm/mach-davinci/include/mach/psc.h
index 47fd0bc..fa59c09 100644
--- a/arch/arm/mach-davinci/include/mach/psc.h
+++ b/arch/arm/mach-davinci/include/mach/psc.h
@@ -243,7 +243,7 @@
#define PSC_STATE_DISABLE 2
#define PSC_STATE_ENABLE 3
-#define MDSTAT_STATE_MASK 0x1f
+#define MDSTAT_STATE_MASK 0x3f
#define MDCTL_FORCE BIT(31)
#ifndef __ASSEMBLER__
diff --git a/arch/arm/mach-davinci/sleep.S b/arch/arm/mach-davinci/sleep.S
index 5740289..d4e9316 100644
--- a/arch/arm/mach-davinci/sleep.S
+++ b/arch/arm/mach-davinci/sleep.S
@@ -217,7 +217,11 @@
ENDPROC(davinci_ddr_psc_config)
CACHE_FLUSH:
- .word arm926_flush_kern_cache_all
+#ifdef CONFIG_CPU_V6
+ .word v6_flush_kern_cache_all
+#else
+ .word arm926_flush_kern_cache_all
+#endif
ENTRY(davinci_cpu_suspend_sz)
.word . - davinci_cpu_suspend
diff --git a/arch/arm/mach-ep93xx/include/mach/ts72xx.h b/arch/arm/mach-ep93xx/include/mach/ts72xx.h
index 0eabec6..f1397a1 100644
--- a/arch/arm/mach-ep93xx/include/mach/ts72xx.h
+++ b/arch/arm/mach-ep93xx/include/mach/ts72xx.h
@@ -6,7 +6,7 @@
* TS72xx memory map:
*
* virt phys size
- * febff000 22000000 4K model number register
+ * febff000 22000000 4K model number register (bits 0-2)
* febfe000 22400000 4K options register
* febfd000 22800000 4K options register #2
* febf9000 10800000 4K TS-5620 RTC index register
@@ -20,6 +20,9 @@
#define TS72XX_MODEL_TS7200 0x00
#define TS72XX_MODEL_TS7250 0x01
#define TS72XX_MODEL_TS7260 0x02
+#define TS72XX_MODEL_TS7300 0x03
+#define TS72XX_MODEL_TS7400 0x04
+#define TS72XX_MODEL_MASK 0x07
#define TS72XX_OPTIONS_PHYS_BASE 0x22400000
@@ -51,19 +54,34 @@
#ifndef __ASSEMBLY__
+static inline int ts72xx_model(void)
+{
+ return __raw_readb(TS72XX_MODEL_VIRT_BASE) & TS72XX_MODEL_MASK;
+}
+
static inline int board_is_ts7200(void)
{
- return __raw_readb(TS72XX_MODEL_VIRT_BASE) == TS72XX_MODEL_TS7200;
+ return ts72xx_model() == TS72XX_MODEL_TS7200;
}
static inline int board_is_ts7250(void)
{
- return __raw_readb(TS72XX_MODEL_VIRT_BASE) == TS72XX_MODEL_TS7250;
+ return ts72xx_model() == TS72XX_MODEL_TS7250;
}
static inline int board_is_ts7260(void)
{
- return __raw_readb(TS72XX_MODEL_VIRT_BASE) == TS72XX_MODEL_TS7260;
+ return ts72xx_model() == TS72XX_MODEL_TS7260;
+}
+
+static inline int board_is_ts7300(void)
+{
+ return ts72xx_model() == TS72XX_MODEL_TS7300;
+}
+
+static inline int board_is_ts7400(void)
+{
+ return ts72xx_model() == TS72XX_MODEL_TS7400;
}
static inline int is_max197_installed(void)
diff --git a/arch/arm/mach-exynos4/clock.c b/arch/arm/mach-exynos4/clock.c
index 851dea0..1561b03 100644
--- a/arch/arm/mach-exynos4/clock.c
+++ b/arch/arm/mach-exynos4/clock.c
@@ -520,7 +520,7 @@
.ctrlbit = (1 << 21),
}, {
.name = "ac97",
- .id = -1,
+ .devname = "samsung-ac97",
.enable = exynos4_clk_ip_peril_ctrl,
.ctrlbit = (1 << 27),
}, {
diff --git a/arch/arm/mach-exynos4/cpu.c b/arch/arm/mach-exynos4/cpu.c
index 2d8a40c..746d6fc 100644
--- a/arch/arm/mach-exynos4/cpu.c
+++ b/arch/arm/mach-exynos4/cpu.c
@@ -24,12 +24,13 @@
#include <plat/exynos4.h>
#include <plat/adc-core.h>
#include <plat/sdhci.h>
-#include <plat/devs.h>
#include <plat/fb-core.h>
#include <plat/fimc-core.h>
#include <plat/iic-core.h>
+#include <plat/reset.h>
#include <mach/regs-irq.h>
+#include <mach/regs-pmu.h>
extern int combiner_init(unsigned int combiner_nr, void __iomem *base,
unsigned int irq_start);
@@ -128,6 +129,11 @@
local_irq_enable();
}
+static void exynos4_sw_reset(void)
+{
+ __raw_writel(0x1, S5P_SWRESET);
+}
+
/*
* exynos4_map_io
*
@@ -241,5 +247,8 @@
/* set idle function */
pm_idle = exynos4_idle;
+ /* set sw_reset function */
+ s5p_reset_hook = exynos4_sw_reset;
+
return sysdev_register(&exynos4_sysdev);
}
diff --git a/arch/arm/mach-exynos4/include/mach/irqs.h b/arch/arm/mach-exynos4/include/mach/irqs.h
index 934d2a4..f8952f8 100644
--- a/arch/arm/mach-exynos4/include/mach/irqs.h
+++ b/arch/arm/mach-exynos4/include/mach/irqs.h
@@ -80,9 +80,8 @@
#define IRQ_HSMMC3 IRQ_SPI(76)
#define IRQ_DWMCI IRQ_SPI(77)
-#define IRQ_MIPICSI0 IRQ_SPI(78)
-
-#define IRQ_MIPICSI1 IRQ_SPI(80)
+#define IRQ_MIPI_CSIS0 IRQ_SPI(78)
+#define IRQ_MIPI_CSIS1 IRQ_SPI(80)
#define IRQ_ONENAND_AUDI IRQ_SPI(82)
#define IRQ_ROTATOR IRQ_SPI(83)
diff --git a/arch/arm/mach-exynos4/include/mach/regs-pmu.h b/arch/arm/mach-exynos4/include/mach/regs-pmu.h
index fa49bbb..cdf9b47 100644
--- a/arch/arm/mach-exynos4/include/mach/regs-pmu.h
+++ b/arch/arm/mach-exynos4/include/mach/regs-pmu.h
@@ -29,6 +29,8 @@
#define S5P_USE_STANDBY_WFE1 (1 << 25)
#define S5P_USE_MASK ((0x3 << 16) | (0x3 << 24))
+#define S5P_SWRESET S5P_PMUREG(0x0400)
+
#define S5P_WAKEUP_STAT S5P_PMUREG(0x0600)
#define S5P_EINT_WAKEUP_MASK S5P_PMUREG(0x0604)
#define S5P_WAKEUP_MASK S5P_PMUREG(0x0608)
diff --git a/arch/arm/mach-exynos4/irq-eint.c b/arch/arm/mach-exynos4/irq-eint.c
index 9d87d2a..badb8c6 100644
--- a/arch/arm/mach-exynos4/irq-eint.c
+++ b/arch/arm/mach-exynos4/irq-eint.c
@@ -23,6 +23,8 @@
#include <mach/regs-gpio.h>
+#include <asm/mach/irq.h>
+
static DEFINE_SPINLOCK(eint_lock);
static unsigned int eint0_15_data[16];
@@ -184,8 +186,11 @@
static void exynos4_irq_demux_eint16_31(unsigned int irq, struct irq_desc *desc)
{
+ struct irq_chip *chip = irq_get_chip(irq);
+ chained_irq_enter(chip, desc);
exynos4_irq_demux_eint(IRQ_EINT(16));
exynos4_irq_demux_eint(IRQ_EINT(24));
+ chained_irq_exit(chip, desc);
}
static void exynos4_irq_eint0_15(unsigned int irq, struct irq_desc *desc)
@@ -193,6 +198,7 @@
u32 *irq_data = irq_get_handler_data(irq);
struct irq_chip *chip = irq_get_chip(irq);
+ chained_irq_enter(chip, desc);
chip->irq_mask(&desc->irq_data);
if (chip->irq_ack)
@@ -201,6 +207,7 @@
generic_handle_irq(*irq_data);
chip->irq_unmask(&desc->irq_data);
+ chained_irq_exit(chip, desc);
}
int __init exynos4_init_irq_eint(void)
diff --git a/arch/arm/mach-exynos4/mach-universal_c210.c b/arch/arm/mach-exynos4/mach-universal_c210.c
index d7ec84d..2aac6f7 100644
--- a/arch/arm/mach-exynos4/mach-universal_c210.c
+++ b/arch/arm/mach-exynos4/mach-universal_c210.c
@@ -79,7 +79,7 @@
};
static struct regulator_consumer_supply max8952_consumer =
- REGULATOR_SUPPLY("vddarm", NULL);
+ REGULATOR_SUPPLY("vdd_arm", NULL);
static struct max8952_platform_data universal_max8952_pdata __initdata = {
.gpio_vid0 = EXYNOS4_GPX0(3),
@@ -105,7 +105,7 @@
};
static struct regulator_consumer_supply lp3974_buck1_consumer =
- REGULATOR_SUPPLY("vddint", NULL);
+ REGULATOR_SUPPLY("vdd_int", NULL);
static struct regulator_consumer_supply lp3974_buck2_consumer =
REGULATOR_SUPPLY("vddg3d", NULL);
diff --git a/arch/arm/mach-exynos4/setup-usb-phy.c b/arch/arm/mach-exynos4/setup-usb-phy.c
index 0883c1b..39aca04 100644
--- a/arch/arm/mach-exynos4/setup-usb-phy.c
+++ b/arch/arm/mach-exynos4/setup-usb-phy.c
@@ -82,7 +82,7 @@
rstcon &= ~(HOST_LINK_PORT_SWRST_MASK | PHY1_SWRST_MASK);
writel(rstcon, EXYNOS4_RSTCON);
- udelay(50);
+ udelay(80);
clk_disable(otg_clk);
clk_put(otg_clk);
diff --git a/arch/arm/mach-footbridge/Kconfig b/arch/arm/mach-footbridge/Kconfig
index dc26fff..c8e7afc 100644
--- a/arch/arm/mach-footbridge/Kconfig
+++ b/arch/arm/mach-footbridge/Kconfig
@@ -62,6 +62,7 @@
config ARCH_NETWINDER
bool "NetWinder"
select CLKSRC_I8253
+ select CLKEVT_I8253
select FOOTBRIDGE_HOST
select ISA
select ISA_DMA
diff --git a/arch/arm/mach-footbridge/dc21285.c b/arch/arm/mach-footbridge/dc21285.c
index 1331fff..18c32a5 100644
--- a/arch/arm/mach-footbridge/dc21285.c
+++ b/arch/arm/mach-footbridge/dc21285.c
@@ -18,6 +18,7 @@
#include <linux/irq.h>
#include <linux/io.h>
#include <linux/spinlock.h>
+#include <video/vga.h>
#include <asm/irq.h>
#include <asm/system.h>
diff --git a/arch/arm/mach-imx/mach-cpuimx27.c b/arch/arm/mach-imx/mach-cpuimx27.c
index 881add0..b1ec2cf 100644
--- a/arch/arm/mach-imx/mach-cpuimx27.c
+++ b/arch/arm/mach-imx/mach-cpuimx27.c
@@ -310,7 +310,7 @@
.init = eukrea_cpuimx27_timer_init,
};
-MACHINE_START(CPUIMX27, "EUKREA CPUIMX27")
+MACHINE_START(EUKREA_CPUIMX27, "EUKREA CPUIMX27")
.atag_offset = 0x100,
.map_io = mx27_map_io,
.init_early = imx27_init_early,
diff --git a/arch/arm/mach-imx/mach-cpuimx35.c b/arch/arm/mach-imx/mach-cpuimx35.c
index 10b8913..470b654 100644
--- a/arch/arm/mach-imx/mach-cpuimx35.c
+++ b/arch/arm/mach-imx/mach-cpuimx35.c
@@ -192,7 +192,7 @@
.init = eukrea_cpuimx35_timer_init,
};
-MACHINE_START(EUKREA_CPUIMX35, "Eukrea CPUIMX35")
+MACHINE_START(EUKREA_CPUIMX35SD, "Eukrea CPUIMX35")
/* Maintainer: Eukrea Electromatique */
.atag_offset = 0x100,
.map_io = mx35_map_io,
diff --git a/arch/arm/mach-imx/mach-eukrea_cpuimx25.c b/arch/arm/mach-imx/mach-eukrea_cpuimx25.c
index d8699b5..9163318 100644
--- a/arch/arm/mach-imx/mach-eukrea_cpuimx25.c
+++ b/arch/arm/mach-imx/mach-eukrea_cpuimx25.c
@@ -161,7 +161,7 @@
.init = eukrea_cpuimx25_timer_init,
};
-MACHINE_START(EUKREA_CPUIMX25, "Eukrea CPUIMX25")
+MACHINE_START(EUKREA_CPUIMX25SD, "Eukrea CPUIMX25")
/* Maintainer: Eukrea Electromatique */
.atag_offset = 0x100,
.map_io = mx25_map_io,
diff --git a/arch/arm/mach-integrator/integrator_ap.c b/arch/arm/mach-integrator/integrator_ap.c
index eaa95bd..b19ae18 100644
--- a/arch/arm/mach-integrator/integrator_ap.c
+++ b/arch/arm/mach-integrator/integrator_ap.c
@@ -337,15 +337,15 @@
static void integrator_clocksource_init(u32 khz)
{
void __iomem *base = (void __iomem *)TIMER2_VA_BASE;
- u32 ctrl = TIMER_CTRL_ENABLE;
+ u32 ctrl = TIMER_CTRL_ENABLE | TIMER_CTRL_PERIODIC;
if (khz >= 1500) {
khz /= 16;
- ctrl = TIMER_CTRL_DIV16;
+ ctrl |= TIMER_CTRL_DIV16;
}
- writel(ctrl, base + TIMER_CTRL);
writel(0xffff, base + TIMER_LOAD);
+ writel(ctrl, base + TIMER_CTRL);
clocksource_mmio_init(base + TIMER_VALUE, "timer2",
khz * 1000, 200, 16, clocksource_mmio_readl_down);
diff --git a/arch/arm/mach-omap2/clock3xxx_data.c b/arch/arm/mach-omap2/clock3xxx_data.c
index ffd55b1..b9b8446 100644
--- a/arch/arm/mach-omap2/clock3xxx_data.c
+++ b/arch/arm/mach-omap2/clock3xxx_data.c
@@ -3078,6 +3078,7 @@
.name = "gpt12_fck",
.ops = &clkops_null,
.parent = &secure_32k_fck,
+ .clkdm_name = "wkup_clkdm",
.recalc = &followparent_recalc,
};
@@ -3085,6 +3086,7 @@
.name = "wdt1_fck",
.ops = &clkops_null,
.parent = &secure_32k_fck,
+ .clkdm_name = "wkup_clkdm",
.recalc = &followparent_recalc,
};
diff --git a/arch/arm/mach-omap2/clock44xx_data.c b/arch/arm/mach-omap2/clock44xx_data.c
index 2af0e3f0..c0b6fbd 100644
--- a/arch/arm/mach-omap2/clock44xx_data.c
+++ b/arch/arm/mach-omap2/clock44xx_data.c
@@ -3376,10 +3376,18 @@
} else if (cpu_is_omap446x()) {
cpu_mask = RATE_IN_4460;
cpu_clkflg = CK_446X;
+ } else {
+ return 0;
}
clk_init(&omap2_clk_functions);
- omap2_clk_disable_clkdm_control();
+
+ /*
+ * Must stay commented until all OMAP SoC drivers are
+ * converted to runtime PM, or drivers may start crashing
+ *
+ * omap2_clk_disable_clkdm_control();
+ */
for (c = omap44xx_clks; c < omap44xx_clks + ARRAY_SIZE(omap44xx_clks);
c++)
diff --git a/arch/arm/mach-omap2/clockdomain.c b/arch/arm/mach-omap2/clockdomain.c
index ab7db08..8f08906 100644
--- a/arch/arm/mach-omap2/clockdomain.c
+++ b/arch/arm/mach-omap2/clockdomain.c
@@ -747,6 +747,7 @@
spin_lock_irqsave(&clkdm->lock, flags);
clkdm->_flags &= ~_CLKDM_FLAG_HWSUP_ENABLED;
ret = arch_clkdm->clkdm_wakeup(clkdm);
+ ret |= pwrdm_state_switch(clkdm->pwrdm.ptr);
spin_unlock_irqrestore(&clkdm->lock, flags);
return ret;
}
@@ -818,6 +819,7 @@
spin_lock_irqsave(&clkdm->lock, flags);
clkdm->_flags &= ~_CLKDM_FLAG_HWSUP_ENABLED;
arch_clkdm->clkdm_deny_idle(clkdm);
+ pwrdm_state_switch(clkdm->pwrdm.ptr);
spin_unlock_irqrestore(&clkdm->lock, flags);
}
diff --git a/arch/arm/mach-omap2/omap_hwmod_2430_data.c b/arch/arm/mach-omap2/omap_hwmod_2430_data.c
index 16743c7..408193d 100644
--- a/arch/arm/mach-omap2/omap_hwmod_2430_data.c
+++ b/arch/arm/mach-omap2/omap_hwmod_2430_data.c
@@ -192,6 +192,7 @@
.pa_end = OMAP243X_HS_BASE + SZ_4K - 1,
.flags = ADDR_TYPE_RT
},
+ { }
};
/* l4_core ->usbhsotg interface */
diff --git a/arch/arm/mach-omap2/pm.c b/arch/arm/mach-omap2/pm.c
index 3feb359..472bf22 100644
--- a/arch/arm/mach-omap2/pm.c
+++ b/arch/arm/mach-omap2/pm.c
@@ -130,7 +130,6 @@
} else {
hwsup = clkdm_in_hwsup(pwrdm->pwrdm_clkdms[0]);
clkdm_wakeup(pwrdm->pwrdm_clkdms[0]);
- pwrdm_wait_transition(pwrdm);
sleep_switch = FORCEWAKEUP_SWITCH;
}
}
@@ -156,7 +155,6 @@
return ret;
}
- pwrdm_wait_transition(pwrdm);
pwrdm_state_switch(pwrdm);
err:
return ret;
diff --git a/arch/arm/mach-omap2/powerdomain.c b/arch/arm/mach-omap2/powerdomain.c
index 9af0847..ef71fdd 100644
--- a/arch/arm/mach-omap2/powerdomain.c
+++ b/arch/arm/mach-omap2/powerdomain.c
@@ -195,28 +195,35 @@
/**
* pwrdm_init - set up the powerdomain layer
- * @pwrdm_list: array of struct powerdomain pointers to register
+ * @pwrdms: array of struct powerdomain pointers to register
* @custom_funcs: func pointers for arch specific implementations
*
- * Loop through the array of powerdomains @pwrdm_list, registering all
- * that are available on the current CPU. If pwrdm_list is supplied
- * and not null, all of the referenced powerdomains will be
- * registered. No return value. XXX pwrdm_list is not really a
- * "list"; it is an array. Rename appropriately.
+ * Loop through the array of powerdomains @pwrdms, registering all
+ * that are available on the current CPU. Also, program all
+ * powerdomain target state as ON; this is to prevent domains from
+ * hitting low power states (if bootloader has target states set to
+ * something other than ON) and potentially even losing context while
+ * PM is not fully initialized. The PM late init code can then program
+ * the desired target state for all the power domains. No return
+ * value.
*/
-void pwrdm_init(struct powerdomain **pwrdm_list, struct pwrdm_ops *custom_funcs)
+void pwrdm_init(struct powerdomain **pwrdms, struct pwrdm_ops *custom_funcs)
{
struct powerdomain **p = NULL;
+ struct powerdomain *temp_p;
if (!custom_funcs)
WARN(1, "powerdomain: No custom pwrdm functions registered\n");
else
arch_pwrdm = custom_funcs;
- if (pwrdm_list) {
- for (p = pwrdm_list; *p; p++)
+ if (pwrdms) {
+ for (p = pwrdms; *p; p++)
_pwrdm_register(*p);
}
+
+ list_for_each_entry(temp_p, &pwrdm_list, node)
+ pwrdm_set_next_pwrst(temp_p, PWRDM_POWER_ON);
}
/**
diff --git a/arch/arm/mach-orion5x/dns323-setup.c b/arch/arm/mach-orion5x/dns323-setup.c
index e25f60f..9e5c166 100644
--- a/arch/arm/mach-orion5x/dns323-setup.c
+++ b/arch/arm/mach-orion5x/dns323-setup.c
@@ -77,7 +77,7 @@
/*
* Check for devices with hard-wired IRQs.
*/
- irq = orion5x_pci_map_irq(const dev, slot, pin);
+ irq = orion5x_pci_map_irq(dev, slot, pin);
if (irq != -1)
return irq;
diff --git a/arch/arm/mach-orion5x/pci.c b/arch/arm/mach-orion5x/pci.c
index 28b8760..bc4a920 100644
--- a/arch/arm/mach-orion5x/pci.c
+++ b/arch/arm/mach-orion5x/pci.c
@@ -14,6 +14,7 @@
#include <linux/pci.h>
#include <linux/slab.h>
#include <linux/mbus.h>
+#include <video/vga.h>
#include <asm/irq.h>
#include <asm/mach/pci.h>
#include <plat/pcie.h>
diff --git a/arch/arm/mach-prima2/clock.c b/arch/arm/mach-prima2/clock.c
index f9a2aaf..615a4e7 100644
--- a/arch/arm/mach-prima2/clock.c
+++ b/arch/arm/mach-prima2/clock.c
@@ -481,6 +481,7 @@
static struct of_device_id clkc_ids[] = {
{ .compatible = "sirf,prima2-clkc" },
+ {},
};
void __init sirfsoc_of_clk_init(void)
diff --git a/arch/arm/mach-prima2/irq.c b/arch/arm/mach-prima2/irq.c
index c3404cb..7af254d 100644
--- a/arch/arm/mach-prima2/irq.c
+++ b/arch/arm/mach-prima2/irq.c
@@ -51,6 +51,7 @@
static struct of_device_id intc_ids[] = {
{ .compatible = "sirf,prima2-intc" },
+ {},
};
void __init sirfsoc_of_irq_init(void)
diff --git a/arch/arm/mach-prima2/rstc.c b/arch/arm/mach-prima2/rstc.c
index d074786..492cfa8 100644
--- a/arch/arm/mach-prima2/rstc.c
+++ b/arch/arm/mach-prima2/rstc.c
@@ -19,6 +19,7 @@
static struct of_device_id rstc_ids[] = {
{ .compatible = "sirf,prima2-rstc" },
+ {},
};
static int __init sirfsoc_of_rstc_init(void)
diff --git a/arch/arm/mach-prima2/timer.c b/arch/arm/mach-prima2/timer.c
index 44027f3..ed7ec48 100644
--- a/arch/arm/mach-prima2/timer.c
+++ b/arch/arm/mach-prima2/timer.c
@@ -190,6 +190,7 @@
static struct of_device_id timer_ids[] = {
{ .compatible = "sirf,prima2-tick" },
+ {},
};
static void __init sirfsoc_of_timer_map(void)
diff --git a/arch/arm/mach-realview/include/mach/system.h b/arch/arm/mach-realview/include/mach/system.h
index a30f2e3..6657ff23 100644
--- a/arch/arm/mach-realview/include/mach/system.h
+++ b/arch/arm/mach-realview/include/mach/system.h
@@ -44,6 +44,7 @@
*/
if (realview_reset)
realview_reset(mode);
+ dsb();
}
#endif
diff --git a/arch/arm/mach-s3c64xx/pm.c b/arch/arm/mach-s3c64xx/pm.c
index 8bad643..055e285 100644
--- a/arch/arm/mach-s3c64xx/pm.c
+++ b/arch/arm/mach-s3c64xx/pm.c
@@ -16,6 +16,7 @@
#include <linux/suspend.h>
#include <linux/serial_core.h>
#include <linux/io.h>
+#include <linux/gpio.h>
#include <mach/map.h>
#include <mach/irqs.h>
diff --git a/arch/arm/mach-s5p64x0/irq-eint.c b/arch/arm/mach-s5p64x0/irq-eint.c
index 69ed454..fe7380f 100644
--- a/arch/arm/mach-s5p64x0/irq-eint.c
+++ b/arch/arm/mach-s5p64x0/irq-eint.c
@@ -129,7 +129,7 @@
}
ct = gc->chip_types;
- ct->chip.irq_ack = irq_gc_ack;
+ ct->chip.irq_ack = irq_gc_ack_set_bit;
ct->chip.irq_mask = irq_gc_mask_set_bit;
ct->chip.irq_unmask = irq_gc_mask_clr_bit;
ct->chip.irq_set_type = s5p64x0_irq_eint_set_type;
diff --git a/arch/arm/mach-s5pv210/pm.c b/arch/arm/mach-s5pv210/pm.c
index 309e388..f149d27 100644
--- a/arch/arm/mach-s5pv210/pm.c
+++ b/arch/arm/mach-s5pv210/pm.c
@@ -88,7 +88,7 @@
SAVE_ITEM(S3C2410_TCNTO(0)),
};
-void s5pv210_cpu_suspend(unsigned long arg)
+static int s5pv210_cpu_suspend(unsigned long arg)
{
unsigned long tmp;
diff --git a/arch/arm/mach-shmobile/board-ag5evm.c b/arch/arm/mach-shmobile/board-ag5evm.c
index 167a67c..5fde49d 100644
--- a/arch/arm/mach-shmobile/board-ag5evm.c
+++ b/arch/arm/mach-shmobile/board-ag5evm.c
@@ -342,6 +342,7 @@
static struct sh_mobile_sdhi_info sdhi0_info = {
.dma_slave_tx = SHDMA_SLAVE_SDHI0_TX,
.dma_slave_rx = SHDMA_SLAVE_SDHI0_RX,
+ .tmio_flags = TMIO_MMC_HAS_IDLE_WAIT,
.tmio_caps = MMC_CAP_SD_HIGHSPEED,
.tmio_ocr_mask = MMC_VDD_27_28 | MMC_VDD_28_29,
};
@@ -383,7 +384,7 @@
}
static struct sh_mobile_sdhi_info sh_sdhi1_info = {
- .tmio_flags = TMIO_MMC_WRPROTECT_DISABLE,
+ .tmio_flags = TMIO_MMC_WRPROTECT_DISABLE | TMIO_MMC_HAS_IDLE_WAIT,
.tmio_caps = MMC_CAP_NONREMOVABLE | MMC_CAP_SDIO_IRQ,
.tmio_ocr_mask = MMC_VDD_32_33 | MMC_VDD_33_34,
.set_pwr = ag5evm_sdhi1_set_pwr,
diff --git a/arch/arm/mach-shmobile/board-ap4evb.c b/arch/arm/mach-shmobile/board-ap4evb.c
index ec8f9d9..b622d8d 100644
--- a/arch/arm/mach-shmobile/board-ap4evb.c
+++ b/arch/arm/mach-shmobile/board-ap4evb.c
@@ -1415,6 +1415,7 @@
fsi_init_pm_clock();
sh7372_pm_init();
pm_clk_add(&fsi_device.dev, "spu2");
+ pm_clk_add(&lcdc1_device.dev, "hdmi");
}
static void __init ap4evb_timer_init(void)
diff --git a/arch/arm/mach-shmobile/board-mackerel.c b/arch/arm/mach-shmobile/board-mackerel.c
index 671925d..de2253d 100644
--- a/arch/arm/mach-shmobile/board-mackerel.c
+++ b/arch/arm/mach-shmobile/board-mackerel.c
@@ -642,6 +642,8 @@
},
.driver_param = {
.buswait_bwait = 4,
+ .d0_tx_id = SHDMA_SLAVE_USB0_TX,
+ .d1_rx_id = SHDMA_SLAVE_USB0_RX,
},
},
};
@@ -811,6 +813,8 @@
.buswait_bwait = 4,
.pipe_type = usbhs1_pipe_cfg,
.pipe_size = ARRAY_SIZE(usbhs1_pipe_cfg),
+ .d0_tx_id = SHDMA_SLAVE_USB1_TX,
+ .d1_rx_id = SHDMA_SLAVE_USB1_RX,
},
},
};
@@ -1591,6 +1595,7 @@
hdmi_init_pm_clock();
sh7372_pm_init();
pm_clk_add(&fsi_device.dev, "spu2");
+ pm_clk_add(&hdmi_lcdc_device.dev, "hdmi");
}
static void __init mackerel_timer_init(void)
diff --git a/arch/arm/mach-shmobile/clock-sh7372.c b/arch/arm/mach-shmobile/clock-sh7372.c
index 6b1619a..6697592 100644
--- a/arch/arm/mach-shmobile/clock-sh7372.c
+++ b/arch/arm/mach-shmobile/clock-sh7372.c
@@ -503,16 +503,17 @@
&sh7372_fsidivb_clk,
};
-enum { MSTP001,
+enum { MSTP001, MSTP000,
MSTP131, MSTP130,
MSTP129, MSTP128, MSTP127, MSTP126, MSTP125,
MSTP118, MSTP117, MSTP116, MSTP113,
MSTP106, MSTP101, MSTP100,
MSTP223,
- MSTP218, MSTP217, MSTP216,
- MSTP207, MSTP206, MSTP204, MSTP203, MSTP202, MSTP201, MSTP200,
- MSTP329, MSTP328, MSTP323, MSTP322, MSTP314, MSTP313, MSTP312,
- MSTP423, MSTP415, MSTP413, MSTP411, MSTP410, MSTP406, MSTP403,
+ MSTP218, MSTP217, MSTP216, MSTP214, MSTP208, MSTP207,
+ MSTP206, MSTP205, MSTP204, MSTP203, MSTP202, MSTP201, MSTP200,
+ MSTP328, MSTP323, MSTP322, MSTP314, MSTP313, MSTP312,
+ MSTP423, MSTP415, MSTP413, MSTP411, MSTP410, MSTP407, MSTP406,
+ MSTP405, MSTP404, MSTP403, MSTP400,
MSTP_NR };
#define MSTP(_parent, _reg, _bit, _flags) \
@@ -520,6 +521,7 @@
static struct clk mstp_clks[MSTP_NR] = {
[MSTP001] = MSTP(&div6_clks[DIV6_SUB], SMSTPCR0, 1, 0), /* IIC2 */
+ [MSTP000] = MSTP(&div6_clks[DIV6_SUB], SMSTPCR0, 0, 0), /* MSIOF0 */
[MSTP131] = MSTP(&div4_clks[DIV4_B], SMSTPCR1, 31, 0), /* VEU3 */
[MSTP130] = MSTP(&div4_clks[DIV4_B], SMSTPCR1, 30, 0), /* VEU2 */
[MSTP129] = MSTP(&div4_clks[DIV4_B], SMSTPCR1, 29, 0), /* VEU1 */
@@ -538,14 +540,16 @@
[MSTP218] = MSTP(&div4_clks[DIV4_HP], SMSTPCR2, 18, 0), /* DMAC1 */
[MSTP217] = MSTP(&div4_clks[DIV4_HP], SMSTPCR2, 17, 0), /* DMAC2 */
[MSTP216] = MSTP(&div4_clks[DIV4_HP], SMSTPCR2, 16, 0), /* DMAC3 */
+ [MSTP214] = MSTP(&div4_clks[DIV4_HP], SMSTPCR2, 14, 0), /* USBDMAC */
+ [MSTP208] = MSTP(&div6_clks[DIV6_SUB], SMSTPCR2, 8, 0), /* MSIOF1 */
[MSTP207] = MSTP(&div6_clks[DIV6_SUB], SMSTPCR2, 7, 0), /* SCIFA5 */
[MSTP206] = MSTP(&div6_clks[DIV6_SUB], SMSTPCR2, 6, 0), /* SCIFB */
+ [MSTP205] = MSTP(&div6_clks[DIV6_SUB], SMSTPCR2, 5, 0), /* MSIOF2 */
[MSTP204] = MSTP(&div6_clks[DIV6_SUB], SMSTPCR2, 4, 0), /* SCIFA0 */
[MSTP203] = MSTP(&div6_clks[DIV6_SUB], SMSTPCR2, 3, 0), /* SCIFA1 */
[MSTP202] = MSTP(&div6_clks[DIV6_SUB], SMSTPCR2, 2, 0), /* SCIFA2 */
[MSTP201] = MSTP(&div6_clks[DIV6_SUB], SMSTPCR2, 1, 0), /* SCIFA3 */
[MSTP200] = MSTP(&div6_clks[DIV6_SUB], SMSTPCR2, 0, 0), /* SCIFA4 */
- [MSTP329] = MSTP(&r_clk, SMSTPCR3, 29, 0), /* CMT10 */
[MSTP328] = MSTP(&div6_clks[DIV6_SPU], SMSTPCR3, 28, 0), /* FSI2 */
[MSTP323] = MSTP(&div6_clks[DIV6_SUB], SMSTPCR3, 23, 0), /* IIC1 */
[MSTP322] = MSTP(&div6_clks[DIV6_SUB], SMSTPCR3, 22, 0), /* USB0 */
@@ -557,8 +561,12 @@
[MSTP413] = MSTP(&pllc1_div2_clk, SMSTPCR4, 13, 0), /* HDMI */
[MSTP411] = MSTP(&div6_clks[DIV6_SUB], SMSTPCR4, 11, 0), /* IIC3 */
[MSTP410] = MSTP(&div6_clks[DIV6_SUB], SMSTPCR4, 10, 0), /* IIC4 */
+ [MSTP407] = MSTP(&div4_clks[DIV4_HP], SMSTPCR4, 7, 0), /* USB-DMAC1 */
[MSTP406] = MSTP(&div6_clks[DIV6_SUB], SMSTPCR4, 6, 0), /* USB1 */
+ [MSTP405] = MSTP(&r_clk, SMSTPCR4, 5, 0), /* CMT4 */
+ [MSTP404] = MSTP(&r_clk, SMSTPCR4, 4, 0), /* CMT3 */
[MSTP403] = MSTP(&r_clk, SMSTPCR4, 3, 0), /* KEYSC */
+ [MSTP400] = MSTP(&r_clk, SMSTPCR4, 0, 0), /* CMT2 */
};
static struct clk_lookup lookups[] = {
@@ -609,6 +617,7 @@
/* MSTP32 clocks */
CLKDEV_DEV_ID("i2c-sh_mobile.2", &mstp_clks[MSTP001]), /* IIC2 */
+ CLKDEV_DEV_ID("spi_sh_msiof.0", &mstp_clks[MSTP000]), /* MSIOF0 */
CLKDEV_DEV_ID("uio_pdrv_genirq.4", &mstp_clks[MSTP131]), /* VEU3 */
CLKDEV_DEV_ID("uio_pdrv_genirq.3", &mstp_clks[MSTP130]), /* VEU2 */
CLKDEV_DEV_ID("uio_pdrv_genirq.2", &mstp_clks[MSTP129]), /* VEU1 */
@@ -629,14 +638,16 @@
CLKDEV_DEV_ID("sh-dma-engine.0", &mstp_clks[MSTP218]), /* DMAC1 */
CLKDEV_DEV_ID("sh-dma-engine.1", &mstp_clks[MSTP217]), /* DMAC2 */
CLKDEV_DEV_ID("sh-dma-engine.2", &mstp_clks[MSTP216]), /* DMAC3 */
+ CLKDEV_DEV_ID("sh-dma-engine.3", &mstp_clks[MSTP214]), /* USB-DMAC0 */
+ CLKDEV_DEV_ID("spi_sh_msiof.1", &mstp_clks[MSTP208]), /* MSIOF1 */
CLKDEV_DEV_ID("sh-sci.5", &mstp_clks[MSTP207]), /* SCIFA5 */
CLKDEV_DEV_ID("sh-sci.6", &mstp_clks[MSTP206]), /* SCIFB */
+ CLKDEV_DEV_ID("spi_sh_msiof.2", &mstp_clks[MSTP205]), /* MSIOF2 */
CLKDEV_DEV_ID("sh-sci.0", &mstp_clks[MSTP204]), /* SCIFA0 */
CLKDEV_DEV_ID("sh-sci.1", &mstp_clks[MSTP203]), /* SCIFA1 */
CLKDEV_DEV_ID("sh-sci.2", &mstp_clks[MSTP202]), /* SCIFA2 */
CLKDEV_DEV_ID("sh-sci.3", &mstp_clks[MSTP201]), /* SCIFA3 */
CLKDEV_DEV_ID("sh-sci.4", &mstp_clks[MSTP200]), /* SCIFA4 */
- CLKDEV_DEV_ID("sh_cmt.10", &mstp_clks[MSTP329]), /* CMT10 */
CLKDEV_DEV_ID("sh_fsi2", &mstp_clks[MSTP328]), /* FSI2 */
CLKDEV_DEV_ID("i2c-sh_mobile.1", &mstp_clks[MSTP323]), /* IIC1 */
CLKDEV_DEV_ID("r8a66597_hcd.0", &mstp_clks[MSTP322]), /* USB0 */
@@ -650,11 +661,17 @@
CLKDEV_DEV_ID("sh-mobile-hdmi", &mstp_clks[MSTP413]), /* HDMI */
CLKDEV_DEV_ID("i2c-sh_mobile.3", &mstp_clks[MSTP411]), /* IIC3 */
CLKDEV_DEV_ID("i2c-sh_mobile.4", &mstp_clks[MSTP410]), /* IIC4 */
+ CLKDEV_DEV_ID("sh-dma-engine.4", &mstp_clks[MSTP407]), /* USB-DMAC1 */
CLKDEV_DEV_ID("r8a66597_hcd.1", &mstp_clks[MSTP406]), /* USB1 */
CLKDEV_DEV_ID("r8a66597_udc.1", &mstp_clks[MSTP406]), /* USB1 */
CLKDEV_DEV_ID("renesas_usbhs.1", &mstp_clks[MSTP406]), /* USB1 */
+ CLKDEV_DEV_ID("sh_cmt.4", &mstp_clks[MSTP405]), /* CMT4 */
+ CLKDEV_DEV_ID("sh_cmt.3", &mstp_clks[MSTP404]), /* CMT3 */
CLKDEV_DEV_ID("sh_keysc.0", &mstp_clks[MSTP403]), /* KEYSC */
+ CLKDEV_DEV_ID("sh_cmt.2", &mstp_clks[MSTP400]), /* CMT2 */
+ CLKDEV_ICK_ID("hdmi", "sh_mobile_lcdc_fb.1",
+ &div6_reparent_clks[DIV6_HDMI]),
CLKDEV_ICK_ID("ick", "sh-mobile-hdmi", &div6_reparent_clks[DIV6_HDMI]),
CLKDEV_ICK_ID("icka", "sh_fsi2", &div6_reparent_clks[DIV6_FSIA]),
CLKDEV_ICK_ID("ickb", "sh_fsi2", &div6_reparent_clks[DIV6_FSIB]),
diff --git a/arch/arm/mach-shmobile/clock-sh73a0.c b/arch/arm/mach-shmobile/clock-sh73a0.c
index 6db2cca..61a846b 100644
--- a/arch/arm/mach-shmobile/clock-sh73a0.c
+++ b/arch/arm/mach-shmobile/clock-sh73a0.c
@@ -365,7 +365,7 @@
__raw_writel(0x108, SD2CKCR);
/* detect main clock parent */
- switch ((__raw_readl(CKSCR) >> 24) & 0x03) {
+ switch ((__raw_readl(CKSCR) >> 28) & 0x03) {
case 0:
main_clk.parent = &sh73a0_extal1_clk;
break;
diff --git a/arch/arm/mach-shmobile/include/mach/sh7372.h b/arch/arm/mach-shmobile/include/mach/sh7372.h
index ce595ce..24e63a8 100644
--- a/arch/arm/mach-shmobile/include/mach/sh7372.h
+++ b/arch/arm/mach-shmobile/include/mach/sh7372.h
@@ -459,6 +459,10 @@
SHDMA_SLAVE_SDHI2_TX,
SHDMA_SLAVE_MMCIF_RX,
SHDMA_SLAVE_MMCIF_TX,
+ SHDMA_SLAVE_USB0_TX,
+ SHDMA_SLAVE_USB0_RX,
+ SHDMA_SLAVE_USB1_TX,
+ SHDMA_SLAVE_USB1_RX,
};
extern struct clk sh7372_extal1_clk;
diff --git a/arch/arm/mach-shmobile/intc-sh7372.c b/arch/arm/mach-shmobile/intc-sh7372.c
index 3b28743..739315e3 100644
--- a/arch/arm/mach-shmobile/intc-sh7372.c
+++ b/arch/arm/mach-shmobile/intc-sh7372.c
@@ -379,7 +379,7 @@
/* BBIF2 */
VPU,
TSIF1,
- _3DG_SGX530,
+ /* 3DG */
_2DDMAC,
IIC2_ALI2, IIC2_TACKI2, IIC2_WAITI2, IIC2_DTEI2,
IPMMU_IPMMUR, IPMMU_IPMMUR2,
@@ -436,7 +436,7 @@
/* BBIF2 */
INTCS_VECT(VPU, 0x980),
INTCS_VECT(TSIF1, 0x9a0),
- INTCS_VECT(_3DG_SGX530, 0x9e0),
+ /* 3DG */
INTCS_VECT(_2DDMAC, 0xa00),
INTCS_VECT(IIC2_ALI2, 0xa80), INTCS_VECT(IIC2_TACKI2, 0xaa0),
INTCS_VECT(IIC2_WAITI2, 0xac0), INTCS_VECT(IIC2_DTEI2, 0xae0),
@@ -521,7 +521,7 @@
RTDMAC_1_DEI3, RTDMAC_1_DEI2, RTDMAC_1_DEI1, RTDMAC_1_DEI0 } },
{ 0xffd20198, 0xffd201d8, 8, /* IMR6SA / IMCR6SA */
{ 0, 0, MSIOF, 0,
- _3DG_SGX530, 0, 0, 0 } },
+ 0, 0, 0, 0 } },
{ 0xffd2019c, 0xffd201dc, 8, /* IMR7SA / IMCR7SA */
{ 0, TMU_TUNI2, TMU_TUNI1, TMU_TUNI0,
0, 0, 0, 0 } },
@@ -561,7 +561,6 @@
TMU_TUNI2, TSIF1 } },
{ 0xffd2001c, 0, 16, 4, /* IPRHS */ { 0, 0, VEU, BEU } },
{ 0xffd20020, 0, 16, 4, /* IPRIS */ { 0, MSIOF, TSIF0, IIC0 } },
- { 0xffd20024, 0, 16, 4, /* IPRJS */ { 0, _3DG_SGX530, 0, 0 } },
{ 0xffd20028, 0, 16, 4, /* IPRKS */ { 0, 0, LMB, 0 } },
{ 0xffd2002c, 0, 16, 4, /* IPRLS */ { IPMMU, 0, 0, 0 } },
{ 0xffd20030, 0, 16, 4, /* IPRMS */ { IIC2, 0, 0, 0 } },
diff --git a/arch/arm/mach-shmobile/setup-sh7372.c b/arch/arm/mach-shmobile/setup-sh7372.c
index 79f0413..2d9b1b1 100644
--- a/arch/arm/mach-shmobile/setup-sh7372.c
+++ b/arch/arm/mach-shmobile/setup-sh7372.c
@@ -169,35 +169,35 @@
};
/* CMT */
-static struct sh_timer_config cmt10_platform_data = {
- .name = "CMT10",
- .channel_offset = 0x10,
- .timer_bit = 0,
+static struct sh_timer_config cmt2_platform_data = {
+ .name = "CMT2",
+ .channel_offset = 0x40,
+ .timer_bit = 5,
.clockevent_rating = 125,
.clocksource_rating = 125,
};
-static struct resource cmt10_resources[] = {
+static struct resource cmt2_resources[] = {
[0] = {
- .name = "CMT10",
- .start = 0xe6138010,
- .end = 0xe613801b,
+ .name = "CMT2",
+ .start = 0xe6130040,
+ .end = 0xe613004b,
.flags = IORESOURCE_MEM,
},
[1] = {
- .start = evt2irq(0x0b00), /* CMT1_CMT10 */
+ .start = evt2irq(0x0b80), /* CMT2 */
.flags = IORESOURCE_IRQ,
},
};
-static struct platform_device cmt10_device = {
+static struct platform_device cmt2_device = {
.name = "sh_cmt",
- .id = 10,
+ .id = 2,
.dev = {
- .platform_data = &cmt10_platform_data,
+ .platform_data = &cmt2_platform_data,
},
- .resource = cmt10_resources,
- .num_resources = ARRAY_SIZE(cmt10_resources),
+ .resource = cmt2_resources,
+ .num_resources = ARRAY_SIZE(cmt2_resources),
};
/* TMU */
@@ -602,6 +602,150 @@
},
};
+/*
+ * USB-DMAC
+ */
+
+unsigned int usbts_shift[] = {3, 4, 5};
+
+enum {
+ XMIT_SZ_8BYTE = 0,
+ XMIT_SZ_16BYTE = 1,
+ XMIT_SZ_32BYTE = 2,
+};
+
+#define USBTS_INDEX2VAL(i) (((i) & 3) << 6)
+
+static const struct sh_dmae_channel sh7372_usb_dmae_channels[] = {
+ {
+ .offset = 0,
+ }, {
+ .offset = 0x20,
+ },
+};
+
+/* USB DMAC0 */
+static const struct sh_dmae_slave_config sh7372_usb_dmae0_slaves[] = {
+ {
+ .slave_id = SHDMA_SLAVE_USB0_TX,
+ .chcr = USBTS_INDEX2VAL(XMIT_SZ_8BYTE),
+ }, {
+ .slave_id = SHDMA_SLAVE_USB0_RX,
+ .chcr = USBTS_INDEX2VAL(XMIT_SZ_8BYTE),
+ },
+};
+
+static struct sh_dmae_pdata usb_dma0_platform_data = {
+ .slave = sh7372_usb_dmae0_slaves,
+ .slave_num = ARRAY_SIZE(sh7372_usb_dmae0_slaves),
+ .channel = sh7372_usb_dmae_channels,
+ .channel_num = ARRAY_SIZE(sh7372_usb_dmae_channels),
+ .ts_low_shift = 6,
+ .ts_low_mask = 0xc0,
+ .ts_high_shift = 0,
+ .ts_high_mask = 0,
+ .ts_shift = usbts_shift,
+ .ts_shift_num = ARRAY_SIZE(usbts_shift),
+ .dmaor_init = DMAOR_DME,
+ .chcr_offset = 0x14,
+ .chcr_ie_bit = 1 << 5,
+ .dmaor_is_32bit = 1,
+ .needs_tend_set = 1,
+ .no_dmars = 1,
+};
+
+static struct resource sh7372_usb_dmae0_resources[] = {
+ {
+ /* Channel registers and DMAOR */
+ .start = 0xe68a0020,
+ .end = 0xe68a0064 - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ /* VCR/SWR/DMICR */
+ .start = 0xe68a0000,
+ .end = 0xe68a0014 - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ /* IRQ for channels */
+ .start = evt2irq(0x0a00),
+ .end = evt2irq(0x0a00),
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct platform_device usb_dma0_device = {
+ .name = "sh-dma-engine",
+ .id = 3,
+ .resource = sh7372_usb_dmae0_resources,
+ .num_resources = ARRAY_SIZE(sh7372_usb_dmae0_resources),
+ .dev = {
+ .platform_data = &usb_dma0_platform_data,
+ },
+};
+
+/* USB DMAC1 */
+static const struct sh_dmae_slave_config sh7372_usb_dmae1_slaves[] = {
+ {
+ .slave_id = SHDMA_SLAVE_USB1_TX,
+ .chcr = USBTS_INDEX2VAL(XMIT_SZ_8BYTE),
+ }, {
+ .slave_id = SHDMA_SLAVE_USB1_RX,
+ .chcr = USBTS_INDEX2VAL(XMIT_SZ_8BYTE),
+ },
+};
+
+static struct sh_dmae_pdata usb_dma1_platform_data = {
+ .slave = sh7372_usb_dmae1_slaves,
+ .slave_num = ARRAY_SIZE(sh7372_usb_dmae1_slaves),
+ .channel = sh7372_usb_dmae_channels,
+ .channel_num = ARRAY_SIZE(sh7372_usb_dmae_channels),
+ .ts_low_shift = 6,
+ .ts_low_mask = 0xc0,
+ .ts_high_shift = 0,
+ .ts_high_mask = 0,
+ .ts_shift = usbts_shift,
+ .ts_shift_num = ARRAY_SIZE(usbts_shift),
+ .dmaor_init = DMAOR_DME,
+ .chcr_offset = 0x14,
+ .chcr_ie_bit = 1 << 5,
+ .dmaor_is_32bit = 1,
+ .needs_tend_set = 1,
+ .no_dmars = 1,
+};
+
+static struct resource sh7372_usb_dmae1_resources[] = {
+ {
+ /* Channel registers and DMAOR */
+ .start = 0xe68c0020,
+ .end = 0xe68c0064 - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ /* VCR/SWR/DMICR */
+ .start = 0xe68c0000,
+ .end = 0xe68c0014 - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ /* IRQ for channels */
+ .start = evt2irq(0x1d00),
+ .end = evt2irq(0x1d00),
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct platform_device usb_dma1_device = {
+ .name = "sh-dma-engine",
+ .id = 4,
+ .resource = sh7372_usb_dmae1_resources,
+ .num_resources = ARRAY_SIZE(sh7372_usb_dmae1_resources),
+ .dev = {
+ .platform_data = &usb_dma1_platform_data,
+ },
+};
+
/* VPU */
static struct uio_info vpu_platform_data = {
.name = "VPU5HG",
@@ -818,7 +962,7 @@
&scif4_device,
&scif5_device,
&scif6_device,
- &cmt10_device,
+ &cmt2_device,
&tmu00_device,
&tmu01_device,
};
@@ -829,6 +973,8 @@
&dma0_device,
&dma1_device,
&dma2_device,
+ &usb_dma0_device,
+ &usb_dma1_device,
&vpu_device,
&veu0_device,
&veu1_device,
diff --git a/arch/arm/mach-vexpress/v2m.c b/arch/arm/mach-vexpress/v2m.c
index de72058..1fafc32 100644
--- a/arch/arm/mach-vexpress/v2m.c
+++ b/arch/arm/mach-vexpress/v2m.c
@@ -318,6 +318,10 @@
.rate = 1000000,
};
+static struct clk v2m_ref_clk = {
+ .rate = 32768,
+};
+
static struct clk dummy_apb_pclk;
static struct clk_lookup v2m_lookups[] = {
@@ -348,6 +352,9 @@
}, { /* CLCD */
.dev_id = "mb:clcd",
.clk = &osc1_clk,
+ }, { /* SP805 WDT */
+ .dev_id = "mb:wdt",
+ .clk = &v2m_ref_clk,
}, { /* SP804 timers */
.dev_id = "sp804",
.con_id = "v2m-timer0",
diff --git a/arch/arm/mm/abort-macro.S b/arch/arm/mm/abort-macro.S
index 52162d5..2cbf68e 100644
--- a/arch/arm/mm/abort-macro.S
+++ b/arch/arm/mm/abort-macro.S
@@ -17,7 +17,7 @@
cmp \tmp, # 0x5600 @ Is it ldrsb?
orreq \tmp, \tmp, #1 << 11 @ Set L-bit if yes
tst \tmp, #1 << 11 @ L = 0 -> write
- orreq \psr, \psr, #1 << 11 @ yes.
+ orreq \fsr, \fsr, #1 << 11 @ yes.
b do_DataAbort
not_thumb:
.endm
diff --git a/arch/arm/mm/cache-l2x0.c b/arch/arm/mm/cache-l2x0.c
index 44c0867..9ecfdb5 100644
--- a/arch/arm/mm/cache-l2x0.c
+++ b/arch/arm/mm/cache-l2x0.c
@@ -277,6 +277,25 @@
spin_unlock_irqrestore(&l2x0_lock, flags);
}
+static void __init l2x0_unlock(__u32 cache_id)
+{
+ int lockregs;
+ int i;
+
+ if (cache_id == L2X0_CACHE_ID_PART_L310)
+ lockregs = 8;
+ else
+ /* L210 and unknown types */
+ lockregs = 1;
+
+ for (i = 0; i < lockregs; i++) {
+ writel_relaxed(0x0, l2x0_base + L2X0_LOCKDOWN_WAY_D_BASE +
+ i * L2X0_LOCKDOWN_STRIDE);
+ writel_relaxed(0x0, l2x0_base + L2X0_LOCKDOWN_WAY_I_BASE +
+ i * L2X0_LOCKDOWN_STRIDE);
+ }
+}
+
void __init l2x0_init(void __iomem *base, __u32 aux_val, __u32 aux_mask)
{
__u32 aux;
@@ -328,6 +347,8 @@
* accessing the below registers will fault.
*/
if (!(readl_relaxed(l2x0_base + L2X0_CTRL) & 1)) {
+ /* Make sure that I&D is not locked down when starting */
+ l2x0_unlock(cache_id);
/* l2x0 controller is disabled */
writel_relaxed(aux, l2x0_base + L2X0_AUX_CTRL);
diff --git a/arch/arm/mm/init.c b/arch/arm/mm/init.c
index 64ab413..34409a0 100644
--- a/arch/arm/mm/init.c
+++ b/arch/arm/mm/init.c
@@ -298,7 +298,7 @@
#ifdef CONFIG_HAVE_ARCH_PFN_VALID
int pfn_valid(unsigned long pfn)
{
- return memblock_is_memory(pfn << PAGE_SHIFT);
+ return memblock_is_memory(__pfn_to_phys(pfn));
}
EXPORT_SYMBOL(pfn_valid);
#endif
diff --git a/arch/arm/mm/mmu.c b/arch/arm/mm/mmu.c
index 594d677..ea9c9f3 100644
--- a/arch/arm/mm/mmu.c
+++ b/arch/arm/mm/mmu.c
@@ -273,6 +273,14 @@
.prot_l1 = PMD_TYPE_TABLE,
.domain = DOMAIN_KERNEL,
},
+ [MT_MEMORY_SO] = {
+ .prot_pte = L_PTE_PRESENT | L_PTE_YOUNG | L_PTE_DIRTY |
+ L_PTE_MT_UNCACHED,
+ .prot_l1 = PMD_TYPE_TABLE,
+ .prot_sect = PMD_TYPE_SECT | PMD_SECT_AP_WRITE | PMD_SECT_S |
+ PMD_SECT_UNCACHED | PMD_SECT_XN,
+ .domain = DOMAIN_KERNEL,
+ },
};
const struct mem_type *get_mem_type(unsigned int type)
diff --git a/arch/arm/mm/proc-arm920.S b/arch/arm/mm/proc-arm920.S
index 92bd102..88fb3d9 100644
--- a/arch/arm/mm/proc-arm920.S
+++ b/arch/arm/mm/proc-arm920.S
@@ -382,28 +382,23 @@
.equ cpu_arm920_suspend_size, 4 * 3
#ifdef CONFIG_PM_SLEEP
ENTRY(cpu_arm920_do_suspend)
- stmfd sp!, {r4 - r7, lr}
+ stmfd sp!, {r4 - r6, lr}
mrc p15, 0, r4, c13, c0, 0 @ PID
mrc p15, 0, r5, c3, c0, 0 @ Domain ID
- mrc p15, 0, r6, c2, c0, 0 @ TTB address
- mrc p15, 0, r7, c1, c0, 0 @ Control register
- stmia r0, {r4 - r7}
- ldmfd sp!, {r4 - r7, pc}
+ mrc p15, 0, r6, c1, c0, 0 @ Control register
+ stmia r0, {r4 - r6}
+ ldmfd sp!, {r4 - r6, pc}
ENDPROC(cpu_arm920_do_suspend)
ENTRY(cpu_arm920_do_resume)
mov ip, #0
mcr p15, 0, ip, c8, c7, 0 @ invalidate I+D TLBs
mcr p15, 0, ip, c7, c7, 0 @ invalidate I+D caches
- ldmia r0, {r4 - r7}
+ ldmia r0, {r4 - r6}
mcr p15, 0, r4, c13, c0, 0 @ PID
mcr p15, 0, r5, c3, c0, 0 @ Domain ID
- mcr p15, 0, r6, c2, c0, 0 @ TTB address
- mov r0, r7 @ control register
- mov r2, r6, lsr #14 @ get TTB0 base
- mov r2, r2, lsl #14
- ldr r3, =PMD_TYPE_SECT | PMD_SECT_BUFFERABLE | \
- PMD_SECT_CACHEABLE | PMD_BIT4 | PMD_SECT_AP_WRITE
+ mcr p15, 0, r1, c2, c0, 0 @ TTB address
+ mov r0, r6 @ control register
b cpu_resume_mmu
ENDPROC(cpu_arm920_do_resume)
#endif
diff --git a/arch/arm/mm/proc-arm926.S b/arch/arm/mm/proc-arm926.S
index 2bbcf05..9f8fd91 100644
--- a/arch/arm/mm/proc-arm926.S
+++ b/arch/arm/mm/proc-arm926.S
@@ -397,28 +397,23 @@
.equ cpu_arm926_suspend_size, 4 * 3
#ifdef CONFIG_PM_SLEEP
ENTRY(cpu_arm926_do_suspend)
- stmfd sp!, {r4 - r7, lr}
+ stmfd sp!, {r4 - r6, lr}
mrc p15, 0, r4, c13, c0, 0 @ PID
mrc p15, 0, r5, c3, c0, 0 @ Domain ID
- mrc p15, 0, r6, c2, c0, 0 @ TTB address
- mrc p15, 0, r7, c1, c0, 0 @ Control register
- stmia r0, {r4 - r7}
- ldmfd sp!, {r4 - r7, pc}
+ mrc p15, 0, r6, c1, c0, 0 @ Control register
+ stmia r0, {r4 - r6}
+ ldmfd sp!, {r4 - r6, pc}
ENDPROC(cpu_arm926_do_suspend)
ENTRY(cpu_arm926_do_resume)
mov ip, #0
mcr p15, 0, ip, c8, c7, 0 @ invalidate I+D TLBs
mcr p15, 0, ip, c7, c7, 0 @ invalidate I+D caches
- ldmia r0, {r4 - r7}
+ ldmia r0, {r4 - r6}
mcr p15, 0, r4, c13, c0, 0 @ PID
mcr p15, 0, r5, c3, c0, 0 @ Domain ID
- mcr p15, 0, r6, c2, c0, 0 @ TTB address
- mov r0, r7 @ control register
- mov r2, r6, lsr #14 @ get TTB0 base
- mov r2, r2, lsl #14
- ldr r3, =PMD_TYPE_SECT | PMD_SECT_BUFFERABLE | \
- PMD_SECT_CACHEABLE | PMD_BIT4 | PMD_SECT_AP_WRITE
+ mcr p15, 0, r1, c2, c0, 0 @ TTB address
+ mov r0, r6 @ control register
b cpu_resume_mmu
ENDPROC(cpu_arm926_do_resume)
#endif
diff --git a/arch/arm/mm/proc-sa1100.S b/arch/arm/mm/proc-sa1100.S
index 07219c2..7d91545 100644
--- a/arch/arm/mm/proc-sa1100.S
+++ b/arch/arm/mm/proc-sa1100.S
@@ -168,34 +168,29 @@
mov pc, lr
.globl cpu_sa1100_suspend_size
-.equ cpu_sa1100_suspend_size, 4*4
+.equ cpu_sa1100_suspend_size, 4 * 3
#ifdef CONFIG_PM_SLEEP
ENTRY(cpu_sa1100_do_suspend)
- stmfd sp!, {r4 - r7, lr}
+ stmfd sp!, {r4 - r6, lr}
mrc p15, 0, r4, c3, c0, 0 @ domain ID
- mrc p15, 0, r5, c2, c0, 0 @ translation table base addr
- mrc p15, 0, r6, c13, c0, 0 @ PID
- mrc p15, 0, r7, c1, c0, 0 @ control reg
- stmia r0, {r4 - r7} @ store cp regs
- ldmfd sp!, {r4 - r7, pc}
+ mrc p15, 0, r5, c13, c0, 0 @ PID
+ mrc p15, 0, r6, c1, c0, 0 @ control reg
+ stmia r0, {r4 - r6} @ store cp regs
+ ldmfd sp!, {r4 - r6, pc}
ENDPROC(cpu_sa1100_do_suspend)
ENTRY(cpu_sa1100_do_resume)
- ldmia r0, {r4 - r7} @ load cp regs
- mov r1, #0
- mcr p15, 0, r1, c8, c7, 0 @ flush I+D TLBs
- mcr p15, 0, r1, c7, c7, 0 @ flush I&D cache
- mcr p15, 0, r1, c9, c0, 0 @ invalidate RB
- mcr p15, 0, r1, c9, c0, 5 @ allow user space to use RB
+ ldmia r0, {r4 - r6} @ load cp regs
+ mov ip, #0
+ mcr p15, 0, ip, c8, c7, 0 @ flush I+D TLBs
+ mcr p15, 0, ip, c7, c7, 0 @ flush I&D cache
+ mcr p15, 0, ip, c9, c0, 0 @ invalidate RB
+ mcr p15, 0, ip, c9, c0, 5 @ allow user space to use RB
mcr p15, 0, r4, c3, c0, 0 @ domain ID
- mcr p15, 0, r5, c2, c0, 0 @ translation table base addr
- mcr p15, 0, r6, c13, c0, 0 @ PID
- mov r0, r7 @ control register
- mov r2, r5, lsr #14 @ get TTB0 base
- mov r2, r2, lsl #14
- ldr r3, =PMD_TYPE_SECT | PMD_SECT_BUFFERABLE | \
- PMD_SECT_CACHEABLE | PMD_SECT_AP_WRITE
+ mcr p15, 0, r1, c2, c0, 0 @ translation table base addr
+ mcr p15, 0, r5, c13, c0, 0 @ PID
+ mov r0, r6 @ control register
b cpu_resume_mmu
ENDPROC(cpu_sa1100_do_resume)
#endif
diff --git a/arch/arm/mm/proc-v6.S b/arch/arm/mm/proc-v6.S
index 219138d..d061d2f 100644
--- a/arch/arm/mm/proc-v6.S
+++ b/arch/arm/mm/proc-v6.S
@@ -128,20 +128,18 @@
/* Suspend/resume support: taken from arch/arm/mach-s3c64xx/sleep.S */
.globl cpu_v6_suspend_size
-.equ cpu_v6_suspend_size, 4 * 8
+.equ cpu_v6_suspend_size, 4 * 6
#ifdef CONFIG_PM_SLEEP
ENTRY(cpu_v6_do_suspend)
- stmfd sp!, {r4 - r11, lr}
+ stmfd sp!, {r4 - r9, lr}
mrc p15, 0, r4, c13, c0, 0 @ FCSE/PID
- mrc p15, 0, r5, c13, c0, 1 @ Context ID
- mrc p15, 0, r6, c3, c0, 0 @ Domain ID
- mrc p15, 0, r7, c2, c0, 0 @ Translation table base 0
- mrc p15, 0, r8, c2, c0, 1 @ Translation table base 1
- mrc p15, 0, r9, c1, c0, 1 @ auxiliary control register
- mrc p15, 0, r10, c1, c0, 2 @ co-processor access control
- mrc p15, 0, r11, c1, c0, 0 @ control register
- stmia r0, {r4 - r11}
- ldmfd sp!, {r4- r11, pc}
+ mrc p15, 0, r5, c3, c0, 0 @ Domain ID
+ mrc p15, 0, r6, c2, c0, 1 @ Translation table base 1
+ mrc p15, 0, r7, c1, c0, 1 @ auxiliary control register
+ mrc p15, 0, r8, c1, c0, 2 @ co-processor access control
+ mrc p15, 0, r9, c1, c0, 0 @ control register
+ stmia r0, {r4 - r9}
+ ldmfd sp!, {r4- r9, pc}
ENDPROC(cpu_v6_do_suspend)
ENTRY(cpu_v6_do_resume)
@@ -150,25 +148,21 @@
mcr p15, 0, ip, c7, c5, 0 @ invalidate I cache
mcr p15, 0, ip, c7, c15, 0 @ clean+invalidate cache
mcr p15, 0, ip, c7, c10, 4 @ drain write buffer
- ldmia r0, {r4 - r11}
+ mcr p15, 0, ip, c13, c0, 1 @ set reserved context ID
+ ldmia r0, {r4 - r9}
mcr p15, 0, r4, c13, c0, 0 @ FCSE/PID
- mcr p15, 0, r5, c13, c0, 1 @ Context ID
- mcr p15, 0, r6, c3, c0, 0 @ Domain ID
- mcr p15, 0, r7, c2, c0, 0 @ Translation table base 0
- mcr p15, 0, r8, c2, c0, 1 @ Translation table base 1
- mcr p15, 0, r9, c1, c0, 1 @ auxiliary control register
- mcr p15, 0, r10, c1, c0, 2 @ co-processor access control
+ mcr p15, 0, r5, c3, c0, 0 @ Domain ID
+ ALT_SMP(orr r1, r1, #TTB_FLAGS_SMP)
+ ALT_UP(orr r1, r1, #TTB_FLAGS_UP)
+ mcr p15, 0, r1, c2, c0, 0 @ Translation table base 0
+ mcr p15, 0, r6, c2, c0, 1 @ Translation table base 1
+ mcr p15, 0, r7, c1, c0, 1 @ auxiliary control register
+ mcr p15, 0, r8, c1, c0, 2 @ co-processor access control
mcr p15, 0, ip, c2, c0, 2 @ TTB control register
mcr p15, 0, ip, c7, c5, 4 @ ISB
- mov r0, r11 @ control register
- mov r2, r7, lsr #14 @ get TTB0 base
- mov r2, r2, lsl #14
- ldr r3, cpu_resume_l1_flags
+ mov r0, r9 @ control register
b cpu_resume_mmu
ENDPROC(cpu_v6_do_resume)
-cpu_resume_l1_flags:
- ALT_SMP(.long PMD_TYPE_SECT | PMD_SECT_AP_WRITE | PMD_FLAGS_SMP)
- ALT_UP(.long PMD_TYPE_SECT | PMD_SECT_AP_WRITE | PMD_FLAGS_UP)
#endif
string cpu_v6_name, "ARMv6-compatible processor"
@@ -223,6 +217,22 @@
mrc p15, 0, r0, c1, c0, 0 @ read control register
bic r0, r0, r5 @ clear bits them
orr r0, r0, r6 @ set them
+#ifdef CONFIG_ARM_ERRATA_364296
+ /*
+ * Workaround for the 364296 ARM1136 r0p2 erratum (possible cache data
+ * corruption with hit-under-miss enabled). The conditional code below
+ * (setting the undocumented bit 31 in the auxiliary control register
+ * and the FI bit in the control register) disables hit-under-miss
+ * without putting the processor into full low interrupt latency mode.
+ */
+ ldr r6, =0x4107b362 @ id for ARM1136 r0p2
+ mrc p15, 0, r5, c0, c0, 0 @ get processor id
+ teq r5, r6 @ check for the faulty core
+ mrceq p15, 0, r5, c1, c0, 1 @ load aux control reg
+ orreq r5, r5, #(1 << 31) @ set the undocumented bit 31
+ mcreq p15, 0, r5, c1, c0, 1 @ write aux control reg
+ orreq r0, r0, #(1 << 21) @ low interrupt latency configuration
+#endif
mov pc, lr @ return to head.S:__ret
/*
diff --git a/arch/arm/mm/proc-v7.S b/arch/arm/mm/proc-v7.S
index a30e785..6af366c 100644
--- a/arch/arm/mm/proc-v7.S
+++ b/arch/arm/mm/proc-v7.S
@@ -66,6 +66,7 @@
ENTRY(cpu_v7_reset)
mrc p15, 0, r1, c1, c0, 0 @ ctrl register
bic r1, r1, #0x1 @ ...............m
+ THUMB( bic r1, r1, #1 << 30 ) @ SCTLR.TE (Thumb exceptions)
mcr p15, 0, r1, c1, c0, 0 @ disable MMU
isb
mov pc, r0
@@ -216,53 +217,50 @@
/* Suspend/resume support: derived from arch/arm/mach-s5pv210/sleep.S */
.globl cpu_v7_suspend_size
-.equ cpu_v7_suspend_size, 4 * 9
+.equ cpu_v7_suspend_size, 4 * 7
#ifdef CONFIG_PM_SLEEP
ENTRY(cpu_v7_do_suspend)
- stmfd sp!, {r4 - r11, lr}
+ stmfd sp!, {r4 - r10, lr}
mrc p15, 0, r4, c13, c0, 0 @ FCSE/PID
- mrc p15, 0, r5, c13, c0, 1 @ Context ID
- mrc p15, 0, r6, c13, c0, 3 @ User r/o thread ID
- stmia r0!, {r4 - r6}
+ mrc p15, 0, r5, c13, c0, 3 @ User r/o thread ID
+ stmia r0!, {r4 - r5}
mrc p15, 0, r6, c3, c0, 0 @ Domain ID
- mrc p15, 0, r7, c2, c0, 0 @ TTB 0
- mrc p15, 0, r8, c2, c0, 1 @ TTB 1
- mrc p15, 0, r9, c1, c0, 0 @ Control register
- mrc p15, 0, r10, c1, c0, 1 @ Auxiliary control register
- mrc p15, 0, r11, c1, c0, 2 @ Co-processor access control
- stmia r0, {r6 - r11}
- ldmfd sp!, {r4 - r11, pc}
+ mrc p15, 0, r7, c2, c0, 1 @ TTB 1
+ mrc p15, 0, r8, c1, c0, 0 @ Control register
+ mrc p15, 0, r9, c1, c0, 1 @ Auxiliary control register
+ mrc p15, 0, r10, c1, c0, 2 @ Co-processor access control
+ stmia r0, {r6 - r10}
+ ldmfd sp!, {r4 - r10, pc}
ENDPROC(cpu_v7_do_suspend)
ENTRY(cpu_v7_do_resume)
mov ip, #0
mcr p15, 0, ip, c8, c7, 0 @ invalidate TLBs
mcr p15, 0, ip, c7, c5, 0 @ invalidate I cache
- ldmia r0!, {r4 - r6}
+ mcr p15, 0, ip, c13, c0, 1 @ set reserved context ID
+ ldmia r0!, {r4 - r5}
mcr p15, 0, r4, c13, c0, 0 @ FCSE/PID
- mcr p15, 0, r5, c13, c0, 1 @ Context ID
- mcr p15, 0, r6, c13, c0, 3 @ User r/o thread ID
- ldmia r0, {r6 - r11}
+ mcr p15, 0, r5, c13, c0, 3 @ User r/o thread ID
+ ldmia r0, {r6 - r10}
mcr p15, 0, r6, c3, c0, 0 @ Domain ID
- mcr p15, 0, r7, c2, c0, 0 @ TTB 0
- mcr p15, 0, r8, c2, c0, 1 @ TTB 1
+ ALT_SMP(orr r1, r1, #TTB_FLAGS_SMP)
+ ALT_UP(orr r1, r1, #TTB_FLAGS_UP)
+ mcr p15, 0, r1, c2, c0, 0 @ TTB 0
+ mcr p15, 0, r7, c2, c0, 1 @ TTB 1
mcr p15, 0, ip, c2, c0, 2 @ TTB control register
- mcr p15, 0, r10, c1, c0, 1 @ Auxiliary control register
- mcr p15, 0, r11, c1, c0, 2 @ Co-processor access control
+ mrc p15, 0, r4, c1, c0, 1 @ Read Auxiliary control register
+ teq r4, r9 @ Is it already set?
+ mcrne p15, 0, r9, c1, c0, 1 @ No, so write it
+ mcr p15, 0, r10, c1, c0, 2 @ Co-processor access control
ldr r4, =PRRR @ PRRR
ldr r5, =NMRR @ NMRR
mcr p15, 0, r4, c10, c2, 0 @ write PRRR
mcr p15, 0, r5, c10, c2, 1 @ write NMRR
isb
- mov r0, r9 @ control register
- mov r2, r7, lsr #14 @ get TTB0 base
- mov r2, r2, lsl #14
- ldr r3, cpu_resume_l1_flags
+ dsb
+ mov r0, r8 @ control register
b cpu_resume_mmu
ENDPROC(cpu_v7_do_resume)
-cpu_resume_l1_flags:
- ALT_SMP(.long PMD_TYPE_SECT | PMD_SECT_AP_WRITE | PMD_FLAGS_SMP)
- ALT_UP(.long PMD_TYPE_SECT | PMD_SECT_AP_WRITE | PMD_FLAGS_UP)
#endif
__CPUINIT
diff --git a/arch/arm/mm/proc-xsc3.S b/arch/arm/mm/proc-xsc3.S
index 28c72a2..abf0507 100644
--- a/arch/arm/mm/proc-xsc3.S
+++ b/arch/arm/mm/proc-xsc3.S
@@ -406,24 +406,23 @@
.align
.globl cpu_xsc3_suspend_size
-.equ cpu_xsc3_suspend_size, 4 * 8
+.equ cpu_xsc3_suspend_size, 4 * 6
#ifdef CONFIG_PM_SLEEP
ENTRY(cpu_xsc3_do_suspend)
- stmfd sp!, {r4 - r10, lr}
+ stmfd sp!, {r4 - r9, lr}
mrc p14, 0, r4, c6, c0, 0 @ clock configuration, for turbo mode
mrc p15, 0, r5, c15, c1, 0 @ CP access reg
mrc p15, 0, r6, c13, c0, 0 @ PID
mrc p15, 0, r7, c3, c0, 0 @ domain ID
- mrc p15, 0, r8, c2, c0, 0 @ translation table base addr
- mrc p15, 0, r9, c1, c0, 1 @ auxiliary control reg
- mrc p15, 0, r10, c1, c0, 0 @ control reg
+ mrc p15, 0, r8, c1, c0, 1 @ auxiliary control reg
+ mrc p15, 0, r9, c1, c0, 0 @ control reg
bic r4, r4, #2 @ clear frequency change bit
- stmia r0, {r1, r4 - r10} @ store v:p offset + cp regs
- ldmia sp!, {r4 - r10, pc}
+ stmia r0, {r4 - r9} @ store cp regs
+ ldmia sp!, {r4 - r9, pc}
ENDPROC(cpu_xsc3_do_suspend)
ENTRY(cpu_xsc3_do_resume)
- ldmia r0, {r1, r4 - r10} @ load v:p offset + cp regs
+ ldmia r0, {r4 - r9} @ load cp regs
mov ip, #0
mcr p15, 0, ip, c7, c7, 0 @ invalidate I & D caches, BTB
mcr p15, 0, ip, c7, c10, 4 @ drain write (&fill) buffer
@@ -433,15 +432,10 @@
mcr p15, 0, r5, c15, c1, 0 @ CP access reg
mcr p15, 0, r6, c13, c0, 0 @ PID
mcr p15, 0, r7, c3, c0, 0 @ domain ID
- mcr p15, 0, r8, c2, c0, 0 @ translation table base addr
- mcr p15, 0, r9, c1, c0, 1 @ auxiliary control reg
-
- @ temporarily map resume_turn_on_mmu into the page table,
- @ otherwise prefetch abort occurs after MMU is turned on
- mov r0, r10 @ control register
- mov r2, r8, lsr #14 @ get TTB0 base
- mov r2, r2, lsl #14
- ldr r3, =0x542e @ section flags
+ orr r1, r1, #0x18 @ cache the page table in L2
+ mcr p15, 0, r1, c2, c0, 0 @ translation table base addr
+ mcr p15, 0, r8, c1, c0, 1 @ auxiliary control reg
+ mov r0, r9 @ control register
b cpu_resume_mmu
ENDPROC(cpu_xsc3_do_resume)
#endif
diff --git a/arch/arm/mm/proc-xscale.S b/arch/arm/mm/proc-xscale.S
index fbc06e5..3277904 100644
--- a/arch/arm/mm/proc-xscale.S
+++ b/arch/arm/mm/proc-xscale.S
@@ -520,24 +520,23 @@
.align
.globl cpu_xscale_suspend_size
-.equ cpu_xscale_suspend_size, 4 * 7
+.equ cpu_xscale_suspend_size, 4 * 6
#ifdef CONFIG_PM_SLEEP
ENTRY(cpu_xscale_do_suspend)
- stmfd sp!, {r4 - r10, lr}
+ stmfd sp!, {r4 - r9, lr}
mrc p14, 0, r4, c6, c0, 0 @ clock configuration, for turbo mode
mrc p15, 0, r5, c15, c1, 0 @ CP access reg
mrc p15, 0, r6, c13, c0, 0 @ PID
mrc p15, 0, r7, c3, c0, 0 @ domain ID
- mrc p15, 0, r8, c2, c0, 0 @ translation table base addr
- mrc p15, 0, r9, c1, c1, 0 @ auxiliary control reg
- mrc p15, 0, r10, c1, c0, 0 @ control reg
+ mrc p15, 0, r8, c1, c1, 0 @ auxiliary control reg
+ mrc p15, 0, r9, c1, c0, 0 @ control reg
bic r4, r4, #2 @ clear frequency change bit
- stmia r0, {r4 - r10} @ store cp regs
- ldmfd sp!, {r4 - r10, pc}
+ stmia r0, {r4 - r9} @ store cp regs
+ ldmfd sp!, {r4 - r9, pc}
ENDPROC(cpu_xscale_do_suspend)
ENTRY(cpu_xscale_do_resume)
- ldmia r0, {r4 - r10} @ load cp regs
+ ldmia r0, {r4 - r9} @ load cp regs
mov ip, #0
mcr p15, 0, ip, c8, c7, 0 @ invalidate I & D TLBs
mcr p15, 0, ip, c7, c7, 0 @ invalidate I & D caches, BTB
@@ -545,13 +544,9 @@
mcr p15, 0, r5, c15, c1, 0 @ CP access reg
mcr p15, 0, r6, c13, c0, 0 @ PID
mcr p15, 0, r7, c3, c0, 0 @ domain ID
- mcr p15, 0, r8, c2, c0, 0 @ translation table base addr
- mcr p15, 0, r9, c1, c1, 0 @ auxiliary control reg
- mov r0, r10 @ control register
- mov r2, r8, lsr #14 @ get TTB0 base
- mov r2, r2, lsl #14
- ldr r3, =PMD_TYPE_SECT | PMD_SECT_BUFFERABLE | \
- PMD_SECT_CACHEABLE | PMD_SECT_AP_WRITE
+ mcr p15, 0, r1, c2, c0, 0 @ translation table base addr
+ mcr p15, 0, r8, c1, c1, 0 @ auxiliary control reg
+ mov r0, r9 @ control register
b cpu_resume_mmu
ENDPROC(cpu_xscale_do_resume)
#endif
diff --git a/arch/arm/plat-omap/omap_device.c b/arch/arm/plat-omap/omap_device.c
index b6b4097..02609ee 100644
--- a/arch/arm/plat-omap/omap_device.c
+++ b/arch/arm/plat-omap/omap_device.c
@@ -615,6 +615,9 @@
return pm_generic_resume_noirq(dev);
}
+#else
+#define _od_suspend_noirq NULL
+#define _od_resume_noirq NULL
#endif
static struct dev_pm_domain omap_device_pm_domain = {
@@ -622,7 +625,8 @@
SET_RUNTIME_PM_OPS(_od_runtime_suspend, _od_runtime_resume,
_od_runtime_idle)
USE_PLATFORM_PM_SLEEP_OPS
- SET_SYSTEM_SLEEP_PM_OPS(_od_suspend_noirq, _od_resume_noirq)
+ .suspend_noirq = _od_suspend_noirq,
+ .resume_noirq = _od_resume_noirq,
}
};
diff --git a/arch/arm/plat-s5p/clock.c b/arch/arm/plat-s5p/clock.c
index 02af235..5f84a3f 100644
--- a/arch/arm/plat-s5p/clock.c
+++ b/arch/arm/plat-s5p/clock.c
@@ -192,7 +192,7 @@
if (IS_ERR(pclk))
return -EINVAL;
- rate = pclk->ops->get_rate(clk);
+ rate = pclk->ops->get_rate(pclk);
clk_put(pclk);
return rate;
diff --git a/arch/arm/plat-s5p/irq-gpioint.c b/arch/arm/plat-s5p/irq-gpioint.c
index 327ab9f..f71078e 100644
--- a/arch/arm/plat-s5p/irq-gpioint.c
+++ b/arch/arm/plat-s5p/irq-gpioint.c
@@ -23,6 +23,8 @@
#include <plat/gpio-core.h>
#include <plat/gpio-cfg.h>
+#include <asm/mach/irq.h>
+
#define GPIO_BASE(chip) (((unsigned long)(chip)->base) & 0xFFFFF000u)
#define CON_OFFSET 0x700
@@ -81,6 +83,9 @@
int group, pend_offset, mask_offset;
unsigned int pend, mask;
+ struct irq_chip *chip = irq_get_chip(irq);
+ chained_irq_enter(chip, desc);
+
for (group = 0; group < bank->nr_groups; group++) {
struct s3c_gpio_chip *chip = bank->chips[group];
if (!chip)
@@ -102,6 +107,7 @@
pend &= ~BIT(offset);
}
}
+ chained_irq_exit(chip, desc);
}
static __init int s5p_gpioint_add(struct s3c_gpio_chip *chip)
diff --git a/arch/arm/plat-samsung/include/plat/backlight.h b/arch/arm/plat-samsung/include/plat/backlight.h
index 51d8da8..ad530c7 100644
--- a/arch/arm/plat-samsung/include/plat/backlight.h
+++ b/arch/arm/plat-samsung/include/plat/backlight.h
@@ -20,7 +20,7 @@
int func;
};
-extern void samsung_bl_set(struct samsung_bl_gpio_info *gpio_info,
+extern void __init samsung_bl_set(struct samsung_bl_gpio_info *gpio_info,
struct platform_pwm_backlight_data *bl_data);
#endif /* __ASM_PLAT_BACKLIGHT_H */
diff --git a/arch/arm/plat-samsung/irq-vic-timer.c b/arch/arm/plat-samsung/irq-vic-timer.c
index f714d06..51583cd 100644
--- a/arch/arm/plat-samsung/irq-vic-timer.c
+++ b/arch/arm/plat-samsung/irq-vic-timer.c
@@ -22,9 +22,14 @@
#include <plat/irq-vic-timer.h>
#include <plat/regs-timer.h>
+#include <asm/mach/irq.h>
+
static void s3c_irq_demux_vic_timer(unsigned int irq, struct irq_desc *desc)
{
+ struct irq_chip *chip = irq_get_chip(irq);
+ chained_irq_enter(chip, desc);
generic_handle_irq((int)desc->irq_data.handler_data);
+ chained_irq_exit(chip, desc);
}
/* We assume the IRQ_TIMER0..IRQ_TIMER4 range is continuous. */
diff --git a/arch/arm/tools/mach-types b/arch/arm/tools/mach-types
index fff68d0..62cc8f9 100644
--- a/arch/arm/tools/mach-types
+++ b/arch/arm/tools/mach-types
@@ -351,7 +351,7 @@
nokia_rx51 MACH_NOKIA_RX51 NOKIA_RX51 1955
omap_zoom2 MACH_OMAP_ZOOM2 OMAP_ZOOM2 1967
cpuat9260 MACH_CPUAT9260 CPUAT9260 1973
-eukrea_cpuimx27 MACH_CPUIMX27 CPUIMX27 1975
+eukrea_cpuimx27 MACH_EUKREA_CPUIMX27 EUKREA_CPUIMX27 1975
acs5k MACH_ACS5K ACS5K 1982
snapper_9260 MACH_SNAPPER_9260 SNAPPER_9260 1987
dsm320 MACH_DSM320 DSM320 1988
@@ -476,8 +476,8 @@
omap4_panda MACH_OMAP4_PANDA OMAP4_PANDA 2791
ti8168evm MACH_TI8168EVM TI8168EVM 2800
teton_bga MACH_TETON_BGA TETON_BGA 2816
-eukrea_cpuimx25sd MACH_EUKREA_CPUIMX25 EUKREA_CPUIMX25 2820
-eukrea_cpuimx35sd MACH_EUKREA_CPUIMX35 EUKREA_CPUIMX35 2821
+eukrea_cpuimx25sd MACH_EUKREA_CPUIMX25SD EUKREA_CPUIMX25SD 2820
+eukrea_cpuimx35sd MACH_EUKREA_CPUIMX35SD EUKREA_CPUIMX35SD 2821
eukrea_cpuimx51sd MACH_EUKREA_CPUIMX51SD EUKREA_CPUIMX51SD 2822
eukrea_cpuimx51 MACH_EUKREA_CPUIMX51 EUKREA_CPUIMX51 2823
smdkc210 MACH_SMDKC210 SMDKC210 2838
diff --git a/arch/arm/vfp/vfpmodule.c b/arch/arm/vfp/vfpmodule.c
index 79bcb43..0cbd5a0 100644
--- a/arch/arm/vfp/vfpmodule.c
+++ b/arch/arm/vfp/vfpmodule.c
@@ -11,6 +11,7 @@
#include <linux/module.h>
#include <linux/types.h>
#include <linux/cpu.h>
+#include <linux/cpu_pm.h>
#include <linux/kernel.h>
#include <linux/notifier.h>
#include <linux/signal.h>
@@ -68,7 +69,7 @@
/*
* Force a reload of the VFP context from the thread structure. We do
* this by ensuring that access to the VFP hardware is disabled, and
- * clear last_VFP_context. Must be called from non-preemptible context.
+ * clear vfp_current_hw_state. Must be called from non-preemptible context.
*/
static void vfp_force_reload(unsigned int cpu, struct thread_info *thread)
{
@@ -436,9 +437,7 @@
set_copro_access(access | CPACC_FULL(10) | CPACC_FULL(11));
}
-#ifdef CONFIG_PM
-#include <linux/syscore_ops.h>
-
+#ifdef CONFIG_CPU_PM
static int vfp_pm_suspend(void)
{
struct thread_info *ti = current_thread_info();
@@ -468,19 +467,33 @@
fmxr(FPEXC, fmrx(FPEXC) & ~FPEXC_EN);
}
-static struct syscore_ops vfp_pm_syscore_ops = {
- .suspend = vfp_pm_suspend,
- .resume = vfp_pm_resume,
+static int vfp_cpu_pm_notifier(struct notifier_block *self, unsigned long cmd,
+ void *v)
+{
+ switch (cmd) {
+ case CPU_PM_ENTER:
+ vfp_pm_suspend();
+ break;
+ case CPU_PM_ENTER_FAILED:
+ case CPU_PM_EXIT:
+ vfp_pm_resume();
+ break;
+ }
+ return NOTIFY_OK;
+}
+
+static struct notifier_block vfp_cpu_pm_notifier_block = {
+ .notifier_call = vfp_cpu_pm_notifier,
};
static void vfp_pm_init(void)
{
- register_syscore_ops(&vfp_pm_syscore_ops);
+ cpu_pm_register_notifier(&vfp_cpu_pm_notifier_block);
}
#else
static inline void vfp_pm_init(void) { }
-#endif /* CONFIG_PM */
+#endif /* CONFIG_CPU_PM */
/*
* Ensure that the VFP state stored in 'thread->vfpstate' is up to date
diff --git a/arch/avr32/kernel/syscall_table.S b/arch/avr32/kernel/syscall_table.S
index c7fd394..6eba535 100644
--- a/arch/avr32/kernel/syscall_table.S
+++ b/arch/avr32/kernel/syscall_table.S
@@ -158,7 +158,7 @@
.long sys_sched_rr_get_interval
.long sys_nanosleep
.long sys_poll
- .long sys_nfsservctl /* 145 */
+ .long sys_ni_syscall /* 145 was nfsservctl */
.long sys_setresgid
.long sys_getresgid
.long sys_prctl
diff --git a/arch/blackfin/mach-common/entry.S b/arch/blackfin/mach-common/entry.S
index 225d311..e413729 100644
--- a/arch/blackfin/mach-common/entry.S
+++ b/arch/blackfin/mach-common/entry.S
@@ -1543,7 +1543,7 @@
.long _sys_ni_syscall /* for vm86 */
.long _sys_ni_syscall /* old "query_module" */
.long _sys_ni_syscall /* sys_poll */
- .long _sys_nfsservctl
+ .long _sys_ni_syscall /* old nfsservctl */
.long _sys_setresgid /* setresgid16 */ /* 170 */
.long _sys_getresgid /* getresgid16 */
.long _sys_prctl
diff --git a/arch/cris/arch-v10/kernel/entry.S b/arch/cris/arch-v10/kernel/entry.S
index 1161883..592fbe9 100644
--- a/arch/cris/arch-v10/kernel/entry.S
+++ b/arch/cris/arch-v10/kernel/entry.S
@@ -771,7 +771,7 @@
.long sys_ni_syscall /* sys_vm86 */
.long sys_ni_syscall /* Old sys_query_module */
.long sys_poll
- .long sys_nfsservctl
+ .long sys_ni_syscall /* old nfsservctl */
.long sys_setresgid16 /* 170 */
.long sys_getresgid16
.long sys_prctl
diff --git a/arch/cris/arch-v32/kernel/entry.S b/arch/cris/arch-v32/kernel/entry.S
index 84fed7e..c3ea4694 100644
--- a/arch/cris/arch-v32/kernel/entry.S
+++ b/arch/cris/arch-v32/kernel/entry.S
@@ -714,7 +714,7 @@
.long sys_ni_syscall /* sys_vm86 */
.long sys_ni_syscall /* Old sys_query_module */
.long sys_poll
- .long sys_nfsservctl
+ .long sys_ni_syscall /* Old nfsservctl */
.long sys_setresgid16 /* 170 */
.long sys_getresgid16
.long sys_prctl
diff --git a/arch/cris/include/asm/serial.h b/arch/cris/include/asm/serial.h
new file mode 100644
index 0000000..af7535a
--- /dev/null
+++ b/arch/cris/include/asm/serial.h
@@ -0,0 +1,9 @@
+#ifndef _ASM_SERIAL_H
+#define _ASM_SERIAL_H
+
+/*
+ * This assumes you have a 1.8432 MHz clock for your UART.
+ */
+#define BASE_BAUD (1843200 / 16)
+
+#endif /* _ASM_SERIAL_H */
diff --git a/arch/frv/kernel/entry.S b/arch/frv/kernel/entry.S
index 017d6d7..5ba23f7 100644
--- a/arch/frv/kernel/entry.S
+++ b/arch/frv/kernel/entry.S
@@ -1358,7 +1358,7 @@
.long sys_ni_syscall /* for vm86 */
.long sys_ni_syscall /* Old sys_query_module */
.long sys_poll
- .long sys_nfsservctl
+ .long sys_ni_syscall /* Old nfsservctl */
.long sys_setresgid16 /* 170 */
.long sys_getresgid16
.long sys_prctl
diff --git a/arch/h8300/kernel/syscalls.S b/arch/h8300/kernel/syscalls.S
index f4b2e67..4be2ea2 100644
--- a/arch/h8300/kernel/syscalls.S
+++ b/arch/h8300/kernel/syscalls.S
@@ -183,7 +183,7 @@
.long SYMBOL_NAME(sys_ni_syscall) /* for vm86 */
.long SYMBOL_NAME(sys_ni_syscall) /* sys_query_module */
.long SYMBOL_NAME(sys_poll)
- .long SYMBOL_NAME(sys_nfsservctl)
+ .long SYMBOL_NAME(sys_ni_syscall) /* old nfsservctl */
.long SYMBOL_NAME(sys_setresgid16) /* 170 */
.long SYMBOL_NAME(sys_getresgid16)
.long SYMBOL_NAME(sys_prctl)
diff --git a/arch/ia64/kernel/entry.S b/arch/ia64/kernel/entry.S
index 97dd2ab..198c753 100644
--- a/arch/ia64/kernel/entry.S
+++ b/arch/ia64/kernel/entry.S
@@ -1614,7 +1614,7 @@
data8 sys_sched_get_priority_min
data8 sys_sched_rr_get_interval
data8 sys_nanosleep
- data8 sys_nfsservctl
+ data8 sys_ni_syscall // old nfsservctl
data8 sys_prctl // 1170
data8 sys_getpagesize
data8 sys_mmap2
diff --git a/arch/m32r/kernel/syscall_table.S b/arch/m32r/kernel/syscall_table.S
index 528f2e6..f365c19 100644
--- a/arch/m32r/kernel/syscall_table.S
+++ b/arch/m32r/kernel/syscall_table.S
@@ -168,7 +168,7 @@
.long sys_tas /* vm86 syscall holder */
.long sys_ni_syscall /* query_module syscall holder */
.long sys_poll
- .long sys_nfsservctl
+ .long sys_ni_syscall /* was nfsservctl */
.long sys_setresgid /* 170 */
.long sys_getresgid
.long sys_prctl
diff --git a/arch/m68k/include/asm/page_mm.h b/arch/m68k/include/asm/page_mm.h
index 31d5570..89f2014 100644
--- a/arch/m68k/include/asm/page_mm.h
+++ b/arch/m68k/include/asm/page_mm.h
@@ -162,7 +162,7 @@
pgdat->node_mem_map + (__pfn - pgdat->node_start_pfn); \
})
#define page_to_pfn(_page) ({ \
- struct page *__p = (_page); \
+ const struct page *__p = (_page); \
struct pglist_data *pgdat; \
pgdat = &pg_data_map[page_to_nid(__p)]; \
((__p) - pgdat->node_mem_map) + pgdat->node_start_pfn; \
diff --git a/arch/m68k/kernel/syscalltable.S b/arch/m68k/kernel/syscalltable.S
index 00d1452..c468f2e 100644
--- a/arch/m68k/kernel/syscalltable.S
+++ b/arch/m68k/kernel/syscalltable.S
@@ -189,7 +189,7 @@
.long sys_getpagesize
.long sys_ni_syscall /* old "query_module" */
.long sys_poll
- .long sys_nfsservctl
+ .long sys_ni_syscall /* old nfsservctl */
.long sys_setresgid16 /* 170 */
.long sys_getresgid16
.long sys_prctl
diff --git a/arch/microblaze/kernel/syscall_table.S b/arch/microblaze/kernel/syscall_table.S
index d915a12..8789daa 100644
--- a/arch/microblaze/kernel/syscall_table.S
+++ b/arch/microblaze/kernel/syscall_table.S
@@ -173,7 +173,7 @@
.long sys_ni_syscall /* sys_vm86 */
.long sys_ni_syscall /* Old sys_query_module */
.long sys_poll
- .long sys_nfsservctl
+ .long sys_ni_syscall /* old nfsservctl */
.long sys_setresgid /* 170 */
.long sys_getresgid
.long sys_prctl
diff --git a/arch/mips/kernel/scall32-o32.S b/arch/mips/kernel/scall32-o32.S
index e521420..865bc7a 100644
--- a/arch/mips/kernel/scall32-o32.S
+++ b/arch/mips/kernel/scall32-o32.S
@@ -424,7 +424,7 @@
sys sys_getresuid 3
sys sys_ni_syscall 0 /* was sys_query_module */
sys sys_poll 3
- sys sys_nfsservctl 3
+ sys sys_ni_syscall 0 /* was nfsservctl */
sys sys_setresgid 3 /* 4190 */
sys sys_getresgid 3
sys sys_prctl 5
diff --git a/arch/mips/kernel/scall64-64.S b/arch/mips/kernel/scall64-64.S
index 85874d6..fb7334b 100644
--- a/arch/mips/kernel/scall64-64.S
+++ b/arch/mips/kernel/scall64-64.S
@@ -299,7 +299,7 @@
PTR sys_ni_syscall /* 5170, was get_kernel_syms */
PTR sys_ni_syscall /* was query_module */
PTR sys_quotactl
- PTR sys_nfsservctl
+ PTR sys_ni_syscall /* was nfsservctl */
PTR sys_ni_syscall /* res. for getpmsg */
PTR sys_ni_syscall /* 5175 for putpmsg */
PTR sys_ni_syscall /* res. for afs_syscall */
diff --git a/arch/mips/kernel/scall64-n32.S b/arch/mips/kernel/scall64-n32.S
index b85842f..f9296e8 100644
--- a/arch/mips/kernel/scall64-n32.S
+++ b/arch/mips/kernel/scall64-n32.S
@@ -294,7 +294,7 @@
PTR sys_ni_syscall /* 6170, was get_kernel_syms */
PTR sys_ni_syscall /* was query_module */
PTR sys_quotactl
- PTR compat_sys_nfsservctl
+ PTR sys_ni_syscall /* was nfsservctl */
PTR sys_ni_syscall /* res. for getpmsg */
PTR sys_ni_syscall /* 6175 for putpmsg */
PTR sys_ni_syscall /* res. for afs_syscall */
diff --git a/arch/mips/kernel/scall64-o32.S b/arch/mips/kernel/scall64-o32.S
index 46c4763..4d7c982 100644
--- a/arch/mips/kernel/scall64-o32.S
+++ b/arch/mips/kernel/scall64-o32.S
@@ -392,7 +392,7 @@
PTR sys_getresuid
PTR sys_ni_syscall /* was query_module */
PTR sys_poll
- PTR compat_sys_nfsservctl
+ PTR sys_ni_syscall /* was nfsservctl */
PTR sys_setresgid /* 4190 */
PTR sys_getresgid
PTR sys_prctl
diff --git a/arch/mn10300/kernel/entry.S b/arch/mn10300/kernel/entry.S
index ae435e1..3e3620d 100644
--- a/arch/mn10300/kernel/entry.S
+++ b/arch/mn10300/kernel/entry.S
@@ -589,7 +589,7 @@
.long sys_ni_syscall /* vm86 */
.long sys_ni_syscall /* Old sys_query_module */
.long sys_poll
- .long sys_nfsservctl
+ .long sys_ni_syscall /* was nfsservctl */
.long sys_setresgid16 /* 170 */
.long sys_getresgid16
.long sys_prctl
diff --git a/arch/openrisc/include/asm/dma-mapping.h b/arch/openrisc/include/asm/dma-mapping.h
index 052f877..60b4722 100644
--- a/arch/openrisc/include/asm/dma-mapping.h
+++ b/arch/openrisc/include/asm/dma-mapping.h
@@ -31,7 +31,6 @@
#define DMA_ERROR_CODE (~(dma_addr_t)0x0)
-int dma_mapping_error(struct device *dev, dma_addr_t dma_addr);
#define dma_alloc_noncoherent(d, s, h, f) dma_alloc_coherent(d, s, h, f)
#define dma_free_noncoherent(d, s, v, h) dma_free_coherent(d, s, v, h)
@@ -47,6 +46,12 @@
void or1k_unmap_page(struct device *dev, dma_addr_t dma_handle,
size_t size, enum dma_data_direction dir,
struct dma_attrs *attrs);
+int or1k_map_sg(struct device *dev, struct scatterlist *sg,
+ int nents, enum dma_data_direction dir,
+ struct dma_attrs *attrs);
+void or1k_unmap_sg(struct device *dev, struct scatterlist *sg,
+ int nents, enum dma_data_direction dir,
+ struct dma_attrs *attrs);
void or1k_sync_single_for_cpu(struct device *dev,
dma_addr_t dma_handle, size_t size,
enum dma_data_direction dir);
@@ -98,6 +103,51 @@
debug_dma_unmap_page(dev, addr, size, dir, true);
}
+static inline int dma_map_sg(struct device *dev, struct scatterlist *sg,
+ int nents, enum dma_data_direction dir)
+{
+ int i, ents;
+ struct scatterlist *s;
+
+ for_each_sg(sg, s, nents, i)
+ kmemcheck_mark_initialized(sg_virt(s), s->length);
+ BUG_ON(!valid_dma_direction(dir));
+ ents = or1k_map_sg(dev, sg, nents, dir, NULL);
+ debug_dma_map_sg(dev, sg, nents, ents, dir);
+
+ return ents;
+}
+
+static inline void dma_unmap_sg(struct device *dev, struct scatterlist *sg,
+ int nents, enum dma_data_direction dir)
+{
+ BUG_ON(!valid_dma_direction(dir));
+ debug_dma_unmap_sg(dev, sg, nents, dir);
+ or1k_unmap_sg(dev, sg, nents, dir, NULL);
+}
+
+static inline dma_addr_t dma_map_page(struct device *dev, struct page *page,
+ size_t offset, size_t size,
+ enum dma_data_direction dir)
+{
+ dma_addr_t addr;
+
+ kmemcheck_mark_initialized(page_address(page) + offset, size);
+ BUG_ON(!valid_dma_direction(dir));
+ addr = or1k_map_page(dev, page, offset, size, dir, NULL);
+ debug_dma_map_page(dev, page, offset, size, dir, addr, false);
+
+ return addr;
+}
+
+static inline void dma_unmap_page(struct device *dev, dma_addr_t addr,
+ size_t size, enum dma_data_direction dir)
+{
+ BUG_ON(!valid_dma_direction(dir));
+ or1k_unmap_page(dev, addr, size, dir, NULL);
+ debug_dma_unmap_page(dev, addr, size, dir, true);
+}
+
static inline void dma_sync_single_for_cpu(struct device *dev, dma_addr_t addr,
size_t size,
enum dma_data_direction dir)
@@ -119,7 +169,12 @@
static inline int dma_supported(struct device *dev, u64 dma_mask)
{
/* Support 32 bit DMA mask exclusively */
- return dma_mask == 0xffffffffULL;
+ return dma_mask == DMA_BIT_MASK(32);
+}
+
+static inline int dma_mapping_error(struct device *dev, dma_addr_t dma_addr)
+{
+ return 0;
}
static inline int dma_set_mask(struct device *dev, u64 dma_mask)
diff --git a/arch/openrisc/include/asm/sigcontext.h b/arch/openrisc/include/asm/sigcontext.h
index 54a5c50..b79c2b1 100644
--- a/arch/openrisc/include/asm/sigcontext.h
+++ b/arch/openrisc/include/asm/sigcontext.h
@@ -23,16 +23,11 @@
/* This struct is saved by setup_frame in signal.c, to keep the current
context while a signal handler is executed. It's restored by sys_sigreturn.
-
- To keep things simple, we use pt_regs here even though normally you just
- specify the list of regs to save. Then we can use copy_from_user on the
- entire regs instead of a bunch of get_user's as well...
*/
struct sigcontext {
- struct pt_regs regs; /* needs to be first */
+ struct user_regs_struct regs; /* needs to be first */
unsigned long oldmask;
- unsigned long usp; /* usp before stacking this gunk on it */
};
#endif /* __ASM_OPENRISC_SIGCONTEXT_H */
diff --git a/arch/openrisc/kernel/dma.c b/arch/openrisc/kernel/dma.c
index 968d3ee..f1c8ee2 100644
--- a/arch/openrisc/kernel/dma.c
+++ b/arch/openrisc/kernel/dma.c
@@ -154,6 +154,33 @@
/* Nothing special to do here... */
}
+int or1k_map_sg(struct device *dev, struct scatterlist *sg,
+ int nents, enum dma_data_direction dir,
+ struct dma_attrs *attrs)
+{
+ struct scatterlist *s;
+ int i;
+
+ for_each_sg(sg, s, nents, i) {
+ s->dma_address = or1k_map_page(dev, sg_page(s), s->offset,
+ s->length, dir, NULL);
+ }
+
+ return nents;
+}
+
+void or1k_unmap_sg(struct device *dev, struct scatterlist *sg,
+ int nents, enum dma_data_direction dir,
+ struct dma_attrs *attrs)
+{
+ struct scatterlist *s;
+ int i;
+
+ for_each_sg(sg, s, nents, i) {
+ or1k_unmap_page(dev, sg_dma_address(s), sg_dma_len(s), dir, NULL);
+ }
+}
+
void or1k_sync_single_for_cpu(struct device *dev,
dma_addr_t dma_handle, size_t size,
enum dma_data_direction dir)
@@ -187,5 +214,4 @@
return 0;
}
-
fs_initcall(dma_init);
diff --git a/arch/openrisc/kernel/signal.c b/arch/openrisc/kernel/signal.c
index 5f759c7..95207ab 100644
--- a/arch/openrisc/kernel/signal.c
+++ b/arch/openrisc/kernel/signal.c
@@ -52,31 +52,25 @@
static int restore_sigcontext(struct pt_regs *regs, struct sigcontext *sc)
{
unsigned int err = 0;
- unsigned long old_usp;
/* Alwys make any pending restarted system call return -EINTR */
current_thread_info()->restart_block.fn = do_no_restart_syscall;
- /* restore the regs from &sc->regs (same as sc, since regs is first)
+ /*
+ * Restore the regs from &sc->regs.
* (sc is already checked for VERIFY_READ since the sigframe was
* checked in sys_sigreturn previously)
*/
-
- if (__copy_from_user(regs, sc, sizeof(struct pt_regs)))
+ if (__copy_from_user(regs, sc->regs.gpr, 32 * sizeof(unsigned long)))
+ goto badframe;
+ if (__copy_from_user(®s->pc, &sc->regs.pc, sizeof(unsigned long)))
+ goto badframe;
+ if (__copy_from_user(®s->sr, &sc->regs.sr, sizeof(unsigned long)))
goto badframe;
/* make sure the SM-bit is cleared so user-mode cannot fool us */
regs->sr &= ~SPR_SR_SM;
- /* restore the old USP as it was before we stacked the sc etc.
- * (we cannot just pop the sigcontext since we aligned the sp and
- * stuff after pushing it)
- */
-
- err |= __get_user(old_usp, &sc->usp);
-
- regs->sp = old_usp;
-
/* TODO: the other ports use regs->orig_XX to disable syscall checks
* after this completes, but we don't use that mechanism. maybe we can
* use it now ?
@@ -137,18 +131,17 @@
unsigned long mask)
{
int err = 0;
- unsigned long usp = regs->sp;
- /* copy the regs. they are first in sc so we can use sc directly */
+ /* copy the regs */
- err |= __copy_to_user(sc, regs, sizeof(struct pt_regs));
+ err |= __copy_to_user(sc->regs.gpr, regs, 32 * sizeof(unsigned long));
+ err |= __copy_to_user(&sc->regs.pc, ®s->pc, sizeof(unsigned long));
+ err |= __copy_to_user(&sc->regs.sr, ®s->sr, sizeof(unsigned long));
/* then some other stuff */
err |= __put_user(mask, &sc->oldmask);
- err |= __put_user(usp, &sc->usp);
-
return err;
}
diff --git a/arch/parisc/kernel/syscall_table.S b/arch/parisc/kernel/syscall_table.S
index e66366f..3735abd 100644
--- a/arch/parisc/kernel/syscall_table.S
+++ b/arch/parisc/kernel/syscall_table.S
@@ -259,7 +259,7 @@
ENTRY_SAME(ni_syscall) /* query_module */
ENTRY_SAME(poll)
/* structs contain pointers and an in_addr... */
- ENTRY_COMP(nfsservctl)
+ ENTRY_SAME(ni_syscall) /* was nfsservctl */
ENTRY_SAME(setresgid) /* 170 */
ENTRY_SAME(getresgid)
ENTRY_SAME(prctl)
diff --git a/arch/powerpc/boot/dts/p1023rds.dts b/arch/powerpc/boot/dts/p1023rds.dts
index bfa96aa..d9b7767 100644
--- a/arch/powerpc/boot/dts/p1023rds.dts
+++ b/arch/powerpc/boot/dts/p1023rds.dts
@@ -387,7 +387,7 @@
#size-cells = <1>;
compatible = "cfi-flash";
reg = <0x0 0x0 0x02000000>;
- bank-width = <1>;
+ bank-width = <2>;
device-width = <1>;
partition@0 {
label = "ramdisk";
diff --git a/arch/powerpc/configs/85xx/p1023rds_defconfig b/arch/powerpc/configs/85xx/p1023rds_defconfig
index 980ff8f..3ff5a81 100644
--- a/arch/powerpc/configs/85xx/p1023rds_defconfig
+++ b/arch/powerpc/configs/85xx/p1023rds_defconfig
@@ -171,3 +171,4 @@
CONFIG_CRYPTO_SHA512=y
CONFIG_CRYPTO_AES=y
# CONFIG_CRYPTO_ANSI_CPRNG is not set
+CONFIG_CRYPTO_DEV_FSL_CAAM=y
diff --git a/arch/powerpc/configs/corenet32_smp_defconfig b/arch/powerpc/configs/corenet32_smp_defconfig
index 10562a5..4311d02 100644
--- a/arch/powerpc/configs/corenet32_smp_defconfig
+++ b/arch/powerpc/configs/corenet32_smp_defconfig
@@ -185,3 +185,4 @@
CONFIG_CRYPTO_SHA512=y
CONFIG_CRYPTO_AES=y
# CONFIG_CRYPTO_ANSI_CPRNG is not set
+CONFIG_CRYPTO_DEV_FSL_CAAM=y
diff --git a/arch/powerpc/configs/corenet64_smp_defconfig b/arch/powerpc/configs/corenet64_smp_defconfig
index d322835..c92c204 100644
--- a/arch/powerpc/configs/corenet64_smp_defconfig
+++ b/arch/powerpc/configs/corenet64_smp_defconfig
@@ -100,5 +100,8 @@
CONFIG_SYSCTL_SYSCALL_CHECK=y
CONFIG_VIRQ_DEBUG=y
CONFIG_CRYPTO_PCBC=m
+CONFIG_CRYPTO_SHA256=y
+CONFIG_CRYPTO_SHA512=y
+CONFIG_CRYPTO_AES=y
# CONFIG_CRYPTO_ANSI_CPRNG is not set
-CONFIG_CRYPTO_DEV_TALITOS=y
+CONFIG_CRYPTO_DEV_FSL_CAAM=y
diff --git a/arch/powerpc/configs/mpc85xx_defconfig b/arch/powerpc/configs/mpc85xx_defconfig
index fcd85d2..a3467bf 100644
--- a/arch/powerpc/configs/mpc85xx_defconfig
+++ b/arch/powerpc/configs/mpc85xx_defconfig
@@ -139,6 +139,7 @@
CONFIG_SND_INTEL8X0=y
# CONFIG_SND_PPC is not set
# CONFIG_SND_USB is not set
+CONFIG_SND_SOC=y
CONFIG_HID_A4TECH=y
CONFIG_HID_APPLE=y
CONFIG_HID_BELKIN=y
diff --git a/arch/powerpc/configs/mpc85xx_smp_defconfig b/arch/powerpc/configs/mpc85xx_smp_defconfig
index 908c941..9693f6e 100644
--- a/arch/powerpc/configs/mpc85xx_smp_defconfig
+++ b/arch/powerpc/configs/mpc85xx_smp_defconfig
@@ -140,6 +140,7 @@
CONFIG_SND_INTEL8X0=y
# CONFIG_SND_PPC is not set
# CONFIG_SND_USB is not set
+CONFIG_SND_SOC=y
CONFIG_HID_A4TECH=y
CONFIG_HID_APPLE=y
CONFIG_HID_BELKIN=y
diff --git a/arch/powerpc/include/asm/systbl.h b/arch/powerpc/include/asm/systbl.h
index f6736b7..fa0d27a 100644
--- a/arch/powerpc/include/asm/systbl.h
+++ b/arch/powerpc/include/asm/systbl.h
@@ -171,7 +171,7 @@
SYSCALL_SPU(getresuid)
SYSCALL(ni_syscall)
SYSCALL_SPU(poll)
-COMPAT_SYS(nfsservctl)
+SYSCALL(ni_syscall)
SYSCALL_SPU(setresgid)
SYSCALL_SPU(getresgid)
COMPAT_SYS_SPU(prctl)
diff --git a/arch/powerpc/sysdev/fsl_rio.c b/arch/powerpc/sysdev/fsl_rio.c
index 2de8551..c65f75a 100644
--- a/arch/powerpc/sysdev/fsl_rio.c
+++ b/arch/powerpc/sysdev/fsl_rio.c
@@ -54,6 +54,7 @@
#define ODSR_CLEAR 0x1c00
#define LTLEECSR_ENABLE_ALL 0xFFC000FC
#define ESCSR_CLEAR 0x07120204
+#define IECSR_CLEAR 0x80000000
#define RIO_PORT1_EDCSR 0x0640
#define RIO_PORT2_EDCSR 0x0680
@@ -1089,11 +1090,11 @@
if (offset == 0) {
out_be32((u32 *)(rio_regs_win + RIO_PORT1_EDCSR), 0);
- out_be32((u32 *)(rio_regs_win + RIO_PORT1_IECSR), 0);
+ out_be32((u32 *)(rio_regs_win + RIO_PORT1_IECSR), IECSR_CLEAR);
out_be32((u32 *)(rio_regs_win + RIO_ESCSR), ESCSR_CLEAR);
} else {
out_be32((u32 *)(rio_regs_win + RIO_PORT2_EDCSR), 0);
- out_be32((u32 *)(rio_regs_win + RIO_PORT2_IECSR), 0);
+ out_be32((u32 *)(rio_regs_win + RIO_PORT2_IECSR), IECSR_CLEAR);
out_be32((u32 *)(rio_regs_win + RIO_PORT2_ESCSR), ESCSR_CLEAR);
}
}
diff --git a/arch/s390/kernel/compat_wrapper.S b/arch/s390/kernel/compat_wrapper.S
index 08ab9aa..7526db6 100644
--- a/arch/s390/kernel/compat_wrapper.S
+++ b/arch/s390/kernel/compat_wrapper.S
@@ -665,12 +665,6 @@
lgfr %r4,%r4 # long
jg sys_poll # branch to system call
-ENTRY(compat_sys_nfsservctl_wrapper)
- lgfr %r2,%r2 # int
- llgtr %r3,%r3 # struct compat_nfsctl_arg*
- llgtr %r4,%r4 # union compat_nfsctl_res*
- jg compat_sys_nfsservctl # branch to system call
-
ENTRY(sys32_setresgid16_wrapper)
llgfr %r2,%r2 # __kernel_old_gid_emu31_t
llgfr %r3,%r3 # __kernel_old_gid_emu31_t
diff --git a/arch/s390/kernel/early.c b/arch/s390/kernel/early.c
index 068f846..f297456 100644
--- a/arch/s390/kernel/early.c
+++ b/arch/s390/kernel/early.c
@@ -396,17 +396,19 @@
static __init void rescue_initrd(void)
{
#ifdef CONFIG_BLK_DEV_INITRD
+ unsigned long min_initrd_addr = (unsigned long) _end + (4UL << 20);
/*
- * Move the initrd right behind the bss section in case it starts
- * within the bss section. So we don't overwrite it when the bss
- * section gets cleared.
+ * Just like in case of IPL from VM reader we make sure there is a
+ * gap of 4MB between end of kernel and start of initrd.
+ * That way we can also be sure that saving an NSS will succeed,
+ * which however only requires different segments.
*/
if (!INITRD_START || !INITRD_SIZE)
return;
- if (INITRD_START >= (unsigned long) __bss_stop)
+ if (INITRD_START >= min_initrd_addr)
return;
- memmove(__bss_stop, (void *) INITRD_START, INITRD_SIZE);
- INITRD_START = (unsigned long) __bss_stop;
+ memmove((void *) min_initrd_addr, (void *) INITRD_START, INITRD_SIZE);
+ INITRD_START = min_initrd_addr;
#endif
}
diff --git a/arch/s390/kernel/ipl.c b/arch/s390/kernel/ipl.c
index 04361d5..48c7102 100644
--- a/arch/s390/kernel/ipl.c
+++ b/arch/s390/kernel/ipl.c
@@ -1220,7 +1220,7 @@
/* sysfs: create fcp kset for mixing attr group and bin attrs */
reipl_fcp_kset = kset_create_and_add(IPL_FCP_STR, NULL,
&reipl_kset->kobj);
- if (!reipl_kset) {
+ if (!reipl_fcp_kset) {
free_page((unsigned long) reipl_block_fcp);
return -ENOMEM;
}
@@ -1618,7 +1618,8 @@
static void stop_run(struct shutdown_trigger *trigger)
{
- if (strcmp(trigger->name, ON_PANIC_STR) == 0)
+ if (strcmp(trigger->name, ON_PANIC_STR) == 0 ||
+ strcmp(trigger->name, ON_RESTART_STR) == 0)
disabled_wait((unsigned long) __builtin_return_address(0));
while (sigp(smp_processor_id(), sigp_stop) == sigp_busy)
cpu_relax();
@@ -1717,7 +1718,7 @@
/* on restart */
static struct shutdown_trigger on_restart_trigger = {ON_RESTART_STR,
- &reipl_action};
+ &stop_action};
static ssize_t on_restart_show(struct kobject *kobj,
struct kobj_attribute *attr, char *page)
diff --git a/arch/s390/kernel/syscalls.S b/arch/s390/kernel/syscalls.S
index 6ee39ef..73eb08c 100644
--- a/arch/s390/kernel/syscalls.S
+++ b/arch/s390/kernel/syscalls.S
@@ -177,7 +177,7 @@
NI_SYSCALL /* for vm86 */
NI_SYSCALL /* old sys_query_module */
SYSCALL(sys_poll,sys_poll,sys32_poll_wrapper)
-SYSCALL(sys_nfsservctl,sys_nfsservctl,compat_sys_nfsservctl_wrapper)
+NI_SYSCALL /* old nfsservctl */
SYSCALL(sys_setresgid16,sys_ni_syscall,sys32_setresgid16_wrapper) /* 170 old setresgid16 syscall */
SYSCALL(sys_getresgid16,sys_ni_syscall,sys32_getresgid16_wrapper) /* old getresgid16 syscall */
SYSCALL(sys_prctl,sys_prctl,sys32_prctl_wrapper)
diff --git a/arch/sh/include/asm/ptrace.h b/arch/sh/include/asm/ptrace.h
index b97baf8..2d3679b 100644
--- a/arch/sh/include/asm/ptrace.h
+++ b/arch/sh/include/asm/ptrace.h
@@ -123,7 +123,7 @@
struct perf_event;
struct perf_sample_data;
-extern void ptrace_triggered(struct perf_event *bp, int nmi,
+extern void ptrace_triggered(struct perf_event *bp,
struct perf_sample_data *data, struct pt_regs *regs);
#define task_pt_regs(task) \
diff --git a/arch/sh/kernel/cpu/sh4a/setup-sh7757.c b/arch/sh/kernel/cpu/sh4a/setup-sh7757.c
index e915dea..0555929 100644
--- a/arch/sh/kernel/cpu/sh4a/setup-sh7757.c
+++ b/arch/sh/kernel/cpu/sh4a/setup-sh7757.c
@@ -15,6 +15,7 @@
#include <linux/serial_sci.h>
#include <linux/io.h>
#include <linux/mm.h>
+#include <linux/dma-mapping.h>
#include <linux/sh_timer.h>
#include <linux/sh_dma.h>
diff --git a/arch/sh/kernel/idle.c b/arch/sh/kernel/idle.c
index 32114e0..db4ecd7 100644
--- a/arch/sh/kernel/idle.c
+++ b/arch/sh/kernel/idle.c
@@ -22,7 +22,7 @@
#include <linux/atomic.h>
#include <asm/smp.h>
-static void (*pm_idle)(void);
+void (*pm_idle)(void);
static int hlt_counter;
diff --git a/arch/sh/kernel/syscalls_32.S b/arch/sh/kernel/syscalls_32.S
index 39b051d..293e39c 100644
--- a/arch/sh/kernel/syscalls_32.S
+++ b/arch/sh/kernel/syscalls_32.S
@@ -185,7 +185,7 @@
.long sys_ni_syscall /* vm86 */
.long sys_ni_syscall /* old "query_module" */
.long sys_poll
- .long sys_nfsservctl
+ .long sys_ni_syscall /* was nfsservctl */
.long sys_setresgid16 /* 170 */
.long sys_getresgid16
.long sys_prctl
diff --git a/arch/sh/kernel/syscalls_64.S b/arch/sh/kernel/syscalls_64.S
index 089c4d8..ceb34b9 100644
--- a/arch/sh/kernel/syscalls_64.S
+++ b/arch/sh/kernel/syscalls_64.S
@@ -189,7 +189,7 @@
.long sys_ni_syscall /* vm86 */
.long sys_ni_syscall /* old "query_module" */
.long sys_poll
- .long sys_nfsservctl
+ .long sys_ni_syscall /* was nfsservctl */
.long sys_setresgid16 /* 170 */
.long sys_getresgid16
.long sys_prctl
diff --git a/arch/sh/kernel/traps_32.c b/arch/sh/kernel/traps_32.c
index d9006f8..7bbef95 100644
--- a/arch/sh/kernel/traps_32.c
+++ b/arch/sh/kernel/traps_32.c
@@ -316,6 +316,35 @@
break;
}
break;
+
+ case 9: /* mov.w @(disp,PC),Rn */
+ srcu = (unsigned char __user *)regs->pc;
+ srcu += 4;
+ srcu += (instruction & 0x00FF) << 1;
+ dst = (unsigned char *)rn;
+ *(unsigned long *)dst = 0;
+
+#if !defined(__LITTLE_ENDIAN__)
+ dst += 2;
+#endif
+
+ if (ma->from(dst, srcu, 2))
+ goto fetch_fault;
+ sign_extend(2, dst);
+ ret = 0;
+ break;
+
+ case 0xd: /* mov.l @(disp,PC),Rn */
+ srcu = (unsigned char __user *)(regs->pc & ~0x3);
+ srcu += 4;
+ srcu += (instruction & 0x00FF) << 2;
+ dst = (unsigned char *)rn;
+ *(unsigned long *)dst = 0;
+
+ if (ma->from(dst, srcu, 4))
+ goto fetch_fault;
+ ret = 0;
+ break;
}
return ret;
@@ -466,6 +495,7 @@
case 0x0500: /* mov.w @(disp,Rm),R0 */
goto simple;
case 0x0B00: /* bf lab - no delayslot*/
+ ret = 0;
break;
case 0x0F00: /* bf/s lab */
ret = handle_delayslot(regs, instruction, ma);
@@ -479,6 +509,7 @@
}
break;
case 0x0900: /* bt lab - no delayslot */
+ ret = 0;
break;
case 0x0D00: /* bt/s lab */
ret = handle_delayslot(regs, instruction, ma);
@@ -494,6 +525,9 @@
}
break;
+ case 0x9000: /* mov.w @(disp,Rm),Rn */
+ goto simple;
+
case 0xA000: /* bra label */
ret = handle_delayslot(regs, instruction, ma);
if (ret==0)
@@ -507,6 +541,9 @@
regs->pc += SH_PC_12BIT_OFFSET(instruction);
}
break;
+
+ case 0xD000: /* mov.l @(disp,Rm),Rn */
+ goto simple;
}
return ret;
diff --git a/arch/sparc/include/asm/sigcontext.h b/arch/sparc/include/asm/sigcontext.h
index a1607d18..69914d7 100644
--- a/arch/sparc/include/asm/sigcontext.h
+++ b/arch/sparc/include/asm/sigcontext.h
@@ -45,6 +45,19 @@
int si_mask;
} __siginfo32_t;
+#define __SIGC_MAXWIN 7
+
+typedef struct {
+ unsigned long locals[8];
+ unsigned long ins[8];
+} __siginfo_reg_window;
+
+typedef struct {
+ int wsaved;
+ __siginfo_reg_window reg_window[__SIGC_MAXWIN];
+ unsigned long rwbuf_stkptrs[__SIGC_MAXWIN];
+} __siginfo_rwin_t;
+
#ifdef CONFIG_SPARC64
typedef struct {
unsigned int si_float_regs [64];
@@ -73,6 +86,7 @@
unsigned long ss_size;
} sigc_stack;
unsigned long sigc_mask;
+ __siginfo_rwin_t * sigc_rwin_save;
};
#else
diff --git a/arch/sparc/kernel/Makefile b/arch/sparc/kernel/Makefile
index b90b4a1..cb85458 100644
--- a/arch/sparc/kernel/Makefile
+++ b/arch/sparc/kernel/Makefile
@@ -32,6 +32,7 @@
obj-y += process_$(BITS).o
obj-y += signal_$(BITS).o
+obj-y += sigutil_$(BITS).o
obj-$(CONFIG_SPARC32) += ioport.o
obj-y += setup_$(BITS).o
obj-y += idprom.o
diff --git a/arch/sparc/kernel/irq.h b/arch/sparc/kernel/irq.h
index 100b9c2..4285112 100644
--- a/arch/sparc/kernel/irq.h
+++ b/arch/sparc/kernel/irq.h
@@ -88,7 +88,7 @@
#define set_irq_udt(cpu) BTFIXUP_CALL(set_irq_udt)(cpu)
/* All SUN4D IPIs are sent on this IRQ, may be shared with hard IRQs */
-#define SUN4D_IPI_IRQ 14
+#define SUN4D_IPI_IRQ 13
extern void sun4d_ipi_interrupt(void);
diff --git a/arch/sparc/kernel/setup_64.c b/arch/sparc/kernel/setup_64.c
index 3e9daea..3c5bb78 100644
--- a/arch/sparc/kernel/setup_64.c
+++ b/arch/sparc/kernel/setup_64.c
@@ -440,8 +440,14 @@
cap |= AV_SPARC_VIS;
if (tlb_type == cheetah || tlb_type == cheetah_plus)
cap |= AV_SPARC_VIS | AV_SPARC_VIS2;
- if (tlb_type == cheetah_plus)
- cap |= AV_SPARC_POPC;
+ if (tlb_type == cheetah_plus) {
+ unsigned long impl, ver;
+
+ __asm__ __volatile__("rdpr %%ver, %0" : "=r" (ver));
+ impl = ((ver >> 32) & 0xffff);
+ if (impl == PANTHER_IMPL)
+ cap |= AV_SPARC_POPC;
+ }
if (tlb_type == hypervisor) {
if (sun4v_chip_type == SUN4V_CHIP_NIAGARA1)
cap |= AV_SPARC_ASI_BLK_INIT;
diff --git a/arch/sparc/kernel/signal32.c b/arch/sparc/kernel/signal32.c
index 75fad42..1ba95af 100644
--- a/arch/sparc/kernel/signal32.c
+++ b/arch/sparc/kernel/signal32.c
@@ -29,6 +29,8 @@
#include <asm/visasm.h>
#include <asm/compat_signal.h>
+#include "sigutil.h"
+
#define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP)))
/* This magic should be in g_upper[0] for all upper parts
@@ -44,14 +46,14 @@
struct signal_frame32 {
struct sparc_stackf32 ss;
__siginfo32_t info;
- /* __siginfo_fpu32_t * */ u32 fpu_save;
+ /* __siginfo_fpu_t * */ u32 fpu_save;
unsigned int insns[2];
unsigned int extramask[_COMPAT_NSIG_WORDS - 1];
unsigned int extra_size; /* Should be sizeof(siginfo_extra_v8plus_t) */
/* Only valid if (info.si_regs.psr & (PSR_VERS|PSR_IMPL)) == PSR_V8PLUS */
siginfo_extra_v8plus_t v8plus;
- __siginfo_fpu_t fpu_state;
-};
+ /* __siginfo_rwin_t * */u32 rwin_save;
+} __attribute__((aligned(8)));
typedef struct compat_siginfo{
int si_signo;
@@ -110,18 +112,14 @@
compat_siginfo_t info;
struct pt_regs32 regs;
compat_sigset_t mask;
- /* __siginfo_fpu32_t * */ u32 fpu_save;
+ /* __siginfo_fpu_t * */ u32 fpu_save;
unsigned int insns[2];
stack_t32 stack;
unsigned int extra_size; /* Should be sizeof(siginfo_extra_v8plus_t) */
/* Only valid if (regs.psr & (PSR_VERS|PSR_IMPL)) == PSR_V8PLUS */
siginfo_extra_v8plus_t v8plus;
- __siginfo_fpu_t fpu_state;
-};
-
-/* Align macros */
-#define SF_ALIGNEDSZ (((sizeof(struct signal_frame32) + 15) & (~15)))
-#define RT_ALIGNEDSZ (((sizeof(struct rt_signal_frame32) + 15) & (~15)))
+ /* __siginfo_rwin_t * */u32 rwin_save;
+} __attribute__((aligned(8)));
int copy_siginfo_to_user32(compat_siginfo_t __user *to, siginfo_t *from)
{
@@ -192,30 +190,13 @@
return 0;
}
-static int restore_fpu_state32(struct pt_regs *regs, __siginfo_fpu_t __user *fpu)
-{
- unsigned long *fpregs = current_thread_info()->fpregs;
- unsigned long fprs;
- int err;
-
- err = __get_user(fprs, &fpu->si_fprs);
- fprs_write(0);
- regs->tstate &= ~TSTATE_PEF;
- if (fprs & FPRS_DL)
- err |= copy_from_user(fpregs, &fpu->si_float_regs[0], (sizeof(unsigned int) * 32));
- if (fprs & FPRS_DU)
- err |= copy_from_user(fpregs+16, &fpu->si_float_regs[32], (sizeof(unsigned int) * 32));
- err |= __get_user(current_thread_info()->xfsr[0], &fpu->si_fsr);
- err |= __get_user(current_thread_info()->gsr[0], &fpu->si_gsr);
- current_thread_info()->fpsaved[0] |= fprs;
- return err;
-}
-
void do_sigreturn32(struct pt_regs *regs)
{
struct signal_frame32 __user *sf;
+ compat_uptr_t fpu_save;
+ compat_uptr_t rwin_save;
unsigned int psr;
- unsigned pc, npc, fpu_save;
+ unsigned pc, npc;
sigset_t set;
unsigned seta[_COMPAT_NSIG_WORDS];
int err, i;
@@ -273,8 +254,13 @@
pt_regs_clear_syscall(regs);
err |= __get_user(fpu_save, &sf->fpu_save);
- if (fpu_save)
- err |= restore_fpu_state32(regs, &sf->fpu_state);
+ if (!err && fpu_save)
+ err |= restore_fpu_state(regs, compat_ptr(fpu_save));
+ err |= __get_user(rwin_save, &sf->rwin_save);
+ if (!err && rwin_save) {
+ if (restore_rwin_state(compat_ptr(rwin_save)))
+ goto segv;
+ }
err |= __get_user(seta[0], &sf->info.si_mask);
err |= copy_from_user(seta+1, &sf->extramask,
(_COMPAT_NSIG_WORDS - 1) * sizeof(unsigned int));
@@ -300,7 +286,9 @@
asmlinkage void do_rt_sigreturn32(struct pt_regs *regs)
{
struct rt_signal_frame32 __user *sf;
- unsigned int psr, pc, npc, fpu_save, u_ss_sp;
+ unsigned int psr, pc, npc, u_ss_sp;
+ compat_uptr_t fpu_save;
+ compat_uptr_t rwin_save;
mm_segment_t old_fs;
sigset_t set;
compat_sigset_t seta;
@@ -359,8 +347,8 @@
pt_regs_clear_syscall(regs);
err |= __get_user(fpu_save, &sf->fpu_save);
- if (fpu_save)
- err |= restore_fpu_state32(regs, &sf->fpu_state);
+ if (!err && fpu_save)
+ err |= restore_fpu_state(regs, compat_ptr(fpu_save));
err |= copy_from_user(&seta, &sf->mask, sizeof(compat_sigset_t));
err |= __get_user(u_ss_sp, &sf->stack.ss_sp);
st.ss_sp = compat_ptr(u_ss_sp);
@@ -376,6 +364,12 @@
do_sigaltstack((stack_t __user *) &st, NULL, (unsigned long)sf);
set_fs(old_fs);
+ err |= __get_user(rwin_save, &sf->rwin_save);
+ if (!err && rwin_save) {
+ if (restore_rwin_state(compat_ptr(rwin_save)))
+ goto segv;
+ }
+
switch (_NSIG_WORDS) {
case 4: set.sig[3] = seta.sig[6] + (((long)seta.sig[7]) << 32);
case 3: set.sig[2] = seta.sig[4] + (((long)seta.sig[5]) << 32);
@@ -433,26 +427,6 @@
return (void __user *) sp;
}
-static int save_fpu_state32(struct pt_regs *regs, __siginfo_fpu_t __user *fpu)
-{
- unsigned long *fpregs = current_thread_info()->fpregs;
- unsigned long fprs;
- int err = 0;
-
- fprs = current_thread_info()->fpsaved[0];
- if (fprs & FPRS_DL)
- err |= copy_to_user(&fpu->si_float_regs[0], fpregs,
- (sizeof(unsigned int) * 32));
- if (fprs & FPRS_DU)
- err |= copy_to_user(&fpu->si_float_regs[32], fpregs+16,
- (sizeof(unsigned int) * 32));
- err |= __put_user(current_thread_info()->xfsr[0], &fpu->si_fsr);
- err |= __put_user(current_thread_info()->gsr[0], &fpu->si_gsr);
- err |= __put_user(fprs, &fpu->si_fprs);
-
- return err;
-}
-
/* The I-cache flush instruction only works in the primary ASI, which
* right now is the nucleus, aka. kernel space.
*
@@ -515,18 +489,23 @@
int signo, sigset_t *oldset)
{
struct signal_frame32 __user *sf;
+ int i, err, wsaved;
+ void __user *tail;
int sigframe_size;
u32 psr;
- int i, err;
unsigned int seta[_COMPAT_NSIG_WORDS];
/* 1. Make sure everything is clean */
synchronize_user_stack();
save_and_clear_fpu();
- sigframe_size = SF_ALIGNEDSZ;
- if (!(current_thread_info()->fpsaved[0] & FPRS_FEF))
- sigframe_size -= sizeof(__siginfo_fpu_t);
+ wsaved = get_thread_wsaved();
+
+ sigframe_size = sizeof(*sf);
+ if (current_thread_info()->fpsaved[0] & FPRS_FEF)
+ sigframe_size += sizeof(__siginfo_fpu_t);
+ if (wsaved)
+ sigframe_size += sizeof(__siginfo_rwin_t);
sf = (struct signal_frame32 __user *)
get_sigframe(&ka->sa, regs, sigframe_size);
@@ -534,8 +513,7 @@
if (invalid_frame_pointer(sf, sigframe_size))
goto sigill;
- if (get_thread_wsaved() != 0)
- goto sigill;
+ tail = (sf + 1);
/* 2. Save the current process state */
if (test_thread_flag(TIF_32BIT)) {
@@ -560,11 +538,22 @@
&sf->v8plus.asi);
if (psr & PSR_EF) {
- err |= save_fpu_state32(regs, &sf->fpu_state);
- err |= __put_user((u64)&sf->fpu_state, &sf->fpu_save);
+ __siginfo_fpu_t __user *fp = tail;
+ tail += sizeof(*fp);
+ err |= save_fpu_state(regs, fp);
+ err |= __put_user((u64)fp, &sf->fpu_save);
} else {
err |= __put_user(0, &sf->fpu_save);
}
+ if (wsaved) {
+ __siginfo_rwin_t __user *rwp = tail;
+ tail += sizeof(*rwp);
+ err |= save_rwin_state(wsaved, rwp);
+ err |= __put_user((u64)rwp, &sf->rwin_save);
+ set_thread_wsaved(0);
+ } else {
+ err |= __put_user(0, &sf->rwin_save);
+ }
switch (_NSIG_WORDS) {
case 4: seta[7] = (oldset->sig[3] >> 32);
@@ -580,10 +569,21 @@
err |= __copy_to_user(sf->extramask, seta + 1,
(_COMPAT_NSIG_WORDS - 1) * sizeof(unsigned int));
- err |= copy_in_user((u32 __user *)sf,
- (u32 __user *)(regs->u_regs[UREG_FP]),
- sizeof(struct reg_window32));
-
+ if (!wsaved) {
+ err |= copy_in_user((u32 __user *)sf,
+ (u32 __user *)(regs->u_regs[UREG_FP]),
+ sizeof(struct reg_window32));
+ } else {
+ struct reg_window *rp;
+
+ rp = ¤t_thread_info()->reg_window[wsaved - 1];
+ for (i = 0; i < 8; i++)
+ err |= __put_user(rp->locals[i], &sf->ss.locals[i]);
+ for (i = 0; i < 6; i++)
+ err |= __put_user(rp->ins[i], &sf->ss.ins[i]);
+ err |= __put_user(rp->ins[6], &sf->ss.fp);
+ err |= __put_user(rp->ins[7], &sf->ss.callers_pc);
+ }
if (err)
goto sigsegv;
@@ -613,7 +613,6 @@
err |= __put_user(0x91d02010, &sf->insns[1]); /*t 0x10*/
if (err)
goto sigsegv;
-
flush_signal_insns(address);
}
return 0;
@@ -632,18 +631,23 @@
siginfo_t *info)
{
struct rt_signal_frame32 __user *sf;
+ int i, err, wsaved;
+ void __user *tail;
int sigframe_size;
u32 psr;
- int i, err;
compat_sigset_t seta;
/* 1. Make sure everything is clean */
synchronize_user_stack();
save_and_clear_fpu();
- sigframe_size = RT_ALIGNEDSZ;
- if (!(current_thread_info()->fpsaved[0] & FPRS_FEF))
- sigframe_size -= sizeof(__siginfo_fpu_t);
+ wsaved = get_thread_wsaved();
+
+ sigframe_size = sizeof(*sf);
+ if (current_thread_info()->fpsaved[0] & FPRS_FEF)
+ sigframe_size += sizeof(__siginfo_fpu_t);
+ if (wsaved)
+ sigframe_size += sizeof(__siginfo_rwin_t);
sf = (struct rt_signal_frame32 __user *)
get_sigframe(&ka->sa, regs, sigframe_size);
@@ -651,8 +655,7 @@
if (invalid_frame_pointer(sf, sigframe_size))
goto sigill;
- if (get_thread_wsaved() != 0)
- goto sigill;
+ tail = (sf + 1);
/* 2. Save the current process state */
if (test_thread_flag(TIF_32BIT)) {
@@ -677,11 +680,22 @@
&sf->v8plus.asi);
if (psr & PSR_EF) {
- err |= save_fpu_state32(regs, &sf->fpu_state);
- err |= __put_user((u64)&sf->fpu_state, &sf->fpu_save);
+ __siginfo_fpu_t __user *fp = tail;
+ tail += sizeof(*fp);
+ err |= save_fpu_state(regs, fp);
+ err |= __put_user((u64)fp, &sf->fpu_save);
} else {
err |= __put_user(0, &sf->fpu_save);
}
+ if (wsaved) {
+ __siginfo_rwin_t __user *rwp = tail;
+ tail += sizeof(*rwp);
+ err |= save_rwin_state(wsaved, rwp);
+ err |= __put_user((u64)rwp, &sf->rwin_save);
+ set_thread_wsaved(0);
+ } else {
+ err |= __put_user(0, &sf->rwin_save);
+ }
/* Update the siginfo structure. */
err |= copy_siginfo_to_user32(&sf->info, info);
@@ -703,9 +717,21 @@
}
err |= __copy_to_user(&sf->mask, &seta, sizeof(compat_sigset_t));
- err |= copy_in_user((u32 __user *)sf,
- (u32 __user *)(regs->u_regs[UREG_FP]),
- sizeof(struct reg_window32));
+ if (!wsaved) {
+ err |= copy_in_user((u32 __user *)sf,
+ (u32 __user *)(regs->u_regs[UREG_FP]),
+ sizeof(struct reg_window32));
+ } else {
+ struct reg_window *rp;
+
+ rp = ¤t_thread_info()->reg_window[wsaved - 1];
+ for (i = 0; i < 8; i++)
+ err |= __put_user(rp->locals[i], &sf->ss.locals[i]);
+ for (i = 0; i < 6; i++)
+ err |= __put_user(rp->ins[i], &sf->ss.ins[i]);
+ err |= __put_user(rp->ins[6], &sf->ss.fp);
+ err |= __put_user(rp->ins[7], &sf->ss.callers_pc);
+ }
if (err)
goto sigsegv;
diff --git a/arch/sparc/kernel/signal_32.c b/arch/sparc/kernel/signal_32.c
index 5e5c5fd..04ede8f 100644
--- a/arch/sparc/kernel/signal_32.c
+++ b/arch/sparc/kernel/signal_32.c
@@ -26,6 +26,8 @@
#include <asm/pgtable.h>
#include <asm/cacheflush.h> /* flush_sig_insns */
+#include "sigutil.h"
+
#define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP)))
extern void fpsave(unsigned long *fpregs, unsigned long *fsr,
@@ -39,8 +41,8 @@
unsigned long insns[2] __attribute__ ((aligned (8)));
unsigned int extramask[_NSIG_WORDS - 1];
unsigned int extra_size; /* Should be 0 */
- __siginfo_fpu_t fpu_state;
-};
+ __siginfo_rwin_t __user *rwin_save;
+} __attribute__((aligned(8)));
struct rt_signal_frame {
struct sparc_stackf ss;
@@ -51,8 +53,8 @@
unsigned int insns[2];
stack_t stack;
unsigned int extra_size; /* Should be 0 */
- __siginfo_fpu_t fpu_state;
-};
+ __siginfo_rwin_t __user *rwin_save;
+} __attribute__((aligned(8)));
/* Align macros */
#define SF_ALIGNEDSZ (((sizeof(struct signal_frame) + 7) & (~7)))
@@ -79,43 +81,13 @@
return _sigpause_common(set);
}
-static inline int
-restore_fpu_state(struct pt_regs *regs, __siginfo_fpu_t __user *fpu)
-{
- int err;
-#ifdef CONFIG_SMP
- if (test_tsk_thread_flag(current, TIF_USEDFPU))
- regs->psr &= ~PSR_EF;
-#else
- if (current == last_task_used_math) {
- last_task_used_math = NULL;
- regs->psr &= ~PSR_EF;
- }
-#endif
- set_used_math();
- clear_tsk_thread_flag(current, TIF_USEDFPU);
-
- if (!access_ok(VERIFY_READ, fpu, sizeof(*fpu)))
- return -EFAULT;
-
- err = __copy_from_user(¤t->thread.float_regs[0], &fpu->si_float_regs[0],
- (sizeof(unsigned long) * 32));
- err |= __get_user(current->thread.fsr, &fpu->si_fsr);
- err |= __get_user(current->thread.fpqdepth, &fpu->si_fpqdepth);
- if (current->thread.fpqdepth != 0)
- err |= __copy_from_user(¤t->thread.fpqueue[0],
- &fpu->si_fpqueue[0],
- ((sizeof(unsigned long) +
- (sizeof(unsigned long *)))*16));
- return err;
-}
-
asmlinkage void do_sigreturn(struct pt_regs *regs)
{
struct signal_frame __user *sf;
unsigned long up_psr, pc, npc;
sigset_t set;
__siginfo_fpu_t __user *fpu_save;
+ __siginfo_rwin_t __user *rwin_save;
int err;
/* Always make any pending restarted system calls return -EINTR */
@@ -150,9 +122,11 @@
pt_regs_clear_syscall(regs);
err |= __get_user(fpu_save, &sf->fpu_save);
-
if (fpu_save)
err |= restore_fpu_state(regs, fpu_save);
+ err |= __get_user(rwin_save, &sf->rwin_save);
+ if (rwin_save)
+ err |= restore_rwin_state(rwin_save);
/* This is pretty much atomic, no amount locking would prevent
* the races which exist anyways.
@@ -180,6 +154,7 @@
struct rt_signal_frame __user *sf;
unsigned int psr, pc, npc;
__siginfo_fpu_t __user *fpu_save;
+ __siginfo_rwin_t __user *rwin_save;
mm_segment_t old_fs;
sigset_t set;
stack_t st;
@@ -207,8 +182,7 @@
pt_regs_clear_syscall(regs);
err |= __get_user(fpu_save, &sf->fpu_save);
-
- if (fpu_save)
+ if (!err && fpu_save)
err |= restore_fpu_state(regs, fpu_save);
err |= __copy_from_user(&set, &sf->mask, sizeof(sigset_t));
@@ -228,6 +202,12 @@
do_sigaltstack((const stack_t __user *) &st, NULL, (unsigned long)sf);
set_fs(old_fs);
+ err |= __get_user(rwin_save, &sf->rwin_save);
+ if (!err && rwin_save) {
+ if (restore_rwin_state(rwin_save))
+ goto segv;
+ }
+
sigdelsetmask(&set, ~_BLOCKABLE);
spin_lock_irq(¤t->sighand->siglock);
current->blocked = set;
@@ -280,53 +260,23 @@
return (void __user *) sp;
}
-static inline int
-save_fpu_state(struct pt_regs *regs, __siginfo_fpu_t __user *fpu)
-{
- int err = 0;
-#ifdef CONFIG_SMP
- if (test_tsk_thread_flag(current, TIF_USEDFPU)) {
- put_psr(get_psr() | PSR_EF);
- fpsave(¤t->thread.float_regs[0], ¤t->thread.fsr,
- ¤t->thread.fpqueue[0], ¤t->thread.fpqdepth);
- regs->psr &= ~(PSR_EF);
- clear_tsk_thread_flag(current, TIF_USEDFPU);
- }
-#else
- if (current == last_task_used_math) {
- put_psr(get_psr() | PSR_EF);
- fpsave(¤t->thread.float_regs[0], ¤t->thread.fsr,
- ¤t->thread.fpqueue[0], ¤t->thread.fpqdepth);
- last_task_used_math = NULL;
- regs->psr &= ~(PSR_EF);
- }
-#endif
- err |= __copy_to_user(&fpu->si_float_regs[0],
- ¤t->thread.float_regs[0],
- (sizeof(unsigned long) * 32));
- err |= __put_user(current->thread.fsr, &fpu->si_fsr);
- err |= __put_user(current->thread.fpqdepth, &fpu->si_fpqdepth);
- if (current->thread.fpqdepth != 0)
- err |= __copy_to_user(&fpu->si_fpqueue[0],
- ¤t->thread.fpqueue[0],
- ((sizeof(unsigned long) +
- (sizeof(unsigned long *)))*16));
- clear_used_math();
- return err;
-}
-
static int setup_frame(struct k_sigaction *ka, struct pt_regs *regs,
int signo, sigset_t *oldset)
{
struct signal_frame __user *sf;
- int sigframe_size, err;
+ int sigframe_size, err, wsaved;
+ void __user *tail;
/* 1. Make sure everything is clean */
synchronize_user_stack();
- sigframe_size = SF_ALIGNEDSZ;
- if (!used_math())
- sigframe_size -= sizeof(__siginfo_fpu_t);
+ wsaved = current_thread_info()->w_saved;
+
+ sigframe_size = sizeof(*sf);
+ if (used_math())
+ sigframe_size += sizeof(__siginfo_fpu_t);
+ if (wsaved)
+ sigframe_size += sizeof(__siginfo_rwin_t);
sf = (struct signal_frame __user *)
get_sigframe(&ka->sa, regs, sigframe_size);
@@ -334,8 +284,7 @@
if (invalid_frame_pointer(sf, sigframe_size))
goto sigill_and_return;
- if (current_thread_info()->w_saved != 0)
- goto sigill_and_return;
+ tail = sf + 1;
/* 2. Save the current process state */
err = __copy_to_user(&sf->info.si_regs, regs, sizeof(struct pt_regs));
@@ -343,17 +292,34 @@
err |= __put_user(0, &sf->extra_size);
if (used_math()) {
- err |= save_fpu_state(regs, &sf->fpu_state);
- err |= __put_user(&sf->fpu_state, &sf->fpu_save);
+ __siginfo_fpu_t __user *fp = tail;
+ tail += sizeof(*fp);
+ err |= save_fpu_state(regs, fp);
+ err |= __put_user(fp, &sf->fpu_save);
} else {
err |= __put_user(0, &sf->fpu_save);
}
+ if (wsaved) {
+ __siginfo_rwin_t __user *rwp = tail;
+ tail += sizeof(*rwp);
+ err |= save_rwin_state(wsaved, rwp);
+ err |= __put_user(rwp, &sf->rwin_save);
+ } else {
+ err |= __put_user(0, &sf->rwin_save);
+ }
err |= __put_user(oldset->sig[0], &sf->info.si_mask);
err |= __copy_to_user(sf->extramask, &oldset->sig[1],
(_NSIG_WORDS - 1) * sizeof(unsigned int));
- err |= __copy_to_user(sf, (char *) regs->u_regs[UREG_FP],
- sizeof(struct reg_window32));
+ if (!wsaved) {
+ err |= __copy_to_user(sf, (char *) regs->u_regs[UREG_FP],
+ sizeof(struct reg_window32));
+ } else {
+ struct reg_window32 *rp;
+
+ rp = ¤t_thread_info()->reg_window[wsaved - 1];
+ err |= __copy_to_user(sf, rp, sizeof(struct reg_window32));
+ }
if (err)
goto sigsegv;
@@ -399,21 +365,24 @@
int signo, sigset_t *oldset, siginfo_t *info)
{
struct rt_signal_frame __user *sf;
- int sigframe_size;
+ int sigframe_size, wsaved;
+ void __user *tail;
unsigned int psr;
int err;
synchronize_user_stack();
- sigframe_size = RT_ALIGNEDSZ;
- if (!used_math())
- sigframe_size -= sizeof(__siginfo_fpu_t);
+ wsaved = current_thread_info()->w_saved;
+ sigframe_size = sizeof(*sf);
+ if (used_math())
+ sigframe_size += sizeof(__siginfo_fpu_t);
+ if (wsaved)
+ sigframe_size += sizeof(__siginfo_rwin_t);
sf = (struct rt_signal_frame __user *)
get_sigframe(&ka->sa, regs, sigframe_size);
if (invalid_frame_pointer(sf, sigframe_size))
goto sigill;
- if (current_thread_info()->w_saved != 0)
- goto sigill;
+ tail = sf + 1;
err = __put_user(regs->pc, &sf->regs.pc);
err |= __put_user(regs->npc, &sf->regs.npc);
err |= __put_user(regs->y, &sf->regs.y);
@@ -425,11 +394,21 @@
err |= __put_user(0, &sf->extra_size);
if (psr & PSR_EF) {
- err |= save_fpu_state(regs, &sf->fpu_state);
- err |= __put_user(&sf->fpu_state, &sf->fpu_save);
+ __siginfo_fpu_t *fp = tail;
+ tail += sizeof(*fp);
+ err |= save_fpu_state(regs, fp);
+ err |= __put_user(fp, &sf->fpu_save);
} else {
err |= __put_user(0, &sf->fpu_save);
}
+ if (wsaved) {
+ __siginfo_rwin_t *rwp = tail;
+ tail += sizeof(*rwp);
+ err |= save_rwin_state(wsaved, rwp);
+ err |= __put_user(rwp, &sf->rwin_save);
+ } else {
+ err |= __put_user(0, &sf->rwin_save);
+ }
err |= __copy_to_user(&sf->mask, &oldset->sig[0], sizeof(sigset_t));
/* Setup sigaltstack */
@@ -437,8 +416,15 @@
err |= __put_user(sas_ss_flags(regs->u_regs[UREG_FP]), &sf->stack.ss_flags);
err |= __put_user(current->sas_ss_size, &sf->stack.ss_size);
- err |= __copy_to_user(sf, (char *) regs->u_regs[UREG_FP],
- sizeof(struct reg_window32));
+ if (!wsaved) {
+ err |= __copy_to_user(sf, (char *) regs->u_regs[UREG_FP],
+ sizeof(struct reg_window32));
+ } else {
+ struct reg_window32 *rp;
+
+ rp = ¤t_thread_info()->reg_window[wsaved - 1];
+ err |= __copy_to_user(sf, rp, sizeof(struct reg_window32));
+ }
err |= copy_siginfo_to_user(&sf->info, info);
diff --git a/arch/sparc/kernel/signal_64.c b/arch/sparc/kernel/signal_64.c
index 006fe45..47509df 100644
--- a/arch/sparc/kernel/signal_64.c
+++ b/arch/sparc/kernel/signal_64.c
@@ -34,6 +34,7 @@
#include "entry.h"
#include "systbls.h"
+#include "sigutil.h"
#define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP)))
@@ -236,7 +237,7 @@
__siginfo_fpu_t __user *fpu_save;
stack_t stack;
sigset_t mask;
- __siginfo_fpu_t fpu_state;
+ __siginfo_rwin_t *rwin_save;
};
static long _sigpause_common(old_sigset_t set)
@@ -266,33 +267,12 @@
return _sigpause_common(set);
}
-static inline int
-restore_fpu_state(struct pt_regs *regs, __siginfo_fpu_t __user *fpu)
-{
- unsigned long *fpregs = current_thread_info()->fpregs;
- unsigned long fprs;
- int err;
-
- err = __get_user(fprs, &fpu->si_fprs);
- fprs_write(0);
- regs->tstate &= ~TSTATE_PEF;
- if (fprs & FPRS_DL)
- err |= copy_from_user(fpregs, &fpu->si_float_regs[0],
- (sizeof(unsigned int) * 32));
- if (fprs & FPRS_DU)
- err |= copy_from_user(fpregs+16, &fpu->si_float_regs[32],
- (sizeof(unsigned int) * 32));
- err |= __get_user(current_thread_info()->xfsr[0], &fpu->si_fsr);
- err |= __get_user(current_thread_info()->gsr[0], &fpu->si_gsr);
- current_thread_info()->fpsaved[0] |= fprs;
- return err;
-}
-
void do_rt_sigreturn(struct pt_regs *regs)
{
struct rt_signal_frame __user *sf;
unsigned long tpc, tnpc, tstate;
__siginfo_fpu_t __user *fpu_save;
+ __siginfo_rwin_t __user *rwin_save;
sigset_t set;
int err;
@@ -325,8 +305,8 @@
regs->tstate |= (tstate & (TSTATE_ASI | TSTATE_ICC | TSTATE_XCC));
err |= __get_user(fpu_save, &sf->fpu_save);
- if (fpu_save)
- err |= restore_fpu_state(regs, &sf->fpu_state);
+ if (!err && fpu_save)
+ err |= restore_fpu_state(regs, fpu_save);
err |= __copy_from_user(&set, &sf->mask, sizeof(sigset_t));
err |= do_sigaltstack(&sf->stack, NULL, (unsigned long)sf);
@@ -334,6 +314,12 @@
if (err)
goto segv;
+ err |= __get_user(rwin_save, &sf->rwin_save);
+ if (!err && rwin_save) {
+ if (restore_rwin_state(rwin_save))
+ goto segv;
+ }
+
regs->tpc = tpc;
regs->tnpc = tnpc;
@@ -351,34 +337,13 @@
}
/* Checks if the fp is valid */
-static int invalid_frame_pointer(void __user *fp, int fplen)
+static int invalid_frame_pointer(void __user *fp)
{
if (((unsigned long) fp) & 15)
return 1;
return 0;
}
-static inline int
-save_fpu_state(struct pt_regs *regs, __siginfo_fpu_t __user *fpu)
-{
- unsigned long *fpregs = current_thread_info()->fpregs;
- unsigned long fprs;
- int err = 0;
-
- fprs = current_thread_info()->fpsaved[0];
- if (fprs & FPRS_DL)
- err |= copy_to_user(&fpu->si_float_regs[0], fpregs,
- (sizeof(unsigned int) * 32));
- if (fprs & FPRS_DU)
- err |= copy_to_user(&fpu->si_float_regs[32], fpregs+16,
- (sizeof(unsigned int) * 32));
- err |= __put_user(current_thread_info()->xfsr[0], &fpu->si_fsr);
- err |= __put_user(current_thread_info()->gsr[0], &fpu->si_gsr);
- err |= __put_user(fprs, &fpu->si_fprs);
-
- return err;
-}
-
static inline void __user *get_sigframe(struct k_sigaction *ka, struct pt_regs *regs, unsigned long framesize)
{
unsigned long sp = regs->u_regs[UREG_FP] + STACK_BIAS;
@@ -414,34 +379,48 @@
int signo, sigset_t *oldset, siginfo_t *info)
{
struct rt_signal_frame __user *sf;
- int sigframe_size, err;
+ int wsaved, err, sf_size;
+ void __user *tail;
/* 1. Make sure everything is clean */
synchronize_user_stack();
save_and_clear_fpu();
- sigframe_size = sizeof(struct rt_signal_frame);
- if (!(current_thread_info()->fpsaved[0] & FPRS_FEF))
- sigframe_size -= sizeof(__siginfo_fpu_t);
+ wsaved = get_thread_wsaved();
+ sf_size = sizeof(struct rt_signal_frame);
+ if (current_thread_info()->fpsaved[0] & FPRS_FEF)
+ sf_size += sizeof(__siginfo_fpu_t);
+ if (wsaved)
+ sf_size += sizeof(__siginfo_rwin_t);
sf = (struct rt_signal_frame __user *)
- get_sigframe(ka, regs, sigframe_size);
-
- if (invalid_frame_pointer (sf, sigframe_size))
+ get_sigframe(ka, regs, sf_size);
+
+ if (invalid_frame_pointer (sf))
goto sigill;
- if (get_thread_wsaved() != 0)
- goto sigill;
+ tail = (sf + 1);
/* 2. Save the current process state */
err = copy_to_user(&sf->regs, regs, sizeof (*regs));
if (current_thread_info()->fpsaved[0] & FPRS_FEF) {
- err |= save_fpu_state(regs, &sf->fpu_state);
- err |= __put_user((u64)&sf->fpu_state, &sf->fpu_save);
+ __siginfo_fpu_t __user *fpu_save = tail;
+ tail += sizeof(__siginfo_fpu_t);
+ err |= save_fpu_state(regs, fpu_save);
+ err |= __put_user((u64)fpu_save, &sf->fpu_save);
} else {
err |= __put_user(0, &sf->fpu_save);
}
+ if (wsaved) {
+ __siginfo_rwin_t __user *rwin_save = tail;
+ tail += sizeof(__siginfo_rwin_t);
+ err |= save_rwin_state(wsaved, rwin_save);
+ err |= __put_user((u64)rwin_save, &sf->rwin_save);
+ set_thread_wsaved(0);
+ } else {
+ err |= __put_user(0, &sf->rwin_save);
+ }
/* Setup sigaltstack */
err |= __put_user(current->sas_ss_sp, &sf->stack.ss_sp);
@@ -450,10 +429,17 @@
err |= copy_to_user(&sf->mask, oldset, sizeof(sigset_t));
- err |= copy_in_user((u64 __user *)sf,
- (u64 __user *)(regs->u_regs[UREG_FP]+STACK_BIAS),
- sizeof(struct reg_window));
+ if (!wsaved) {
+ err |= copy_in_user((u64 __user *)sf,
+ (u64 __user *)(regs->u_regs[UREG_FP] +
+ STACK_BIAS),
+ sizeof(struct reg_window));
+ } else {
+ struct reg_window *rp;
+ rp = ¤t_thread_info()->reg_window[wsaved - 1];
+ err |= copy_to_user(sf, rp, sizeof(struct reg_window));
+ }
if (info)
err |= copy_siginfo_to_user(&sf->info, info);
else {
diff --git a/arch/sparc/kernel/sigutil.h b/arch/sparc/kernel/sigutil.h
new file mode 100644
index 0000000..d223aa4
--- /dev/null
+++ b/arch/sparc/kernel/sigutil.h
@@ -0,0 +1,9 @@
+#ifndef _SIGUTIL_H
+#define _SIGUTIL_H
+
+int save_fpu_state(struct pt_regs *regs, __siginfo_fpu_t __user *fpu);
+int restore_fpu_state(struct pt_regs *regs, __siginfo_fpu_t __user *fpu);
+int save_rwin_state(int wsaved, __siginfo_rwin_t __user *rwin);
+int restore_rwin_state(__siginfo_rwin_t __user *rp);
+
+#endif /* _SIGUTIL_H */
diff --git a/arch/sparc/kernel/sigutil_32.c b/arch/sparc/kernel/sigutil_32.c
new file mode 100644
index 0000000..35c7897
--- /dev/null
+++ b/arch/sparc/kernel/sigutil_32.c
@@ -0,0 +1,120 @@
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/thread_info.h>
+#include <linux/uaccess.h>
+#include <linux/sched.h>
+
+#include <asm/sigcontext.h>
+#include <asm/fpumacro.h>
+#include <asm/ptrace.h>
+
+#include "sigutil.h"
+
+int save_fpu_state(struct pt_regs *regs, __siginfo_fpu_t __user *fpu)
+{
+ int err = 0;
+#ifdef CONFIG_SMP
+ if (test_tsk_thread_flag(current, TIF_USEDFPU)) {
+ put_psr(get_psr() | PSR_EF);
+ fpsave(¤t->thread.float_regs[0], ¤t->thread.fsr,
+ ¤t->thread.fpqueue[0], ¤t->thread.fpqdepth);
+ regs->psr &= ~(PSR_EF);
+ clear_tsk_thread_flag(current, TIF_USEDFPU);
+ }
+#else
+ if (current == last_task_used_math) {
+ put_psr(get_psr() | PSR_EF);
+ fpsave(¤t->thread.float_regs[0], ¤t->thread.fsr,
+ ¤t->thread.fpqueue[0], ¤t->thread.fpqdepth);
+ last_task_used_math = NULL;
+ regs->psr &= ~(PSR_EF);
+ }
+#endif
+ err |= __copy_to_user(&fpu->si_float_regs[0],
+ ¤t->thread.float_regs[0],
+ (sizeof(unsigned long) * 32));
+ err |= __put_user(current->thread.fsr, &fpu->si_fsr);
+ err |= __put_user(current->thread.fpqdepth, &fpu->si_fpqdepth);
+ if (current->thread.fpqdepth != 0)
+ err |= __copy_to_user(&fpu->si_fpqueue[0],
+ ¤t->thread.fpqueue[0],
+ ((sizeof(unsigned long) +
+ (sizeof(unsigned long *)))*16));
+ clear_used_math();
+ return err;
+}
+
+int restore_fpu_state(struct pt_regs *regs, __siginfo_fpu_t __user *fpu)
+{
+ int err;
+#ifdef CONFIG_SMP
+ if (test_tsk_thread_flag(current, TIF_USEDFPU))
+ regs->psr &= ~PSR_EF;
+#else
+ if (current == last_task_used_math) {
+ last_task_used_math = NULL;
+ regs->psr &= ~PSR_EF;
+ }
+#endif
+ set_used_math();
+ clear_tsk_thread_flag(current, TIF_USEDFPU);
+
+ if (!access_ok(VERIFY_READ, fpu, sizeof(*fpu)))
+ return -EFAULT;
+
+ err = __copy_from_user(¤t->thread.float_regs[0], &fpu->si_float_regs[0],
+ (sizeof(unsigned long) * 32));
+ err |= __get_user(current->thread.fsr, &fpu->si_fsr);
+ err |= __get_user(current->thread.fpqdepth, &fpu->si_fpqdepth);
+ if (current->thread.fpqdepth != 0)
+ err |= __copy_from_user(¤t->thread.fpqueue[0],
+ &fpu->si_fpqueue[0],
+ ((sizeof(unsigned long) +
+ (sizeof(unsigned long *)))*16));
+ return err;
+}
+
+int save_rwin_state(int wsaved, __siginfo_rwin_t __user *rwin)
+{
+ int i, err = __put_user(wsaved, &rwin->wsaved);
+
+ for (i = 0; i < wsaved; i++) {
+ struct reg_window32 *rp;
+ unsigned long fp;
+
+ rp = ¤t_thread_info()->reg_window[i];
+ fp = current_thread_info()->rwbuf_stkptrs[i];
+ err |= copy_to_user(&rwin->reg_window[i], rp,
+ sizeof(struct reg_window32));
+ err |= __put_user(fp, &rwin->rwbuf_stkptrs[i]);
+ }
+ return err;
+}
+
+int restore_rwin_state(__siginfo_rwin_t __user *rp)
+{
+ struct thread_info *t = current_thread_info();
+ int i, wsaved, err;
+
+ __get_user(wsaved, &rp->wsaved);
+ if (wsaved > NSWINS)
+ return -EFAULT;
+
+ err = 0;
+ for (i = 0; i < wsaved; i++) {
+ err |= copy_from_user(&t->reg_window[i],
+ &rp->reg_window[i],
+ sizeof(struct reg_window32));
+ err |= __get_user(t->rwbuf_stkptrs[i],
+ &rp->rwbuf_stkptrs[i]);
+ }
+ if (err)
+ return err;
+
+ t->w_saved = wsaved;
+ synchronize_user_stack();
+ if (t->w_saved)
+ return -EFAULT;
+ return 0;
+
+}
diff --git a/arch/sparc/kernel/sigutil_64.c b/arch/sparc/kernel/sigutil_64.c
new file mode 100644
index 0000000..e7dc508
--- /dev/null
+++ b/arch/sparc/kernel/sigutil_64.c
@@ -0,0 +1,93 @@
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/thread_info.h>
+#include <linux/uaccess.h>
+
+#include <asm/sigcontext.h>
+#include <asm/fpumacro.h>
+#include <asm/ptrace.h>
+
+#include "sigutil.h"
+
+int save_fpu_state(struct pt_regs *regs, __siginfo_fpu_t __user *fpu)
+{
+ unsigned long *fpregs = current_thread_info()->fpregs;
+ unsigned long fprs;
+ int err = 0;
+
+ fprs = current_thread_info()->fpsaved[0];
+ if (fprs & FPRS_DL)
+ err |= copy_to_user(&fpu->si_float_regs[0], fpregs,
+ (sizeof(unsigned int) * 32));
+ if (fprs & FPRS_DU)
+ err |= copy_to_user(&fpu->si_float_regs[32], fpregs+16,
+ (sizeof(unsigned int) * 32));
+ err |= __put_user(current_thread_info()->xfsr[0], &fpu->si_fsr);
+ err |= __put_user(current_thread_info()->gsr[0], &fpu->si_gsr);
+ err |= __put_user(fprs, &fpu->si_fprs);
+
+ return err;
+}
+
+int restore_fpu_state(struct pt_regs *regs, __siginfo_fpu_t __user *fpu)
+{
+ unsigned long *fpregs = current_thread_info()->fpregs;
+ unsigned long fprs;
+ int err;
+
+ err = __get_user(fprs, &fpu->si_fprs);
+ fprs_write(0);
+ regs->tstate &= ~TSTATE_PEF;
+ if (fprs & FPRS_DL)
+ err |= copy_from_user(fpregs, &fpu->si_float_regs[0],
+ (sizeof(unsigned int) * 32));
+ if (fprs & FPRS_DU)
+ err |= copy_from_user(fpregs+16, &fpu->si_float_regs[32],
+ (sizeof(unsigned int) * 32));
+ err |= __get_user(current_thread_info()->xfsr[0], &fpu->si_fsr);
+ err |= __get_user(current_thread_info()->gsr[0], &fpu->si_gsr);
+ current_thread_info()->fpsaved[0] |= fprs;
+ return err;
+}
+
+int save_rwin_state(int wsaved, __siginfo_rwin_t __user *rwin)
+{
+ int i, err = __put_user(wsaved, &rwin->wsaved);
+
+ for (i = 0; i < wsaved; i++) {
+ struct reg_window *rp = ¤t_thread_info()->reg_window[i];
+ unsigned long fp = current_thread_info()->rwbuf_stkptrs[i];
+
+ err |= copy_to_user(&rwin->reg_window[i], rp,
+ sizeof(struct reg_window));
+ err |= __put_user(fp, &rwin->rwbuf_stkptrs[i]);
+ }
+ return err;
+}
+
+int restore_rwin_state(__siginfo_rwin_t __user *rp)
+{
+ struct thread_info *t = current_thread_info();
+ int i, wsaved, err;
+
+ __get_user(wsaved, &rp->wsaved);
+ if (wsaved > NSWINS)
+ return -EFAULT;
+
+ err = 0;
+ for (i = 0; i < wsaved; i++) {
+ err |= copy_from_user(&t->reg_window[i],
+ &rp->reg_window[i],
+ sizeof(struct reg_window));
+ err |= __get_user(t->rwbuf_stkptrs[i],
+ &rp->rwbuf_stkptrs[i]);
+ }
+ if (err)
+ return err;
+
+ set_thread_wsaved(wsaved);
+ synchronize_user_stack();
+ if (get_thread_wsaved())
+ return -EFAULT;
+ return 0;
+}
diff --git a/arch/sparc/kernel/sys32.S b/arch/sparc/kernel/sys32.S
index 44e5faf..d97f3eb 100644
--- a/arch/sparc/kernel/sys32.S
+++ b/arch/sparc/kernel/sys32.S
@@ -81,7 +81,6 @@
SIGN2(sys32_fadvise64_64, compat_sys_fadvise64_64, %o0, %o5)
SIGN2(sys32_bdflush, sys_bdflush, %o0, %o1)
SIGN1(sys32_mlockall, sys_mlockall, %o0)
-SIGN1(sys32_nfsservctl, compat_sys_nfsservctl, %o0)
SIGN1(sys32_clock_nanosleep, compat_sys_clock_nanosleep, %o1)
SIGN1(sys32_timer_settime, compat_sys_timer_settime, %o1)
SIGN1(sys32_io_submit, compat_sys_io_submit, %o1)
diff --git a/arch/sparc/kernel/systbls_32.S b/arch/sparc/kernel/systbls_32.S
index 6e492d5..09d8ec4 100644
--- a/arch/sparc/kernel/systbls_32.S
+++ b/arch/sparc/kernel/systbls_32.S
@@ -67,7 +67,7 @@
/*235*/ .long sys_fstatfs64, sys_llseek, sys_mlock, sys_munlock, sys_mlockall
/*240*/ .long sys_munlockall, sys_sched_setparam, sys_sched_getparam, sys_sched_setscheduler, sys_sched_getscheduler
/*245*/ .long sys_sched_yield, sys_sched_get_priority_max, sys_sched_get_priority_min, sys_sched_rr_get_interval, sys_nanosleep
-/*250*/ .long sys_mremap, sys_sysctl, sys_getsid, sys_fdatasync, sys_nfsservctl
+/*250*/ .long sys_mremap, sys_sysctl, sys_getsid, sys_fdatasync, sys_ni_syscall
/*255*/ .long sys_sync_file_range, sys_clock_settime, sys_clock_gettime, sys_clock_getres, sys_clock_nanosleep
/*260*/ .long sys_sched_getaffinity, sys_sched_setaffinity, sys_timer_settime, sys_timer_gettime, sys_timer_getoverrun
/*265*/ .long sys_timer_delete, sys_timer_create, sys_nis_syscall, sys_io_setup, sys_io_destroy
diff --git a/arch/sparc/kernel/systbls_64.S b/arch/sparc/kernel/systbls_64.S
index f566518..edbec45 100644
--- a/arch/sparc/kernel/systbls_64.S
+++ b/arch/sparc/kernel/systbls_64.S
@@ -68,7 +68,7 @@
.word compat_sys_fstatfs64, sys_llseek, sys_mlock, sys_munlock, sys32_mlockall
/*240*/ .word sys_munlockall, sys32_sched_setparam, sys32_sched_getparam, sys32_sched_setscheduler, sys32_sched_getscheduler
.word sys_sched_yield, sys32_sched_get_priority_max, sys32_sched_get_priority_min, sys32_sched_rr_get_interval, compat_sys_nanosleep
-/*250*/ .word sys_mremap, compat_sys_sysctl, sys32_getsid, sys_fdatasync, sys32_nfsservctl
+/*250*/ .word sys_mremap, compat_sys_sysctl, sys32_getsid, sys_fdatasync, sys_nis_syscall
.word sys32_sync_file_range, compat_sys_clock_settime, compat_sys_clock_gettime, compat_sys_clock_getres, sys32_clock_nanosleep
/*260*/ .word compat_sys_sched_getaffinity, compat_sys_sched_setaffinity, sys32_timer_settime, compat_sys_timer_gettime, sys_timer_getoverrun
.word sys_timer_delete, compat_sys_timer_create, sys_ni_syscall, compat_sys_io_setup, sys_io_destroy
@@ -145,7 +145,7 @@
.word sys_fstatfs64, sys_llseek, sys_mlock, sys_munlock, sys_mlockall
/*240*/ .word sys_munlockall, sys_sched_setparam, sys_sched_getparam, sys_sched_setscheduler, sys_sched_getscheduler
.word sys_sched_yield, sys_sched_get_priority_max, sys_sched_get_priority_min, sys_sched_rr_get_interval, sys_nanosleep
-/*250*/ .word sys_64_mremap, sys_sysctl, sys_getsid, sys_fdatasync, sys_nfsservctl
+/*250*/ .word sys_64_mremap, sys_sysctl, sys_getsid, sys_fdatasync, sys_nis_syscall
.word sys_sync_file_range, sys_clock_settime, sys_clock_gettime, sys_clock_getres, sys_clock_nanosleep
/*260*/ .word sys_sched_getaffinity, sys_sched_setaffinity, sys_timer_settime, sys_timer_gettime, sys_timer_getoverrun
.word sys_timer_delete, sys_timer_create, sys_ni_syscall, sys_io_setup, sys_io_destroy
diff --git a/arch/x86/ia32/ia32entry.S b/arch/x86/ia32/ia32entry.S
index a0e866d..54edb207 100644
--- a/arch/x86/ia32/ia32entry.S
+++ b/arch/x86/ia32/ia32entry.S
@@ -672,7 +672,7 @@
.quad sys32_vm86_warning /* vm86 */
.quad quiet_ni_syscall /* query_module */
.quad sys_poll
- .quad compat_sys_nfsservctl
+ .quad quiet_ni_syscall /* old nfsservctl */
.quad sys_setresgid16 /* 170 */
.quad sys_getresgid16
.quad sys_prctl
diff --git a/arch/x86/include/asm/pvclock.h b/arch/x86/include/asm/pvclock.h
index a518c0a..c59cc97 100644
--- a/arch/x86/include/asm/pvclock.h
+++ b/arch/x86/include/asm/pvclock.h
@@ -44,7 +44,7 @@
: "a" ((u32)delta), "1" ((u32)(delta >> 32)), "2" (mul_frac) );
#elif defined(__x86_64__)
__asm__ (
- "mul %[mul_frac] ; shrd $32, %[hi], %[lo]"
+ "mulq %[mul_frac] ; shrd $32, %[hi], %[lo]"
: [lo]"=a"(product),
[hi]"=d"(tmp)
: "0"(delta),
diff --git a/arch/x86/include/asm/unistd_64.h b/arch/x86/include/asm/unistd_64.h
index d92641c..2010405 100644
--- a/arch/x86/include/asm/unistd_64.h
+++ b/arch/x86/include/asm/unistd_64.h
@@ -414,7 +414,7 @@
__SYSCALL(__NR_quotactl, sys_quotactl)
#define __NR_nfsservctl 180
-__SYSCALL(__NR_nfsservctl, sys_nfsservctl)
+__SYSCALL(__NR_nfsservctl, sys_ni_syscall)
/* reserved for LiS/STREAMS */
#define __NR_getpmsg 181
diff --git a/arch/x86/kernel/apic/x2apic_uv_x.c b/arch/x86/kernel/apic/x2apic_uv_x.c
index adc66c3..34b1859 100644
--- a/arch/x86/kernel/apic/x2apic_uv_x.c
+++ b/arch/x86/kernel/apic/x2apic_uv_x.c
@@ -207,7 +207,6 @@
((start_rip << UVH_IPI_INT_VECTOR_SHFT) >> 12) |
APIC_DM_INIT;
uv_write_global_mmr64(pnode, UVH_IPI_INT, val);
- mdelay(10);
val = (1UL << UVH_IPI_INT_SEND_SHFT) |
(phys_apicid << UVH_IPI_INT_APIC_ID_SHFT) |
diff --git a/arch/x86/kernel/cpu/mtrr/main.c b/arch/x86/kernel/cpu/mtrr/main.c
index 08119a3..6b96110 100644
--- a/arch/x86/kernel/cpu/mtrr/main.c
+++ b/arch/x86/kernel/cpu/mtrr/main.c
@@ -149,7 +149,6 @@
*/
static int mtrr_rendezvous_handler(void *info)
{
-#ifdef CONFIG_SMP
struct set_mtrr_data *data = info;
/*
@@ -171,7 +170,6 @@
} else if (mtrr_aps_delayed_init || !cpu_online(smp_processor_id())) {
mtrr_if->set_all();
}
-#endif
return 0;
}
diff --git a/arch/x86/kernel/cpu/perf_event.c b/arch/x86/kernel/cpu/perf_event.c
index 4ee3abf..cfa62ec 100644
--- a/arch/x86/kernel/cpu/perf_event.c
+++ b/arch/x86/kernel/cpu/perf_event.c
@@ -1900,6 +1900,9 @@
perf_callchain_store(entry, regs->ip);
+ if (!current->mm)
+ return;
+
if (perf_callchain_user32(regs, entry))
return;
diff --git a/arch/x86/kernel/entry_32.S b/arch/x86/kernel/entry_32.S
index 5c1a9197..f3f6f53 100644
--- a/arch/x86/kernel/entry_32.S
+++ b/arch/x86/kernel/entry_32.S
@@ -54,6 +54,7 @@
#include <asm/ftrace.h>
#include <asm/irq_vectors.h>
#include <asm/cpufeature.h>
+#include <asm/alternative-asm.h>
/* Avoid __ASSEMBLER__'ifying <linux/audit.h> just for this. */
#include <linux/elf-em.h>
@@ -873,12 +874,7 @@
661: pushl_cfi $do_general_protection
662:
.section .altinstructions,"a"
- .balign 4
- .long 661b
- .long 663f
- .word X86_FEATURE_XMM
- .byte 662b-661b
- .byte 664f-663f
+ altinstruction_entry 661b, 663f, X86_FEATURE_XMM, 662b-661b, 664f-663f
.previous
.section .altinstr_replacement,"ax"
663: pushl $do_simd_coprocessor_error
diff --git a/arch/x86/kernel/syscall_table_32.S b/arch/x86/kernel/syscall_table_32.S
index fbb0a04..bc19be3 100644
--- a/arch/x86/kernel/syscall_table_32.S
+++ b/arch/x86/kernel/syscall_table_32.S
@@ -168,7 +168,7 @@
.long ptregs_vm86
.long sys_ni_syscall /* Old sys_query_module */
.long sys_poll
- .long sys_nfsservctl
+ .long sys_ni_syscall /* Old nfsservctl */
.long sys_setresgid16 /* 170 */
.long sys_getresgid16
.long sys_prctl
diff --git a/arch/x86/pci/acpi.c b/arch/x86/pci/acpi.c
index c953302..039d913 100644
--- a/arch/x86/pci/acpi.c
+++ b/arch/x86/pci/acpi.c
@@ -365,8 +365,13 @@
*/
if (bus) {
struct pci_bus *child;
- list_for_each_entry(child, &bus->children, node)
- pcie_bus_configure_settings(child, child->self->pcie_mpss);
+ list_for_each_entry(child, &bus->children, node) {
+ struct pci_dev *self = child->self;
+ if (!self)
+ continue;
+
+ pcie_bus_configure_settings(child, self->pcie_mpss);
+ }
}
if (!bus)
diff --git a/arch/x86/platform/mrst/mrst.c b/arch/x86/platform/mrst/mrst.c
index 7000e74b..58425ad 100644
--- a/arch/x86/platform/mrst/mrst.c
+++ b/arch/x86/platform/mrst/mrst.c
@@ -689,7 +689,9 @@
irq_attr.trigger = 1;
irq_attr.polarity = 1;
io_apic_set_pci_routing(NULL, pentry->irq, &irq_attr);
- }
+ } else
+ pentry->irq = 0; /* No irq */
+
switch (pentry->type) {
case SFI_DEV_TYPE_IPC:
/* ID as IRQ is a hack that will go away */
diff --git a/arch/x86/platform/olpc/olpc.c b/arch/x86/platform/olpc/olpc.c
index 8b9940e..7cce722 100644
--- a/arch/x86/platform/olpc/olpc.c
+++ b/arch/x86/platform/olpc/olpc.c
@@ -161,13 +161,13 @@
if (inbuf && inlen) {
/* write data to EC */
for (i = 0; i < inlen; i++) {
+ pr_devel("olpc-ec: sending cmd arg 0x%x\n", inbuf[i]);
+ outb(inbuf[i], 0x68);
if (wait_on_ibf(0x6c, 0)) {
printk(KERN_ERR "olpc-ec: timeout waiting for"
" EC accept data!\n");
goto err;
}
- pr_devel("olpc-ec: sending cmd arg 0x%x\n", inbuf[i]);
- outb(inbuf[i], 0x68);
}
}
if (outbuf && outlen) {
diff --git a/arch/x86/vdso/vdso32/sysenter.S b/arch/x86/vdso/vdso32/sysenter.S
index e2800af..e354bce 100644
--- a/arch/x86/vdso/vdso32/sysenter.S
+++ b/arch/x86/vdso/vdso32/sysenter.S
@@ -43,7 +43,7 @@
.space 7,0x90
/* 14: System call restart point is here! (SYSENTER_RETURN-2) */
- jmp .Lenter_kernel
+ int $0x80
/* 16: System call normal return point is here! */
VDSO32_SYSENTER_RETURN: /* Symbol used by sysenter.c via vdso32-syms.h */
pop %ebp
diff --git a/arch/x86/xen/setup.c b/arch/x86/xen/setup.c
index df118a8..c3b8d44 100644
--- a/arch/x86/xen/setup.c
+++ b/arch/x86/xen/setup.c
@@ -184,6 +184,19 @@
PFN_UP(start_pci), PFN_DOWN(last));
return identity;
}
+
+static unsigned long __init xen_get_max_pages(void)
+{
+ unsigned long max_pages = MAX_DOMAIN_PAGES;
+ domid_t domid = DOMID_SELF;
+ int ret;
+
+ ret = HYPERVISOR_memory_op(XENMEM_maximum_reservation, &domid);
+ if (ret > 0)
+ max_pages = ret;
+ return min(max_pages, MAX_DOMAIN_PAGES);
+}
+
/**
* machine_specific_memory_setup - Hook for machine specific memory setup.
**/
@@ -292,6 +305,12 @@
sanitize_e820_map(e820.map, ARRAY_SIZE(e820.map), &e820.nr_map);
+ extra_limit = xen_get_max_pages();
+ if (extra_limit >= max_pfn)
+ extra_pages = extra_limit - max_pfn;
+ else
+ extra_pages = 0;
+
extra_pages += xen_return_unused_memory(xen_start_info->nr_pages, &e820);
/*
diff --git a/arch/x86/xen/smp.c b/arch/x86/xen/smp.c
index e79dbb9..d4fc6d4 100644
--- a/arch/x86/xen/smp.c
+++ b/arch/x86/xen/smp.c
@@ -32,6 +32,7 @@
#include <xen/page.h>
#include <xen/events.h>
+#include <xen/hvc-console.h>
#include "xen-ops.h"
#include "mmu.h"
@@ -207,6 +208,15 @@
unsigned cpu;
unsigned int i;
+ if (skip_ioapic_setup) {
+ char *m = (max_cpus == 0) ?
+ "The nosmp parameter is incompatible with Xen; " \
+ "use Xen dom0_max_vcpus=1 parameter" :
+ "The noapic parameter is incompatible with Xen";
+
+ xen_raw_printk(m);
+ panic(m);
+ }
xen_init_lock_cpu(0);
smp_store_cpu_info(0);
diff --git a/arch/x86/xen/xen-asm_32.S b/arch/x86/xen/xen-asm_32.S
index 22a2093..b040b0e 100644
--- a/arch/x86/xen/xen-asm_32.S
+++ b/arch/x86/xen/xen-asm_32.S
@@ -113,11 +113,13 @@
/*
* If there's something pending, mask events again so we can
- * jump back into xen_hypervisor_callback
+ * jump back into xen_hypervisor_callback. Otherwise do not
+ * touch XEN_vcpu_info_mask.
*/
- sete XEN_vcpu_info_mask(%eax)
+ jne 1f
+ movb $1, XEN_vcpu_info_mask(%eax)
- popl %eax
+1: popl %eax
/*
* From this point on the registers are restored and the stack
diff --git a/arch/xtensa/include/asm/unistd.h b/arch/xtensa/include/asm/unistd.h
index a6f934f..798ee6d 100644
--- a/arch/xtensa/include/asm/unistd.h
+++ b/arch/xtensa/include/asm/unistd.h
@@ -455,7 +455,7 @@
#define __NR_quotactl 204
__SYSCALL(204, sys_quotactl, 4)
#define __NR_nfsservctl 205
-__SYSCALL(205, sys_nfsservctl, 3)
+__SYSCALL(205, sys_ni_syscall, 0)
#define __NR__sysctl 206
__SYSCALL(206, sys_sysctl, 1)
#define __NR_bdflush 207
diff --git a/drivers/base/devres.c b/drivers/base/devres.c
index cf7a0c7..65cd748 100644
--- a/drivers/base/devres.c
+++ b/drivers/base/devres.c
@@ -397,6 +397,7 @@
static int release_nodes(struct device *dev, struct list_head *first,
struct list_head *end, unsigned long flags)
+ __releases(&dev->devres_lock)
{
LIST_HEAD(todo);
int cnt;
diff --git a/drivers/base/devtmpfs.c b/drivers/base/devtmpfs.c
index 33e1bed..a4760e0 100644
--- a/drivers/base/devtmpfs.c
+++ b/drivers/base/devtmpfs.c
@@ -376,7 +376,7 @@
return err;
}
-static __initdata DECLARE_COMPLETION(setup_done);
+static DECLARE_COMPLETION(setup_done);
static int handle(const char *name, mode_t mode, struct device *dev)
{
diff --git a/drivers/base/firmware_class.c b/drivers/base/firmware_class.c
index bbb03e6..06ed6b4 100644
--- a/drivers/base/firmware_class.c
+++ b/drivers/base/firmware_class.c
@@ -521,11 +521,6 @@
if (!firmware_p)
return -EINVAL;
- if (WARN_ON(usermodehelper_is_disabled())) {
- dev_err(device, "firmware: %s will not be loaded\n", name);
- return -EBUSY;
- }
-
*firmware_p = firmware = kzalloc(sizeof(*firmware), GFP_KERNEL);
if (!firmware) {
dev_err(device, "%s: kmalloc(struct firmware) failed\n",
@@ -539,6 +534,12 @@
return 0;
}
+ if (WARN_ON(usermodehelper_is_disabled())) {
+ dev_err(device, "firmware: %s will not be loaded\n", name);
+ retval = -EBUSY;
+ goto out;
+ }
+
if (uevent)
dev_dbg(device, "firmware: requesting %s\n", name);
diff --git a/drivers/base/platform.c b/drivers/base/platform.c
index 0cad9c7..99a5272 100644
--- a/drivers/base/platform.c
+++ b/drivers/base/platform.c
@@ -33,7 +33,7 @@
/**
* arch_setup_pdev_archdata - Allow manipulation of archdata before its used
- * @dev: platform device
+ * @pdev: platform device
*
* This is called before platform_device_add() such that any pdev_archdata may
* be setup before the platform_notifier is called. So if a user needs to
diff --git a/drivers/base/power/clock_ops.c b/drivers/base/power/clock_ops.c
index a846b2f..2c18d58 100644
--- a/drivers/base/power/clock_ops.c
+++ b/drivers/base/power/clock_ops.c
@@ -19,7 +19,7 @@
struct pm_clk_data {
struct list_head clock_list;
- struct mutex lock;
+ spinlock_t lock;
};
enum pce_status {
@@ -73,9 +73,9 @@
}
}
- mutex_lock(&pcd->lock);
+ spin_lock_irq(&pcd->lock);
list_add_tail(&ce->node, &pcd->clock_list);
- mutex_unlock(&pcd->lock);
+ spin_unlock_irq(&pcd->lock);
return 0;
}
@@ -83,8 +83,8 @@
* __pm_clk_remove - Destroy PM clock entry.
* @ce: PM clock entry to destroy.
*
- * This routine must be called under the mutex protecting the PM list of clocks
- * corresponding the the @ce's device.
+ * This routine must be called under the spinlock protecting the PM list of
+ * clocks corresponding the the @ce's device.
*/
static void __pm_clk_remove(struct pm_clock_entry *ce)
{
@@ -123,7 +123,7 @@
if (!pcd)
return;
- mutex_lock(&pcd->lock);
+ spin_lock_irq(&pcd->lock);
list_for_each_entry(ce, &pcd->clock_list, node) {
if (!con_id && !ce->con_id) {
@@ -137,7 +137,7 @@
}
}
- mutex_unlock(&pcd->lock);
+ spin_unlock_irq(&pcd->lock);
}
/**
@@ -158,7 +158,7 @@
}
INIT_LIST_HEAD(&pcd->clock_list);
- mutex_init(&pcd->lock);
+ spin_lock_init(&pcd->lock);
dev->power.subsys_data = pcd;
return 0;
}
@@ -181,12 +181,12 @@
dev->power.subsys_data = NULL;
- mutex_lock(&pcd->lock);
+ spin_lock_irq(&pcd->lock);
list_for_each_entry_safe_reverse(ce, c, &pcd->clock_list, node)
__pm_clk_remove(ce);
- mutex_unlock(&pcd->lock);
+ spin_unlock_irq(&pcd->lock);
kfree(pcd);
}
@@ -220,13 +220,14 @@
{
struct pm_clk_data *pcd = __to_pcd(dev);
struct pm_clock_entry *ce;
+ unsigned long flags;
dev_dbg(dev, "%s()\n", __func__);
if (!pcd)
return 0;
- mutex_lock(&pcd->lock);
+ spin_lock_irqsave(&pcd->lock, flags);
list_for_each_entry_reverse(ce, &pcd->clock_list, node) {
if (ce->status == PCE_STATUS_NONE)
@@ -238,7 +239,7 @@
}
}
- mutex_unlock(&pcd->lock);
+ spin_unlock_irqrestore(&pcd->lock, flags);
return 0;
}
@@ -251,13 +252,14 @@
{
struct pm_clk_data *pcd = __to_pcd(dev);
struct pm_clock_entry *ce;
+ unsigned long flags;
dev_dbg(dev, "%s()\n", __func__);
if (!pcd)
return 0;
- mutex_lock(&pcd->lock);
+ spin_lock_irqsave(&pcd->lock, flags);
list_for_each_entry(ce, &pcd->clock_list, node) {
if (ce->status == PCE_STATUS_NONE)
@@ -269,7 +271,7 @@
}
}
- mutex_unlock(&pcd->lock);
+ spin_unlock_irqrestore(&pcd->lock, flags);
return 0;
}
@@ -344,6 +346,7 @@
{
struct pm_clk_data *pcd = __to_pcd(dev);
struct pm_clock_entry *ce;
+ unsigned long flags;
dev_dbg(dev, "%s()\n", __func__);
@@ -351,12 +354,12 @@
if (!pcd || !dev->driver)
return 0;
- mutex_lock(&pcd->lock);
+ spin_lock_irqsave(&pcd->lock, flags);
list_for_each_entry_reverse(ce, &pcd->clock_list, node)
clk_disable(ce->clk);
- mutex_unlock(&pcd->lock);
+ spin_unlock_irqrestore(&pcd->lock, flags);
return 0;
}
@@ -369,6 +372,7 @@
{
struct pm_clk_data *pcd = __to_pcd(dev);
struct pm_clock_entry *ce;
+ unsigned long flags;
dev_dbg(dev, "%s()\n", __func__);
@@ -376,12 +380,12 @@
if (!pcd || !dev->driver)
return 0;
- mutex_lock(&pcd->lock);
+ spin_lock_irqsave(&pcd->lock, flags);
list_for_each_entry(ce, &pcd->clock_list, node)
clk_enable(ce->clk);
- mutex_unlock(&pcd->lock);
+ spin_unlock_irqrestore(&pcd->lock, flags);
return 0;
}
diff --git a/drivers/base/regmap/regmap.c b/drivers/base/regmap/regmap.c
index 0eef4da..20663f8 100644
--- a/drivers/base/regmap/regmap.c
+++ b/drivers/base/regmap/regmap.c
@@ -168,13 +168,11 @@
map->work_buf = kmalloc(map->format.buf_size, GFP_KERNEL);
if (map->work_buf == NULL) {
ret = -ENOMEM;
- goto err_bus;
+ goto err_map;
}
return map;
-err_bus:
- module_put(map->bus->owner);
err_map:
kfree(map);
err:
@@ -188,7 +186,6 @@
void regmap_exit(struct regmap *map)
{
kfree(map->work_buf);
- module_put(map->bus->owner);
kfree(map);
}
EXPORT_SYMBOL_GPL(regmap_exit);
diff --git a/drivers/bcma/main.c b/drivers/bcma/main.c
index 873e2e4..73b7b1a 100644
--- a/drivers/bcma/main.c
+++ b/drivers/bcma/main.c
@@ -15,6 +15,7 @@
static int bcma_bus_match(struct device *dev, struct device_driver *drv);
static int bcma_device_probe(struct device *dev);
static int bcma_device_remove(struct device *dev);
+static int bcma_device_uevent(struct device *dev, struct kobj_uevent_env *env);
static ssize_t manuf_show(struct device *dev, struct device_attribute *attr, char *buf)
{
@@ -49,6 +50,7 @@
.match = bcma_bus_match,
.probe = bcma_device_probe,
.remove = bcma_device_remove,
+ .uevent = bcma_device_uevent,
.dev_attrs = bcma_device_attrs,
};
@@ -227,6 +229,16 @@
return 0;
}
+static int bcma_device_uevent(struct device *dev, struct kobj_uevent_env *env)
+{
+ struct bcma_device *core = container_of(dev, struct bcma_device, dev);
+
+ return add_uevent_var(env,
+ "MODALIAS=bcma:m%04Xid%04Xrev%02Xcl%02X",
+ core->id.manuf, core->id.id,
+ core->id.rev, core->id.class);
+}
+
static int __init bcma_modinit(void)
{
int err;
diff --git a/drivers/bluetooth/ath3k.c b/drivers/bluetooth/ath3k.c
index a585473..db7cb81 100644
--- a/drivers/bluetooth/ath3k.c
+++ b/drivers/bluetooth/ath3k.c
@@ -63,6 +63,7 @@
/* Atheros AR3011 with sflash firmware*/
{ USB_DEVICE(0x0CF3, 0x3002) },
{ USB_DEVICE(0x13d3, 0x3304) },
+ { USB_DEVICE(0x0930, 0x0215) },
/* Atheros AR9285 Malbec with sflash firmware */
{ USB_DEVICE(0x03F0, 0x311D) },
diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c
index 91d13a9..3ef4760 100644
--- a/drivers/bluetooth/btusb.c
+++ b/drivers/bluetooth/btusb.c
@@ -106,6 +106,7 @@
/* Atheros 3011 with sflash firmware */
{ USB_DEVICE(0x0cf3, 0x3002), .driver_info = BTUSB_IGNORE },
{ USB_DEVICE(0x13d3, 0x3304), .driver_info = BTUSB_IGNORE },
+ { USB_DEVICE(0x0930, 0x0215), .driver_info = BTUSB_IGNORE },
/* Atheros AR9285 Malbec with sflash firmware */
{ USB_DEVICE(0x03f0, 0x311d), .driver_info = BTUSB_IGNORE },
@@ -256,7 +257,9 @@
err = usb_submit_urb(urb, GFP_ATOMIC);
if (err < 0) {
- if (err != -EPERM)
+ /* -EPERM: urb is being killed;
+ * -ENODEV: device got disconnected */
+ if (err != -EPERM && err != -ENODEV)
BT_ERR("%s urb %p failed to resubmit (%d)",
hdev->name, urb, -err);
usb_unanchor_urb(urb);
@@ -341,7 +344,9 @@
err = usb_submit_urb(urb, GFP_ATOMIC);
if (err < 0) {
- if (err != -EPERM)
+ /* -EPERM: urb is being killed;
+ * -ENODEV: device got disconnected */
+ if (err != -EPERM && err != -ENODEV)
BT_ERR("%s urb %p failed to resubmit (%d)",
hdev->name, urb, -err);
usb_unanchor_urb(urb);
@@ -431,7 +436,9 @@
err = usb_submit_urb(urb, GFP_ATOMIC);
if (err < 0) {
- if (err != -EPERM)
+ /* -EPERM: urb is being killed;
+ * -ENODEV: device got disconnected */
+ if (err != -EPERM && err != -ENODEV)
BT_ERR("%s urb %p failed to resubmit (%d)",
hdev->name, urb, -err);
usb_unanchor_urb(urb);
diff --git a/drivers/char/msm_smd_pkt.c b/drivers/char/msm_smd_pkt.c
index b6f8a65..8eca55d 100644
--- a/drivers/char/msm_smd_pkt.c
+++ b/drivers/char/msm_smd_pkt.c
@@ -379,9 +379,8 @@
for (i = 0; i < NUM_SMD_PKT_PORTS; ++i) {
smd_pkt_devp[i] = kzalloc(sizeof(struct smd_pkt_dev),
GFP_KERNEL);
- if (IS_ERR(smd_pkt_devp[i])) {
- r = PTR_ERR(smd_pkt_devp[i]);
- pr_err("kmalloc() failed %d\n", r);
+ if (!smd_pkt_devp[i]) {
+ pr_err("kmalloc() failed\n");
goto clean_cdevs;
}
diff --git a/drivers/clocksource/sh_cmt.c b/drivers/clocksource/sh_cmt.c
index dc7c033..32a77be 100644
--- a/drivers/clocksource/sh_cmt.c
+++ b/drivers/clocksource/sh_cmt.c
@@ -26,6 +26,7 @@
#include <linux/clk.h>
#include <linux/irq.h>
#include <linux/err.h>
+#include <linux/delay.h>
#include <linux/clocksource.h>
#include <linux/clockchips.h>
#include <linux/sh_timer.h>
@@ -150,13 +151,13 @@
static int sh_cmt_enable(struct sh_cmt_priv *p, unsigned long *rate)
{
- int ret;
+ int k, ret;
/* enable clock */
ret = clk_enable(p->clk);
if (ret) {
dev_err(&p->pdev->dev, "cannot enable clock\n");
- return ret;
+ goto err0;
}
/* make sure channel is disabled */
@@ -174,9 +175,38 @@
sh_cmt_write(p, CMCOR, 0xffffffff);
sh_cmt_write(p, CMCNT, 0);
+ /*
+ * According to the sh73a0 user's manual, as CMCNT can be operated
+ * only by the RCLK (Pseudo 32 KHz), there's one restriction on
+ * modifying CMCNT register; two RCLK cycles are necessary before
+ * this register is either read or any modification of the value
+ * it holds is reflected in the LSI's actual operation.
+ *
+ * While at it, we're supposed to clear out the CMCNT as of this
+ * moment, so make sure it's processed properly here. This will
+ * take RCLKx2 at maximum.
+ */
+ for (k = 0; k < 100; k++) {
+ if (!sh_cmt_read(p, CMCNT))
+ break;
+ udelay(1);
+ }
+
+ if (sh_cmt_read(p, CMCNT)) {
+ dev_err(&p->pdev->dev, "cannot clear CMCNT\n");
+ ret = -ETIMEDOUT;
+ goto err1;
+ }
+
/* enable channel */
sh_cmt_start_stop_ch(p, 1);
return 0;
+ err1:
+ /* stop clock */
+ clk_disable(p->clk);
+
+ err0:
+ return ret;
}
static void sh_cmt_disable(struct sh_cmt_priv *p)
diff --git a/drivers/dma/ste_dma40.c b/drivers/dma/ste_dma40.c
index cd3a7c7..467e4dc 100644
--- a/drivers/dma/ste_dma40.c
+++ b/drivers/dma/ste_dma40.c
@@ -174,8 +174,10 @@
* @tasklet: Tasklet that gets scheduled from interrupt context to complete a
* transfer and call client callback.
* @client: Cliented owned descriptor list.
+ * @pending_queue: Submitted jobs, to be issued by issue_pending()
* @active: Active descriptor.
* @queue: Queued jobs.
+ * @prepare_queue: Prepared jobs.
* @dma_cfg: The client configuration of this dma channel.
* @configured: whether the dma_cfg configuration is valid
* @base: Pointer to the device instance struct.
@@ -203,6 +205,7 @@
struct list_head pending_queue;
struct list_head active;
struct list_head queue;
+ struct list_head prepare_queue;
struct stedma40_chan_cfg dma_cfg;
bool configured;
struct d40_base *base;
@@ -477,7 +480,6 @@
list_for_each_entry_safe(d, _d, &d40c->client, node)
if (async_tx_test_ack(&d->txd)) {
- d40_pool_lli_free(d40c, d);
d40_desc_remove(d);
desc = d;
memset(desc, 0, sizeof(*desc));
@@ -644,8 +646,11 @@
return d;
}
+/* remove desc from current queue and add it to the pending_queue */
static void d40_desc_queue(struct d40_chan *d40c, struct d40_desc *desc)
{
+ d40_desc_remove(desc);
+ desc->is_in_client_list = false;
list_add_tail(&desc->node, &d40c->pending_queue);
}
@@ -803,6 +808,7 @@
static void d40_term_all(struct d40_chan *d40c)
{
struct d40_desc *d40d;
+ struct d40_desc *_d;
/* Release active descriptors */
while ((d40d = d40_first_active_get(d40c))) {
@@ -822,6 +828,21 @@
d40_desc_free(d40c, d40d);
}
+ /* Release client owned descriptors */
+ if (!list_empty(&d40c->client))
+ list_for_each_entry_safe(d40d, _d, &d40c->client, node) {
+ d40_desc_remove(d40d);
+ d40_desc_free(d40c, d40d);
+ }
+
+ /* Release descriptors in prepare queue */
+ if (!list_empty(&d40c->prepare_queue))
+ list_for_each_entry_safe(d40d, _d,
+ &d40c->prepare_queue, node) {
+ d40_desc_remove(d40d);
+ d40_desc_free(d40c, d40d);
+ }
+
d40c->pending_tx = 0;
d40c->busy = false;
}
@@ -1208,7 +1229,6 @@
if (!d40d->cyclic) {
if (async_tx_test_ack(&d40d->txd)) {
- d40_pool_lli_free(d40c, d40d);
d40_desc_remove(d40d);
d40_desc_free(d40c, d40d);
} else {
@@ -1595,21 +1615,10 @@
u32 event;
struct d40_phy_res *phy = d40c->phy_chan;
bool is_src;
- struct d40_desc *d;
- struct d40_desc *_d;
-
/* Terminate all queued and active transfers */
d40_term_all(d40c);
- /* Release client owned descriptors */
- if (!list_empty(&d40c->client))
- list_for_each_entry_safe(d, _d, &d40c->client, node) {
- d40_pool_lli_free(d40c, d);
- d40_desc_remove(d);
- d40_desc_free(d40c, d);
- }
-
if (phy == NULL) {
chan_err(d40c, "phy == null\n");
return -EINVAL;
@@ -1911,6 +1920,12 @@
goto err;
}
+ /*
+ * add descriptor to the prepare queue in order to be able
+ * to free them later in terminate_all
+ */
+ list_add_tail(&desc->node, &chan->prepare_queue);
+
spin_unlock_irqrestore(&chan->lock, flags);
return &desc->txd;
@@ -2400,6 +2415,7 @@
INIT_LIST_HEAD(&d40c->queue);
INIT_LIST_HEAD(&d40c->pending_queue);
INIT_LIST_HEAD(&d40c->client);
+ INIT_LIST_HEAD(&d40c->prepare_queue);
tasklet_init(&d40c->tasklet, dma_tasklet,
(unsigned long) d40c);
diff --git a/drivers/firewire/sbp2.c b/drivers/firewire/sbp2.c
index 41841a3..17cef86 100644
--- a/drivers/firewire/sbp2.c
+++ b/drivers/firewire/sbp2.c
@@ -1198,6 +1198,10 @@
{
struct fw_unit *unit = fw_unit(dev);
struct sbp2_target *tgt = dev_get_drvdata(&unit->device);
+ struct sbp2_logical_unit *lu;
+
+ list_for_each_entry(lu, &tgt->lu_list, link)
+ cancel_delayed_work_sync(&lu->work);
sbp2_target_put(tgt);
return 0;
diff --git a/drivers/firmware/google/gsmi.c b/drivers/firmware/google/gsmi.c
index 68810fd..aa83de9 100644
--- a/drivers/firmware/google/gsmi.c
+++ b/drivers/firmware/google/gsmi.c
@@ -420,7 +420,7 @@
static efi_status_t gsmi_set_variable(efi_char16_t *name,
efi_guid_t *vendor,
- unsigned long attr,
+ u32 attr,
unsigned long data_size,
void *data)
{
diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c
index 82db185..fe738f0 100644
--- a/drivers/gpu/drm/drm_crtc.c
+++ b/drivers/gpu/drm/drm_crtc.c
@@ -499,6 +499,7 @@
mutex_lock(&dev->mode_config.mutex);
drm_mode_object_put(dev, &connector->base);
list_del(&connector->head);
+ dev->mode_config.num_connector--;
mutex_unlock(&dev->mode_config.mutex);
}
EXPORT_SYMBOL(drm_connector_cleanup);
@@ -529,6 +530,7 @@
mutex_lock(&dev->mode_config.mutex);
drm_mode_object_put(dev, &encoder->base);
list_del(&encoder->head);
+ dev->mode_config.num_encoder--;
mutex_unlock(&dev->mode_config.mutex);
}
EXPORT_SYMBOL(drm_encoder_cleanup);
diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c
index 802b61a..f7c6854 100644
--- a/drivers/gpu/drm/drm_fb_helper.c
+++ b/drivers/gpu/drm/drm_fb_helper.c
@@ -256,7 +256,6 @@
{
printk(KERN_ERR "panic occurred, switching back to text console\n");
return drm_fb_helper_force_kernel_mode();
- return 0;
}
EXPORT_SYMBOL(drm_fb_helper_panic);
diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
index ee1d701..56a8554 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -878,7 +878,7 @@
int pp_reg, lvds_reg;
u32 val;
enum pipe panel_pipe = PIPE_A;
- bool locked = locked;
+ bool locked = true;
if (HAS_PCH_SPLIT(dev_priv->dev)) {
pp_reg = PCH_PP_CONTROL;
@@ -7238,8 +7238,6 @@
intel_encoder_clones(dev, encoder->clone_mask);
}
- intel_panel_setup_backlight(dev);
-
/* disable all the possible outputs/crtcs before entering KMS mode */
drm_helper_disable_unused_functions(dev);
}
diff --git a/drivers/gpu/drm/nouveau/nouveau_fence.c b/drivers/gpu/drm/nouveau/nouveau_fence.c
index 8d02d87..c919cfc 100644
--- a/drivers/gpu/drm/nouveau/nouveau_fence.c
+++ b/drivers/gpu/drm/nouveau/nouveau_fence.c
@@ -530,7 +530,8 @@
nouveau_gpuobj_ref(NULL, &obj);
if (ret)
return ret;
- } else {
+ } else
+ if (USE_SEMA(dev)) {
/* map fence bo into channel's vm */
ret = nouveau_bo_vma_add(dev_priv->fence.bo, chan->vm,
&chan->fence.vma);
diff --git a/drivers/gpu/drm/nouveau/nouveau_sgdma.c b/drivers/gpu/drm/nouveau/nouveau_sgdma.c
index c444cad..2706cb3 100644
--- a/drivers/gpu/drm/nouveau/nouveau_sgdma.c
+++ b/drivers/gpu/drm/nouveau/nouveau_sgdma.c
@@ -37,8 +37,11 @@
return -ENOMEM;
nvbe->ttm_alloced = kmalloc(sizeof(bool) * num_pages, GFP_KERNEL);
- if (!nvbe->ttm_alloced)
+ if (!nvbe->ttm_alloced) {
+ kfree(nvbe->pages);
+ nvbe->pages = NULL;
return -ENOMEM;
+ }
nvbe->nr_pages = 0;
while (num_pages--) {
@@ -126,7 +129,7 @@
for (j = 0; j < PAGE_SIZE / NV_CTXDMA_PAGE_SIZE; j++, pte++) {
nv_wo32(gpuobj, (pte * 4) + 0, offset_l | 3);
- dma_offset += NV_CTXDMA_PAGE_SIZE;
+ offset_l += NV_CTXDMA_PAGE_SIZE;
}
}
diff --git a/drivers/gpu/drm/nouveau/nv04_crtc.c b/drivers/gpu/drm/nouveau/nv04_crtc.c
index 118261d..5e45398 100644
--- a/drivers/gpu/drm/nouveau/nv04_crtc.c
+++ b/drivers/gpu/drm/nouveau/nv04_crtc.c
@@ -781,11 +781,20 @@
struct drm_device *dev = crtc->dev;
struct drm_nouveau_private *dev_priv = dev->dev_private;
struct nv04_crtc_reg *regp = &dev_priv->mode_reg.crtc_reg[nv_crtc->index];
- struct drm_framebuffer *drm_fb = nv_crtc->base.fb;
- struct nouveau_framebuffer *fb = nouveau_framebuffer(drm_fb);
+ struct drm_framebuffer *drm_fb;
+ struct nouveau_framebuffer *fb;
int arb_burst, arb_lwm;
int ret;
+ NV_DEBUG_KMS(dev, "index %d\n", nv_crtc->index);
+
+ /* no fb bound */
+ if (!atomic && !crtc->fb) {
+ NV_DEBUG_KMS(dev, "No FB bound\n");
+ return 0;
+ }
+
+
/* If atomic, we want to switch to the fb we were passed, so
* now we update pointers to do that. (We don't pin; just
* assume we're already pinned and update the base address.)
@@ -794,6 +803,8 @@
drm_fb = passed_fb;
fb = nouveau_framebuffer(passed_fb);
} else {
+ drm_fb = crtc->fb;
+ fb = nouveau_framebuffer(crtc->fb);
/* If not atomic, we can go ahead and pin, and unpin the
* old fb we were passed.
*/
diff --git a/drivers/gpu/drm/nouveau/nv50_crtc.c b/drivers/gpu/drm/nouveau/nv50_crtc.c
index 46ad59e..5d989073 100644
--- a/drivers/gpu/drm/nouveau/nv50_crtc.c
+++ b/drivers/gpu/drm/nouveau/nv50_crtc.c
@@ -519,12 +519,18 @@
struct drm_device *dev = nv_crtc->base.dev;
struct drm_nouveau_private *dev_priv = dev->dev_private;
struct nouveau_channel *evo = nv50_display(dev)->master;
- struct drm_framebuffer *drm_fb = nv_crtc->base.fb;
- struct nouveau_framebuffer *fb = nouveau_framebuffer(drm_fb);
+ struct drm_framebuffer *drm_fb;
+ struct nouveau_framebuffer *fb;
int ret;
NV_DEBUG_KMS(dev, "index %d\n", nv_crtc->index);
+ /* no fb bound */
+ if (!atomic && !crtc->fb) {
+ NV_DEBUG_KMS(dev, "No FB bound\n");
+ return 0;
+ }
+
/* If atomic, we want to switch to the fb we were passed, so
* now we update pointers to do that. (We don't pin; just
* assume we're already pinned and update the base address.)
@@ -533,6 +539,8 @@
drm_fb = passed_fb;
fb = nouveau_framebuffer(passed_fb);
} else {
+ drm_fb = crtc->fb;
+ fb = nouveau_framebuffer(crtc->fb);
/* If not atomic, we can go ahead and pin, and unpin the
* old fb we were passed.
*/
diff --git a/drivers/gpu/drm/radeon/evergreen.c b/drivers/gpu/drm/radeon/evergreen.c
index fb5fa08..dc0a5b5 100644
--- a/drivers/gpu/drm/radeon/evergreen.c
+++ b/drivers/gpu/drm/radeon/evergreen.c
@@ -41,6 +41,31 @@
void evergreen_fini(struct radeon_device *rdev);
static void evergreen_pcie_gen2_enable(struct radeon_device *rdev);
+void evergreen_fix_pci_max_read_req_size(struct radeon_device *rdev)
+{
+ u16 ctl, v;
+ int cap, err;
+
+ cap = pci_pcie_cap(rdev->pdev);
+ if (!cap)
+ return;
+
+ err = pci_read_config_word(rdev->pdev, cap + PCI_EXP_DEVCTL, &ctl);
+ if (err)
+ return;
+
+ v = (ctl & PCI_EXP_DEVCTL_READRQ) >> 12;
+
+ /* if bios or OS sets MAX_READ_REQUEST_SIZE to an invalid value, fix it
+ * to avoid hangs or perfomance issues
+ */
+ if ((v == 0) || (v == 6) || (v == 7)) {
+ ctl &= ~PCI_EXP_DEVCTL_READRQ;
+ ctl |= (2 << 12);
+ pci_write_config_word(rdev->pdev, cap + PCI_EXP_DEVCTL, ctl);
+ }
+}
+
void evergreen_pre_page_flip(struct radeon_device *rdev, int crtc)
{
/* enable the pflip int */
@@ -1357,6 +1382,7 @@
SOFT_RESET_PA |
SOFT_RESET_SH |
SOFT_RESET_VGT |
+ SOFT_RESET_SPI |
SOFT_RESET_SX));
RREG32(GRBM_SOFT_RESET);
mdelay(15);
@@ -1862,6 +1888,8 @@
WREG32(GRBM_CNTL, GRBM_READ_TIMEOUT(0xff));
+ evergreen_fix_pci_max_read_req_size(rdev);
+
cc_gc_shader_pipe_config = RREG32(CC_GC_SHADER_PIPE_CONFIG) & ~2;
cc_gc_shader_pipe_config |=
diff --git a/drivers/gpu/drm/radeon/ni.c b/drivers/gpu/drm/radeon/ni.c
index 44c4750..cbf57d7 100644
--- a/drivers/gpu/drm/radeon/ni.c
+++ b/drivers/gpu/drm/radeon/ni.c
@@ -39,6 +39,7 @@
extern void evergreen_mc_program(struct radeon_device *rdev);
extern void evergreen_irq_suspend(struct radeon_device *rdev);
extern int evergreen_mc_init(struct radeon_device *rdev);
+extern void evergreen_fix_pci_max_read_req_size(struct radeon_device *rdev);
#define EVERGREEN_PFP_UCODE_SIZE 1120
#define EVERGREEN_PM4_UCODE_SIZE 1376
@@ -669,6 +670,8 @@
WREG32(GRBM_CNTL, GRBM_READ_TIMEOUT(0xff));
+ evergreen_fix_pci_max_read_req_size(rdev);
+
mc_shared_chmap = RREG32(MC_SHARED_CHMAP);
mc_arb_ramcfg = RREG32(MC_ARB_RAMCFG);
@@ -1159,6 +1162,7 @@
SOFT_RESET_PA |
SOFT_RESET_SH |
SOFT_RESET_VGT |
+ SOFT_RESET_SPI |
SOFT_RESET_SX));
RREG32(GRBM_SOFT_RESET);
mdelay(15);
diff --git a/drivers/gpu/drm/radeon/radeon_clocks.c b/drivers/gpu/drm/radeon/radeon_clocks.c
index dcd0863e..b6e18c8 100644
--- a/drivers/gpu/drm/radeon/radeon_clocks.c
+++ b/drivers/gpu/drm/radeon/radeon_clocks.c
@@ -219,6 +219,9 @@
} else {
DRM_INFO("Using generic clock info\n");
+ /* may need to be per card */
+ rdev->clock.max_pixel_clock = 35000;
+
if (rdev->flags & RADEON_IS_IGP) {
p1pll->reference_freq = 1432;
p2pll->reference_freq = 1432;
diff --git a/drivers/gpu/drm/radeon/radeon_combios.c b/drivers/gpu/drm/radeon/radeon_combios.c
index e0138b6..6367524 100644
--- a/drivers/gpu/drm/radeon/radeon_combios.c
+++ b/drivers/gpu/drm/radeon/radeon_combios.c
@@ -3298,6 +3298,14 @@
rdev->pdev->subsystem_device == 0x30a4)
return;
+ /* quirk for rs4xx Compaq Presario V5245EU laptop to make it resume
+ * - it hangs on resume inside the dynclk 1 table.
+ */
+ if (rdev->family == CHIP_RS480 &&
+ rdev->pdev->subsystem_vendor == 0x103c &&
+ rdev->pdev->subsystem_device == 0x30ae)
+ return;
+
/* DYN CLK 1 */
table = combios_get_table_offset(dev, COMBIOS_DYN_CLK_1_TABLE);
if (table)
diff --git a/drivers/gpu/drm/radeon/radeon_connectors.c b/drivers/gpu/drm/radeon/radeon_connectors.c
index 7f65940..c4b8741 100644
--- a/drivers/gpu/drm/radeon/radeon_connectors.c
+++ b/drivers/gpu/drm/radeon/radeon_connectors.c
@@ -466,6 +466,16 @@
(supported_device == ATOM_DEVICE_DFP2_SUPPORT))
return true;
}
+ /* TOSHIBA Satellite L300D with ATI Mobility Radeon x1100
+ * (RS690M) sends data to i2c bus for a HDMI connector that
+ * is not implemented */
+ if ((dev->pdev->device == 0x791f) &&
+ (dev->pdev->subsystem_vendor == 0x1179) &&
+ (dev->pdev->subsystem_device == 0xff68)) {
+ if ((connector_type == DRM_MODE_CONNECTOR_HDMIA) &&
+ (supported_device == ATOM_DEVICE_DFP2_SUPPORT))
+ return true;
+ }
/* Default: no EDID header probe required for DDC probing */
return false;
@@ -1287,12 +1297,33 @@
if (!radeon_dig_connector->edp_on)
atombios_set_edp_panel_power(connector,
ATOM_TRANSMITTER_ACTION_POWER_OFF);
- } else {
- /* need to setup ddc on the bridge */
- if (radeon_connector_encoder_is_dp_bridge(connector)) {
+ } else if (radeon_connector_encoder_is_dp_bridge(connector)) {
+ /* DP bridges are always DP */
+ radeon_dig_connector->dp_sink_type = CONNECTOR_OBJECT_ID_DISPLAYPORT;
+ /* get the DPCD from the bridge */
+ radeon_dp_getdpcd(radeon_connector);
+
+ if (radeon_hpd_sense(rdev, radeon_connector->hpd.hpd))
+ ret = connector_status_connected;
+ else {
+ /* need to setup ddc on the bridge */
if (encoder)
radeon_atom_ext_encoder_setup_ddc(encoder);
+ if (radeon_ddc_probe(radeon_connector,
+ radeon_connector->requires_extended_probe))
+ ret = connector_status_connected;
}
+
+ if ((ret == connector_status_disconnected) &&
+ radeon_connector->dac_load_detect) {
+ struct drm_encoder *encoder = radeon_best_single_encoder(connector);
+ struct drm_encoder_helper_funcs *encoder_funcs;
+ if (encoder) {
+ encoder_funcs = encoder->helper_private;
+ ret = encoder_funcs->detect(encoder, connector);
+ }
+ }
+ } else {
radeon_dig_connector->dp_sink_type = radeon_dp_getsinktype(radeon_connector);
if (radeon_hpd_sense(rdev, radeon_connector->hpd.hpd)) {
ret = connector_status_connected;
@@ -1308,16 +1339,6 @@
ret = connector_status_connected;
}
}
-
- if ((ret == connector_status_disconnected) &&
- radeon_connector->dac_load_detect) {
- struct drm_encoder *encoder = radeon_best_single_encoder(connector);
- struct drm_encoder_helper_funcs *encoder_funcs;
- if (encoder) {
- encoder_funcs = encoder->helper_private;
- ret = encoder_funcs->detect(encoder, connector);
- }
- }
}
radeon_connector_update_scratch_regs(connector, ret);
diff --git a/drivers/gpu/drm/radeon/radeon_device.c b/drivers/gpu/drm/radeon/radeon_device.c
index a3b011b..b51e157 100644
--- a/drivers/gpu/drm/radeon/radeon_device.c
+++ b/drivers/gpu/drm/radeon/radeon_device.c
@@ -301,6 +301,8 @@
mc->mc_vram_size = mc->aper_size;
}
mc->vram_end = mc->vram_start + mc->mc_vram_size - 1;
+ if (radeon_vram_limit && radeon_vram_limit < mc->real_vram_size)
+ mc->real_vram_size = radeon_vram_limit;
dev_info(rdev->dev, "VRAM: %lluM 0x%016llX - 0x%016llX (%lluM used)\n",
mc->mc_vram_size >> 20, mc->vram_start,
mc->vram_end, mc->real_vram_size >> 20);
diff --git a/drivers/gpu/drm/radeon/radeon_display.c b/drivers/gpu/drm/radeon/radeon_display.c
index 1a85894..6cc17fb 100644
--- a/drivers/gpu/drm/radeon/radeon_display.c
+++ b/drivers/gpu/drm/radeon/radeon_display.c
@@ -707,16 +707,21 @@
radeon_router_select_ddc_port(radeon_connector);
if ((radeon_connector->base.connector_type == DRM_MODE_CONNECTOR_DisplayPort) ||
- (radeon_connector->base.connector_type == DRM_MODE_CONNECTOR_eDP)) {
+ (radeon_connector->base.connector_type == DRM_MODE_CONNECTOR_eDP) ||
+ radeon_connector_encoder_is_dp_bridge(&radeon_connector->base)) {
struct radeon_connector_atom_dig *dig = radeon_connector->con_priv;
+
if ((dig->dp_sink_type == CONNECTOR_OBJECT_ID_DISPLAYPORT ||
dig->dp_sink_type == CONNECTOR_OBJECT_ID_eDP) && dig->dp_i2c_bus)
- radeon_connector->edid = drm_get_edid(&radeon_connector->base, &dig->dp_i2c_bus->adapter);
- }
- if (!radeon_connector->ddc_bus)
- return -1;
- if (!radeon_connector->edid) {
- radeon_connector->edid = drm_get_edid(&radeon_connector->base, &radeon_connector->ddc_bus->adapter);
+ radeon_connector->edid = drm_get_edid(&radeon_connector->base,
+ &dig->dp_i2c_bus->adapter);
+ else if (radeon_connector->ddc_bus && !radeon_connector->edid)
+ radeon_connector->edid = drm_get_edid(&radeon_connector->base,
+ &radeon_connector->ddc_bus->adapter);
+ } else {
+ if (radeon_connector->ddc_bus && !radeon_connector->edid)
+ radeon_connector->edid = drm_get_edid(&radeon_connector->base,
+ &radeon_connector->ddc_bus->adapter);
}
if (!radeon_connector->edid) {
diff --git a/drivers/gpu/drm/radeon/radeon_test.c b/drivers/gpu/drm/radeon/radeon_test.c
index dee4a0c..602fa35 100644
--- a/drivers/gpu/drm/radeon/radeon_test.c
+++ b/drivers/gpu/drm/radeon/radeon_test.c
@@ -40,10 +40,14 @@
size = 1024 * 1024;
/* Number of tests =
- * (Total GTT - IB pool - writeback page - ring buffer) / test size
+ * (Total GTT - IB pool - writeback page - ring buffers) / test size
*/
- n = ((u32)(rdev->mc.gtt_size - RADEON_IB_POOL_SIZE*64*1024 - RADEON_GPU_PAGE_SIZE -
- rdev->cp.ring_size)) / size;
+ n = rdev->mc.gtt_size - RADEON_IB_POOL_SIZE*64*1024 - rdev->cp.ring_size;
+ if (rdev->wb.wb_obj)
+ n -= RADEON_GPU_PAGE_SIZE;
+ if (rdev->ih.ring_obj)
+ n -= rdev->ih.ring_size;
+ n /= size;
gtt_obj = kzalloc(n * sizeof(*gtt_obj), GFP_KERNEL);
if (!gtt_obj) {
@@ -132,9 +136,15 @@
gtt_start++, vram_start++) {
if (*vram_start != gtt_start) {
DRM_ERROR("Incorrect GTT->VRAM copy %d: Got 0x%p, "
- "expected 0x%p (GTT map 0x%p-0x%p)\n",
- i, *vram_start, gtt_start, gtt_map,
- gtt_end);
+ "expected 0x%p (GTT/VRAM offset "
+ "0x%16llx/0x%16llx)\n",
+ i, *vram_start, gtt_start,
+ (unsigned long long)
+ (gtt_addr - rdev->mc.gtt_start +
+ (void*)gtt_start - gtt_map),
+ (unsigned long long)
+ (vram_addr - rdev->mc.vram_start +
+ (void*)gtt_start - gtt_map));
radeon_bo_kunmap(vram_obj);
goto out_cleanup;
}
@@ -175,9 +185,15 @@
gtt_start++, vram_start++) {
if (*gtt_start != vram_start) {
DRM_ERROR("Incorrect VRAM->GTT copy %d: Got 0x%p, "
- "expected 0x%p (VRAM map 0x%p-0x%p)\n",
- i, *gtt_start, vram_start, vram_map,
- vram_end);
+ "expected 0x%p (VRAM/GTT offset "
+ "0x%16llx/0x%16llx)\n",
+ i, *gtt_start, vram_start,
+ (unsigned long long)
+ (vram_addr - rdev->mc.vram_start +
+ (void*)vram_start - vram_map),
+ (unsigned long long)
+ (gtt_addr - rdev->mc.gtt_start +
+ (void*)vram_start - vram_map));
radeon_bo_kunmap(gtt_obj[i]);
goto out_cleanup;
}
diff --git a/drivers/gpu/drm/radeon/radeon_ttm.c b/drivers/gpu/drm/radeon/radeon_ttm.c
index 60125dd..9b86fb0 100644
--- a/drivers/gpu/drm/radeon/radeon_ttm.c
+++ b/drivers/gpu/drm/radeon/radeon_ttm.c
@@ -450,6 +450,29 @@
return -EINVAL;
mem->bus.base = rdev->mc.aper_base;
mem->bus.is_iomem = true;
+#ifdef __alpha__
+ /*
+ * Alpha: use bus.addr to hold the ioremap() return,
+ * so we can modify bus.base below.
+ */
+ if (mem->placement & TTM_PL_FLAG_WC)
+ mem->bus.addr =
+ ioremap_wc(mem->bus.base + mem->bus.offset,
+ mem->bus.size);
+ else
+ mem->bus.addr =
+ ioremap_nocache(mem->bus.base + mem->bus.offset,
+ mem->bus.size);
+
+ /*
+ * Alpha: Use just the bus offset plus
+ * the hose/domain memory base for bus.base.
+ * It then can be used to build PTEs for VRAM
+ * access, as done in ttm_bo_vm_fault().
+ */
+ mem->bus.base = (mem->bus.base & 0x0ffffffffUL) +
+ rdev->ddev->hose->dense_mem_base;
+#endif
break;
default:
return -EINVAL;
diff --git a/drivers/gpu/drm/ttm/ttm_bo.c b/drivers/gpu/drm/ttm/ttm_bo.c
index 56619f6..a4d38d8 100644
--- a/drivers/gpu/drm/ttm/ttm_bo.c
+++ b/drivers/gpu/drm/ttm/ttm_bo.c
@@ -353,8 +353,10 @@
ret = ttm_tt_set_user(bo->ttm, current,
bo->buffer_start, bo->num_pages);
- if (unlikely(ret != 0))
+ if (unlikely(ret != 0)) {
ttm_tt_destroy(bo->ttm);
+ bo->ttm = NULL;
+ }
break;
default:
printk(KERN_ERR TTM_PFX "Illegal buffer object type\n");
@@ -390,10 +392,12 @@
* Create and bind a ttm if required.
*/
- if (!(new_man->flags & TTM_MEMTYPE_FLAG_FIXED) && (bo->ttm == NULL)) {
- ret = ttm_bo_add_ttm(bo, false);
- if (ret)
- goto out_err;
+ if (!(new_man->flags & TTM_MEMTYPE_FLAG_FIXED)) {
+ if (bo->ttm == NULL) {
+ ret = ttm_bo_add_ttm(bo, false);
+ if (ret)
+ goto out_err;
+ }
ret = ttm_tt_set_placement_caching(bo->ttm, mem->placement);
if (ret)
diff --git a/drivers/gpu/drm/ttm/ttm_bo_util.c b/drivers/gpu/drm/ttm/ttm_bo_util.c
index 77dbf40..ae3c6f5 100644
--- a/drivers/gpu/drm/ttm/ttm_bo_util.c
+++ b/drivers/gpu/drm/ttm/ttm_bo_util.c
@@ -635,13 +635,13 @@
if (ret)
return ret;
- ttm_bo_free_old_node(bo);
if ((man->flags & TTM_MEMTYPE_FLAG_FIXED) &&
(bo->ttm != NULL)) {
ttm_tt_unbind(bo->ttm);
ttm_tt_destroy(bo->ttm);
bo->ttm = NULL;
}
+ ttm_bo_free_old_node(bo);
} else {
/**
* This should help pipeline ordinary buffer moves.
diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig
index 306b15f..1130a89 100644
--- a/drivers/hid/Kconfig
+++ b/drivers/hid/Kconfig
@@ -589,6 +589,7 @@
config HID_WIIMOTE
tristate "Nintendo Wii Remote support"
depends on BT_HIDP
+ depends on LEDS_CLASS
---help---
Support for the Nintendo Wii Remote bluetooth device.
diff --git a/drivers/hid/hid-apple.c b/drivers/hid/hid-apple.c
index b85744f..18b3bc6 100644
--- a/drivers/hid/hid-apple.c
+++ b/drivers/hid/hid-apple.c
@@ -444,6 +444,12 @@
{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER4_HF_JIS),
.driver_data = APPLE_NUMLOCK_EMULATION | APPLE_HAS_FN |
APPLE_RDESC_JIS },
+ { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_REVB_ANSI),
+ .driver_data = APPLE_HAS_FN },
+ { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_REVB_ISO),
+ .driver_data = APPLE_HAS_FN | APPLE_ISO_KEYBOARD },
+ { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_REVB_JIS),
+ .driver_data = APPLE_HAS_FN },
{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_ANSI),
.driver_data = APPLE_NUMLOCK_EMULATION | APPLE_HAS_FN },
{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_ISO),
diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c
index 1a5cf0c..242353d 100644
--- a/drivers/hid/hid-core.c
+++ b/drivers/hid/hid-core.c
@@ -1340,6 +1340,9 @@
{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING5_ANSI) },
{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING5_ISO) },
{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING5_JIS) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_REVB_ANSI) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_REVB_ISO) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_REVB_JIS) },
{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_ANSI) },
{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_ISO) },
{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_JIS) },
diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h
index db63ccf..7484e1b 100644
--- a/drivers/hid/hid-ids.h
+++ b/drivers/hid/hid-ids.h
@@ -109,6 +109,9 @@
#define USB_DEVICE_ID_APPLE_WELLSPRING5_ANSI 0x0245
#define USB_DEVICE_ID_APPLE_WELLSPRING5_ISO 0x0246
#define USB_DEVICE_ID_APPLE_WELLSPRING5_JIS 0x0247
+#define USB_DEVICE_ID_APPLE_ALU_REVB_ANSI 0x024f
+#define USB_DEVICE_ID_APPLE_ALU_REVB_ISO 0x0250
+#define USB_DEVICE_ID_APPLE_ALU_REVB_JIS 0x0251
#define USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_ANSI 0x0239
#define USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_ISO 0x023a
#define USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_JIS 0x023b
@@ -274,6 +277,7 @@
#define USB_DEVICE_ID_PENPOWER 0x00f4
#define USB_VENDOR_ID_GREENASIA 0x0e8f
+#define USB_DEVICE_ID_GREENASIA_DUAL_USB_JOYPAD 0x3013
#define USB_VENDOR_ID_GRETAGMACBETH 0x0971
#define USB_DEVICE_ID_GRETAGMACBETH_HUEY 0x2005
@@ -576,6 +580,9 @@
#define USB_DEVICE_ID_SAMSUNG_IR_REMOTE 0x0001
#define USB_DEVICE_ID_SAMSUNG_WIRELESS_KBD_MOUSE 0x0600
+#define USB_VENDOR_ID_SIGMA_MICRO 0x1c4f
+#define USB_DEVICE_ID_SIGMA_MICRO_KEYBOARD 0x0002
+
#define USB_VENDOR_ID_SKYCABLE 0x1223
#define USB_DEVICE_ID_SKYCABLE_WIRELESS_PRESENTER 0x3F07
diff --git a/drivers/hid/hid-magicmouse.c b/drivers/hid/hid-magicmouse.c
index 0ec91c1..f0fbd7b 100644
--- a/drivers/hid/hid-magicmouse.c
+++ b/drivers/hid/hid-magicmouse.c
@@ -81,6 +81,28 @@
#define NO_TOUCHES -1
#define SINGLE_TOUCH_UP -2
+/* Touch surface information. Dimension is in hundredths of a mm, min and max
+ * are in units. */
+#define MOUSE_DIMENSION_X (float)9056
+#define MOUSE_MIN_X -1100
+#define MOUSE_MAX_X 1258
+#define MOUSE_RES_X ((MOUSE_MAX_X - MOUSE_MIN_X) / (MOUSE_DIMENSION_X / 100))
+#define MOUSE_DIMENSION_Y (float)5152
+#define MOUSE_MIN_Y -1589
+#define MOUSE_MAX_Y 2047
+#define MOUSE_RES_Y ((MOUSE_MAX_Y - MOUSE_MIN_Y) / (MOUSE_DIMENSION_Y / 100))
+
+#define TRACKPAD_DIMENSION_X (float)13000
+#define TRACKPAD_MIN_X -2909
+#define TRACKPAD_MAX_X 3167
+#define TRACKPAD_RES_X \
+ ((TRACKPAD_MAX_X - TRACKPAD_MIN_X) / (TRACKPAD_DIMENSION_X / 100))
+#define TRACKPAD_DIMENSION_Y (float)11000
+#define TRACKPAD_MIN_Y -2456
+#define TRACKPAD_MAX_Y 2565
+#define TRACKPAD_RES_Y \
+ ((TRACKPAD_MAX_Y - TRACKPAD_MIN_Y) / (TRACKPAD_DIMENSION_Y / 100))
+
/**
* struct magicmouse_sc - Tracks Magic Mouse-specific data.
* @input: Input device through which we report events.
@@ -406,17 +428,31 @@
* inverse of the reported Y.
*/
if (input->id.product == USB_DEVICE_ID_APPLE_MAGICMOUSE) {
- input_set_abs_params(input, ABS_MT_POSITION_X, -1100,
- 1358, 4, 0);
- input_set_abs_params(input, ABS_MT_POSITION_Y, -1589,
- 2047, 4, 0);
+ input_set_abs_params(input, ABS_MT_POSITION_X,
+ MOUSE_MIN_X, MOUSE_MAX_X, 4, 0);
+ input_set_abs_params(input, ABS_MT_POSITION_Y,
+ MOUSE_MIN_Y, MOUSE_MAX_Y, 4, 0);
+
+ input_abs_set_res(input, ABS_MT_POSITION_X,
+ MOUSE_RES_X);
+ input_abs_set_res(input, ABS_MT_POSITION_Y,
+ MOUSE_RES_Y);
} else { /* USB_DEVICE_ID_APPLE_MAGICTRACKPAD */
- input_set_abs_params(input, ABS_X, -2909, 3167, 4, 0);
- input_set_abs_params(input, ABS_Y, -2456, 2565, 4, 0);
- input_set_abs_params(input, ABS_MT_POSITION_X, -2909,
- 3167, 4, 0);
- input_set_abs_params(input, ABS_MT_POSITION_Y, -2456,
- 2565, 4, 0);
+ input_set_abs_params(input, ABS_X, TRACKPAD_MIN_X,
+ TRACKPAD_MAX_X, 4, 0);
+ input_set_abs_params(input, ABS_Y, TRACKPAD_MIN_Y,
+ TRACKPAD_MAX_Y, 4, 0);
+ input_set_abs_params(input, ABS_MT_POSITION_X,
+ TRACKPAD_MIN_X, TRACKPAD_MAX_X, 4, 0);
+ input_set_abs_params(input, ABS_MT_POSITION_Y,
+ TRACKPAD_MIN_Y, TRACKPAD_MAX_Y, 4, 0);
+
+ input_abs_set_res(input, ABS_X, TRACKPAD_RES_X);
+ input_abs_set_res(input, ABS_Y, TRACKPAD_RES_Y);
+ input_abs_set_res(input, ABS_MT_POSITION_X,
+ TRACKPAD_RES_X);
+ input_abs_set_res(input, ABS_MT_POSITION_Y,
+ TRACKPAD_RES_Y);
}
input_set_events_per_packet(input, 60);
@@ -501,9 +537,17 @@
}
report->size = 6;
+ /*
+ * Some devices repond with 'invalid report id' when feature
+ * report switching it into multitouch mode is sent to it.
+ *
+ * This results in -EIO from the _raw low-level transport callback,
+ * but there seems to be no other way of switching the mode.
+ * Thus the super-ugly hacky success check below.
+ */
ret = hdev->hid_output_raw_report(hdev, feature, sizeof(feature),
HID_FEATURE_REPORT);
- if (ret != sizeof(feature)) {
+ if (ret != -EIO && ret != sizeof(feature)) {
hid_err(hdev, "unable to request touch data (%d)\n", ret);
goto err_stop_hw;
}
diff --git a/drivers/hid/hid-wacom.c b/drivers/hid/hid-wacom.c
index 0688832..a597039 100644
--- a/drivers/hid/hid-wacom.c
+++ b/drivers/hid/hid-wacom.c
@@ -353,11 +353,7 @@
if (ret) {
hid_warn(hdev, "can't create sysfs battery attribute, err: %d\n",
ret);
- /*
- * battery attribute is not critical for the tablet, but if it
- * failed then there is no need to create ac attribute
- */
- goto move_on;
+ goto err_battery;
}
wdata->ac.properties = wacom_ac_props;
@@ -371,14 +367,8 @@
if (ret) {
hid_warn(hdev,
"can't create ac battery attribute, err: %d\n", ret);
- /*
- * ac attribute is not critical for the tablet, but if it
- * failed then we don't want to battery attribute to exist
- */
- power_supply_unregister(&wdata->battery);
+ goto err_ac;
}
-
-move_on:
#endif
hidinput = list_entry(hdev->inputs.next, struct hid_input, list);
input = hidinput->input;
@@ -416,6 +406,13 @@
return 0;
+#ifdef CONFIG_HID_WACOM_POWER_SUPPLY
+err_ac:
+ power_supply_unregister(&wdata->battery);
+err_battery:
+ device_remove_file(&hdev->dev, &dev_attr_speed);
+ hid_hw_stop(hdev);
+#endif
err_free:
kfree(wdata);
return ret;
@@ -426,6 +423,7 @@
#ifdef CONFIG_HID_WACOM_POWER_SUPPLY
struct wacom_data *wdata = hid_get_drvdata(hdev);
#endif
+ device_remove_file(&hdev->dev, &dev_attr_speed);
hid_hw_stop(hdev);
#ifdef CONFIG_HID_WACOM_POWER_SUPPLY
diff --git a/drivers/hid/hid-wiimote.c b/drivers/hid/hid-wiimote.c
index a594383..85a02e5 100644
--- a/drivers/hid/hid-wiimote.c
+++ b/drivers/hid/hid-wiimote.c
@@ -10,10 +10,10 @@
* any later version.
*/
-#include <linux/atomic.h>
#include <linux/device.h>
#include <linux/hid.h>
#include <linux/input.h>
+#include <linux/leds.h>
#include <linux/module.h>
#include <linux/spinlock.h>
#include "hid-ids.h"
@@ -33,9 +33,9 @@
};
struct wiimote_data {
- atomic_t ready;
struct hid_device *hdev;
struct input_dev *input;
+ struct led_classdev *leds[4];
spinlock_t qlock;
__u8 head;
@@ -53,8 +53,15 @@
#define WIIPROTO_FLAGS_LEDS (WIIPROTO_FLAG_LED1 | WIIPROTO_FLAG_LED2 | \
WIIPROTO_FLAG_LED3 | WIIPROTO_FLAG_LED4)
+/* return flag for led \num */
+#define WIIPROTO_FLAG_LED(num) (WIIPROTO_FLAG_LED1 << (num - 1))
+
enum wiiproto_reqs {
+ WIIPROTO_REQ_NULL = 0x0,
WIIPROTO_REQ_LED = 0x11,
+ WIIPROTO_REQ_DRM = 0x12,
+ WIIPROTO_REQ_STATUS = 0x20,
+ WIIPROTO_REQ_RETURN = 0x22,
WIIPROTO_REQ_DRM_K = 0x30,
};
@@ -87,9 +94,6 @@
BTN_MODE, /* WIIPROTO_KEY_HOME */
};
-#define dev_to_wii(pdev) hid_get_drvdata(container_of(pdev, struct hid_device, \
- dev))
-
static ssize_t wiimote_hid_send(struct hid_device *hdev, __u8 *buffer,
size_t count)
{
@@ -192,66 +196,96 @@
wiimote_queue(wdata, cmd, sizeof(cmd));
}
-#define wiifs_led_show_set(num) \
-static ssize_t wiifs_led_show_##num(struct device *dev, \
- struct device_attribute *attr, char *buf) \
-{ \
- struct wiimote_data *wdata = dev_to_wii(dev); \
- unsigned long flags; \
- int state; \
- \
- if (!atomic_read(&wdata->ready)) \
- return -EBUSY; \
- \
- spin_lock_irqsave(&wdata->state.lock, flags); \
- state = !!(wdata->state.flags & WIIPROTO_FLAG_LED##num); \
- spin_unlock_irqrestore(&wdata->state.lock, flags); \
- \
- return sprintf(buf, "%d\n", state); \
-} \
-static ssize_t wiifs_led_set_##num(struct device *dev, \
- struct device_attribute *attr, const char *buf, size_t count) \
-{ \
- struct wiimote_data *wdata = dev_to_wii(dev); \
- int tmp = simple_strtoul(buf, NULL, 10); \
- unsigned long flags; \
- __u8 state; \
- \
- if (!atomic_read(&wdata->ready)) \
- return -EBUSY; \
- \
- spin_lock_irqsave(&wdata->state.lock, flags); \
- \
- state = wdata->state.flags; \
- \
- if (tmp) \
- wiiproto_req_leds(wdata, state | WIIPROTO_FLAG_LED##num);\
- else \
- wiiproto_req_leds(wdata, state & ~WIIPROTO_FLAG_LED##num);\
- \
- spin_unlock_irqrestore(&wdata->state.lock, flags); \
- \
- return count; \
-} \
-static DEVICE_ATTR(led##num, S_IRUGO | S_IWUSR, wiifs_led_show_##num, \
- wiifs_led_set_##num)
+/*
+ * Check what peripherals of the wiimote are currently
+ * active and select a proper DRM that supports all of
+ * the requested data inputs.
+ */
+static __u8 select_drm(struct wiimote_data *wdata)
+{
+ return WIIPROTO_REQ_DRM_K;
+}
-wiifs_led_show_set(1);
-wiifs_led_show_set(2);
-wiifs_led_show_set(3);
-wiifs_led_show_set(4);
+static void wiiproto_req_drm(struct wiimote_data *wdata, __u8 drm)
+{
+ __u8 cmd[3];
+
+ if (drm == WIIPROTO_REQ_NULL)
+ drm = select_drm(wdata);
+
+ cmd[0] = WIIPROTO_REQ_DRM;
+ cmd[1] = 0;
+ cmd[2] = drm;
+
+ wiimote_queue(wdata, cmd, sizeof(cmd));
+}
+
+static enum led_brightness wiimote_leds_get(struct led_classdev *led_dev)
+{
+ struct wiimote_data *wdata;
+ struct device *dev = led_dev->dev->parent;
+ int i;
+ unsigned long flags;
+ bool value = false;
+
+ wdata = hid_get_drvdata(container_of(dev, struct hid_device, dev));
+
+ for (i = 0; i < 4; ++i) {
+ if (wdata->leds[i] == led_dev) {
+ spin_lock_irqsave(&wdata->state.lock, flags);
+ value = wdata->state.flags & WIIPROTO_FLAG_LED(i + 1);
+ spin_unlock_irqrestore(&wdata->state.lock, flags);
+ break;
+ }
+ }
+
+ return value ? LED_FULL : LED_OFF;
+}
+
+static void wiimote_leds_set(struct led_classdev *led_dev,
+ enum led_brightness value)
+{
+ struct wiimote_data *wdata;
+ struct device *dev = led_dev->dev->parent;
+ int i;
+ unsigned long flags;
+ __u8 state, flag;
+
+ wdata = hid_get_drvdata(container_of(dev, struct hid_device, dev));
+
+ for (i = 0; i < 4; ++i) {
+ if (wdata->leds[i] == led_dev) {
+ flag = WIIPROTO_FLAG_LED(i + 1);
+ spin_lock_irqsave(&wdata->state.lock, flags);
+ state = wdata->state.flags;
+ if (value == LED_OFF)
+ wiiproto_req_leds(wdata, state & ~flag);
+ else
+ wiiproto_req_leds(wdata, state | flag);
+ spin_unlock_irqrestore(&wdata->state.lock, flags);
+ break;
+ }
+ }
+}
static int wiimote_input_event(struct input_dev *dev, unsigned int type,
unsigned int code, int value)
{
+ return 0;
+}
+
+static int wiimote_input_open(struct input_dev *dev)
+{
struct wiimote_data *wdata = input_get_drvdata(dev);
- if (!atomic_read(&wdata->ready))
- return -EBUSY;
- /* smp_rmb: Make sure wdata->xy is available when wdata->ready is 1 */
- smp_rmb();
+ return hid_hw_open(wdata->hdev);
+}
- return 0;
+static void wiimote_input_close(struct input_dev *dev)
+{
+ struct wiimote_data *wdata = input_get_drvdata(dev);
+
+ hid_hw_close(wdata->hdev);
}
static void handler_keys(struct wiimote_data *wdata, const __u8 *payload)
@@ -281,6 +315,26 @@
input_sync(wdata->input);
}
+static void handler_status(struct wiimote_data *wdata, const __u8 *payload)
+{
+ handler_keys(wdata, payload);
+
+ /* on status reports the drm is reset so we need to resend the drm */
+ wiiproto_req_drm(wdata, WIIPROTO_REQ_NULL);
+}
+
+static void handler_return(struct wiimote_data *wdata, const __u8 *payload)
+{
+ __u8 err = payload[3];
+ __u8 cmd = payload[2];
+
+ handler_keys(wdata, payload);
+
+ if (err)
+ hid_warn(wdata->hdev, "Remote error %hhu on req %hhu\n", err,
+ cmd);
+}
+
struct wiiproto_handler {
__u8 id;
size_t size;
@@ -288,6 +342,8 @@
};
static struct wiiproto_handler handlers[] = {
+ { .id = WIIPROTO_REQ_STATUS, .size = 6, .func = handler_status },
+ { .id = WIIPROTO_REQ_RETURN, .size = 4, .func = handler_return },
{ .id = WIIPROTO_REQ_DRM_K, .size = 2, .func = handler_keys },
{ .id = 0 }
};
@@ -300,11 +356,6 @@
int i;
unsigned long flags;
- if (!atomic_read(&wdata->ready))
- return -EBUSY;
- /* smp_rmb: Make sure wdata->xy is available when wdata->ready is 1 */
- smp_rmb();
-
if (size < 1)
return -EINVAL;
@@ -321,6 +372,58 @@
return 0;
}
+static void wiimote_leds_destroy(struct wiimote_data *wdata)
+{
+ int i;
+ struct led_classdev *led;
+
+ for (i = 0; i < 4; ++i) {
+ if (wdata->leds[i]) {
+ led = wdata->leds[i];
+ wdata->leds[i] = NULL;
+ led_classdev_unregister(led);
+ kfree(led);
+ }
+ }
+}
+
+static int wiimote_leds_create(struct wiimote_data *wdata)
+{
+ int i, ret;
+ struct device *dev = &wdata->hdev->dev;
+ size_t namesz = strlen(dev_name(dev)) + 9;
+ struct led_classdev *led;
+ char *name;
+
+ for (i = 0; i < 4; ++i) {
+ led = kzalloc(sizeof(struct led_classdev) + namesz, GFP_KERNEL);
+ if (!led) {
+ ret = -ENOMEM;
+ goto err;
+ }
+ name = (void*)&led[1];
+ snprintf(name, namesz, "%s:blue:p%d", dev_name(dev), i);
+ led->name = name;
+ led->brightness = 0;
+ led->max_brightness = 1;
+ led->brightness_get = wiimote_leds_get;
+ led->brightness_set = wiimote_leds_set;
+
+ ret = led_classdev_register(dev, led);
+ if (ret) {
+ kfree(led);
+ goto err;
+ }
+ wdata->leds[i] = led;
+ }
+
+ return 0;
+
+err:
+ wiimote_leds_destroy(wdata);
+ return ret;
+}
+
static struct wiimote_data *wiimote_create(struct hid_device *hdev)
{
struct wiimote_data *wdata;
@@ -341,6 +444,8 @@
input_set_drvdata(wdata->input, wdata);
wdata->input->event = wiimote_input_event;
+ wdata->input->open = wiimote_input_open;
+ wdata->input->close = wiimote_input_close;
wdata->input->dev.parent = &wdata->hdev->dev;
wdata->input->id.bustype = wdata->hdev->bus;
wdata->input->id.vendor = wdata->hdev->vendor;
@@ -362,6 +467,12 @@
static void wiimote_destroy(struct wiimote_data *wdata)
{
+ wiimote_leds_destroy(wdata);
+
+ input_unregister_device(wdata->input);
+ cancel_work_sync(&wdata->worker);
+ hid_hw_stop(wdata->hdev);
+
kfree(wdata);
}
@@ -377,19 +488,6 @@
return -ENOMEM;
}
- ret = device_create_file(&hdev->dev, &dev_attr_led1);
- if (ret)
- goto err;
- ret = device_create_file(&hdev->dev, &dev_attr_led2);
- if (ret)
- goto err;
- ret = device_create_file(&hdev->dev, &dev_attr_led3);
- if (ret)
- goto err;
- ret = device_create_file(&hdev->dev, &dev_attr_led4);
- if (ret)
- goto err;
-
ret = hid_parse(hdev);
if (ret) {
hid_err(hdev, "HID parse failed\n");
@@ -408,9 +506,10 @@
goto err_stop;
}
- /* smp_wmb: Write wdata->xy first before wdata->ready is set to 1 */
- smp_wmb();
- atomic_set(&wdata->ready, 1);
+ ret = wiimote_leds_create(wdata);
+ if (ret)
+ goto err_free;
+
hid_info(hdev, "New device registered\n");
/* by default set led1 after device initialization */
@@ -420,15 +519,15 @@
return 0;
+err_free:
+ wiimote_destroy(wdata);
+ return ret;
+
err_stop:
hid_hw_stop(hdev);
err:
input_free_device(wdata->input);
- device_remove_file(&hdev->dev, &dev_attr_led1);
- device_remove_file(&hdev->dev, &dev_attr_led2);
- device_remove_file(&hdev->dev, &dev_attr_led3);
- device_remove_file(&hdev->dev, &dev_attr_led4);
- wiimote_destroy(wdata);
+ kfree(wdata);
return ret;
}
@@ -437,16 +536,6 @@
struct wiimote_data *wdata = hid_get_drvdata(hdev);
hid_info(hdev, "Device removed\n");
-
- device_remove_file(&hdev->dev, &dev_attr_led1);
- device_remove_file(&hdev->dev, &dev_attr_led2);
- device_remove_file(&hdev->dev, &dev_attr_led3);
- device_remove_file(&hdev->dev, &dev_attr_led4);
-
- hid_hw_stop(hdev);
- input_unregister_device(wdata->input);
-
- cancel_work_sync(&wdata->worker);
wiimote_destroy(wdata);
}
diff --git a/drivers/hid/usbhid/hid-quirks.c b/drivers/hid/usbhid/hid-quirks.c
index 621959d..3146fdc 100644
--- a/drivers/hid/usbhid/hid-quirks.c
+++ b/drivers/hid/usbhid/hid-quirks.c
@@ -47,6 +47,7 @@
{ USB_VENDOR_ID_AFATECH, USB_DEVICE_ID_AFATECH_AF9016, HID_QUIRK_FULLSPEED_INTERVAL },
{ USB_VENDOR_ID_ETURBOTOUCH, USB_DEVICE_ID_ETURBOTOUCH, HID_QUIRK_MULTI_INPUT },
+ { USB_VENDOR_ID_GREENASIA, USB_DEVICE_ID_GREENASIA_DUAL_USB_JOYPAD, HID_QUIRK_MULTI_INPUT },
{ USB_VENDOR_ID_PANTHERLORD, USB_DEVICE_ID_PANTHERLORD_TWIN_USB_JOYSTICK, HID_QUIRK_MULTI_INPUT | HID_QUIRK_SKIP_OUTPUT_REPORTS },
{ USB_VENDOR_ID_PLAYDOTCOM, USB_DEVICE_ID_PLAYDOTCOM_EMS_USBII, HID_QUIRK_MULTI_INPUT },
{ USB_VENDOR_ID_TOUCHPACK, USB_DEVICE_ID_TOUCHPACK_RTS, HID_QUIRK_MULTI_INPUT },
@@ -89,6 +90,7 @@
{ USB_VENDOR_ID_CHICONY, USB_DEVICE_ID_CHICONY_MULTI_TOUCH, HID_QUIRK_MULTI_INPUT },
{ USB_VENDOR_ID_CHICONY, USB_DEVICE_ID_CHICONY_WIRELESS, HID_QUIRK_MULTI_INPUT },
+ { USB_VENDOR_ID_SIGMA_MICRO, USB_DEVICE_ID_SIGMA_MICRO_KEYBOARD, HID_QUIRK_NO_INIT_REPORTS },
{ 0, 0 }
};
diff --git a/drivers/hwmon/i5k_amb.c b/drivers/hwmon/i5k_amb.c
index c4c40be..d22f241 100644
--- a/drivers/hwmon/i5k_amb.c
+++ b/drivers/hwmon/i5k_amb.c
@@ -114,7 +114,6 @@
void __iomem *amb_mmio;
struct i5k_device_attribute *attrs;
unsigned int num_attrs;
- unsigned long chipset_id;
};
static ssize_t show_name(struct device *dev, struct device_attribute *devattr,
@@ -444,8 +443,6 @@
goto out;
}
- data->chipset_id = devid;
-
res = 0;
out:
pci_dev_put(pcidev);
@@ -478,23 +475,13 @@
return res;
}
-static unsigned long i5k_channel_pci_id(struct i5k_amb_data *data,
- unsigned long channel)
-{
- switch (data->chipset_id) {
- case PCI_DEVICE_ID_INTEL_5000_ERR:
- return PCI_DEVICE_ID_INTEL_5000_FBD0 + channel;
- case PCI_DEVICE_ID_INTEL_5400_ERR:
- return PCI_DEVICE_ID_INTEL_5400_FBD0 + channel;
- default:
- BUG();
- }
-}
-
-static unsigned long chipset_ids[] = {
- PCI_DEVICE_ID_INTEL_5000_ERR,
- PCI_DEVICE_ID_INTEL_5400_ERR,
- 0
+static struct {
+ unsigned long err;
+ unsigned long fbd0;
+} chipset_ids[] __devinitdata = {
+ { PCI_DEVICE_ID_INTEL_5000_ERR, PCI_DEVICE_ID_INTEL_5000_FBD0 },
+ { PCI_DEVICE_ID_INTEL_5400_ERR, PCI_DEVICE_ID_INTEL_5400_FBD0 },
+ { 0, 0 }
};
#ifdef MODULE
@@ -510,8 +497,7 @@
{
struct i5k_amb_data *data;
struct resource *reso;
- int i;
- int res = -ENODEV;
+ int i, res;
data = kzalloc(sizeof(*data), GFP_KERNEL);
if (!data)
@@ -520,22 +506,22 @@
/* Figure out where the AMB registers live */
i = 0;
do {
- res = i5k_find_amb_registers(data, chipset_ids[i]);
+ res = i5k_find_amb_registers(data, chipset_ids[i].err);
+ if (res == 0)
+ break;
i++;
- } while (res && chipset_ids[i]);
+ } while (chipset_ids[i].err);
if (res)
goto err;
/* Copy the DIMM presence map for the first two channels */
- res = i5k_channel_probe(&data->amb_present[0],
- i5k_channel_pci_id(data, 0));
+ res = i5k_channel_probe(&data->amb_present[0], chipset_ids[i].fbd0);
if (res)
goto err;
/* Copy the DIMM presence map for the optional second two channels */
- i5k_channel_probe(&data->amb_present[2],
- i5k_channel_pci_id(data, 1));
+ i5k_channel_probe(&data->amb_present[2], chipset_ids[i].fbd0 + 1);
/* Set up resource regions */
reso = request_mem_region(data->amb_base, data->amb_len, DRVNAME);
diff --git a/drivers/hwmon/max16065.c b/drivers/hwmon/max16065.c
index d94a24f..dd2d7b9 100644
--- a/drivers/hwmon/max16065.c
+++ b/drivers/hwmon/max16065.c
@@ -124,7 +124,7 @@
static inline int ADC_TO_CURR(int adc, int gain)
{
- return adc * 1400000 / gain * 255;
+ return adc * 1400000 / (gain * 255);
}
/*
diff --git a/drivers/hwmon/ntc_thermistor.c b/drivers/hwmon/ntc_thermistor.c
index d7926f4..eab1161 100644
--- a/drivers/hwmon/ntc_thermistor.c
+++ b/drivers/hwmon/ntc_thermistor.c
@@ -211,8 +211,7 @@
if (data->comp[mid].ohm <= ohm) {
*i_low = mid;
*i_high = mid - 1;
- }
- if (data->comp[mid].ohm > ohm) {
+ } else {
*i_low = mid + 1;
*i_high = mid;
}
diff --git a/drivers/hwmon/pmbus/ucd9000.c b/drivers/hwmon/pmbus/ucd9000.c
index ace1c73..d0ddb60 100644
--- a/drivers/hwmon/pmbus/ucd9000.c
+++ b/drivers/hwmon/pmbus/ucd9000.c
@@ -141,13 +141,11 @@
block_buffer[ret] = '\0';
dev_info(&client->dev, "Device ID %s\n", block_buffer);
- mid = NULL;
- for (i = 0; i < ARRAY_SIZE(ucd9000_id); i++) {
- mid = &ucd9000_id[i];
+ for (mid = ucd9000_id; mid->name[0]; mid++) {
if (!strncasecmp(mid->name, block_buffer, strlen(mid->name)))
break;
}
- if (!mid || !strlen(mid->name)) {
+ if (!mid->name[0]) {
dev_err(&client->dev, "Unsupported device\n");
return -ENODEV;
}
diff --git a/drivers/hwmon/pmbus/ucd9200.c b/drivers/hwmon/pmbus/ucd9200.c
index ffcc1cf..c65e9da 100644
--- a/drivers/hwmon/pmbus/ucd9200.c
+++ b/drivers/hwmon/pmbus/ucd9200.c
@@ -68,13 +68,11 @@
block_buffer[ret] = '\0';
dev_info(&client->dev, "Device ID %s\n", block_buffer);
- mid = NULL;
- for (i = 0; i < ARRAY_SIZE(ucd9200_id); i++) {
- mid = &ucd9200_id[i];
+ for (mid = ucd9200_id; mid->name[0]; mid++) {
if (!strncasecmp(mid->name, block_buffer, strlen(mid->name)))
break;
}
- if (!mid || !strlen(mid->name)) {
+ if (!mid->name[0]) {
dev_err(&client->dev, "Unsupported device\n");
return -ENODEV;
}
diff --git a/drivers/i2c/busses/i2c-nomadik.c b/drivers/i2c/busses/i2c-nomadik.c
index 0c731ca..b228e09 100644
--- a/drivers/i2c/busses/i2c-nomadik.c
+++ b/drivers/i2c/busses/i2c-nomadik.c
@@ -146,6 +146,7 @@
* @stop: stop condition
* @xfer_complete: acknowledge completion for a I2C message
* @result: controller propogated result
+ * @regulator: pointer to i2c regulator
* @busy: Busy doing transfer
*/
struct nmk_i2c_dev {
@@ -417,12 +418,12 @@
writel(readl(dev->virtbase + I2C_IMSCR) | irq_mask,
dev->virtbase + I2C_IMSCR);
- timeout = wait_for_completion_interruptible_timeout(
+ timeout = wait_for_completion_timeout(
&dev->xfer_complete, dev->adap.timeout);
if (timeout < 0) {
dev_err(&dev->pdev->dev,
- "wait_for_completion_interruptible_timeout"
+ "wait_for_completion_timeout"
"returned %d waiting for event\n", timeout);
status = timeout;
}
@@ -504,12 +505,12 @@
writel(readl(dev->virtbase + I2C_IMSCR) | irq_mask,
dev->virtbase + I2C_IMSCR);
- timeout = wait_for_completion_interruptible_timeout(
+ timeout = wait_for_completion_timeout(
&dev->xfer_complete, dev->adap.timeout);
if (timeout < 0) {
dev_err(&dev->pdev->dev,
- "wait_for_completion_interruptible_timeout"
+ "wait_for_completion_timeout "
"returned %d waiting for event\n", timeout);
status = timeout;
}
diff --git a/drivers/i2c/busses/i2c-omap.c b/drivers/i2c/busses/i2c-omap.c
index 1a766cf..2dfb631 100644
--- a/drivers/i2c/busses/i2c-omap.c
+++ b/drivers/i2c/busses/i2c-omap.c
@@ -1139,41 +1139,12 @@
return 0;
}
-#ifdef CONFIG_SUSPEND
-static int omap_i2c_suspend(struct device *dev)
-{
- if (!pm_runtime_suspended(dev))
- if (dev->bus && dev->bus->pm && dev->bus->pm->runtime_suspend)
- dev->bus->pm->runtime_suspend(dev);
-
- return 0;
-}
-
-static int omap_i2c_resume(struct device *dev)
-{
- if (!pm_runtime_suspended(dev))
- if (dev->bus && dev->bus->pm && dev->bus->pm->runtime_resume)
- dev->bus->pm->runtime_resume(dev);
-
- return 0;
-}
-
-static struct dev_pm_ops omap_i2c_pm_ops = {
- .suspend = omap_i2c_suspend,
- .resume = omap_i2c_resume,
-};
-#define OMAP_I2C_PM_OPS (&omap_i2c_pm_ops)
-#else
-#define OMAP_I2C_PM_OPS NULL
-#endif
-
static struct platform_driver omap_i2c_driver = {
.probe = omap_i2c_probe,
.remove = omap_i2c_remove,
.driver = {
.name = "omap_i2c",
.owner = THIS_MODULE,
- .pm = OMAP_I2C_PM_OPS,
},
};
diff --git a/drivers/i2c/busses/i2c-pxa-pci.c b/drivers/i2c/busses/i2c-pxa-pci.c
index 6659d26..b73da6c 100644
--- a/drivers/i2c/busses/i2c-pxa-pci.c
+++ b/drivers/i2c/busses/i2c-pxa-pci.c
@@ -109,12 +109,15 @@
return -EINVAL;
}
sds = kzalloc(sizeof(*sds), GFP_KERNEL);
- if (!sds)
+ if (!sds) {
+ ret = -ENOMEM;
goto err_mem;
+ }
for (i = 0; i < ARRAY_SIZE(sds->pdev); i++) {
sds->pdev[i] = add_i2c_device(dev, i);
if (IS_ERR(sds->pdev[i])) {
+ ret = PTR_ERR(sds->pdev[i]);
while (--i >= 0)
platform_device_unregister(sds->pdev[i]);
goto err_dev_add;
diff --git a/drivers/i2c/busses/i2c-tegra.c b/drivers/i2c/busses/i2c-tegra.c
index 2440b74..3c94c4a 100644
--- a/drivers/i2c/busses/i2c-tegra.c
+++ b/drivers/i2c/busses/i2c-tegra.c
@@ -270,14 +270,30 @@
/* Rounds down to not include partial word at the end of buf */
words_to_transfer = buf_remaining / BYTES_PER_FIFO_WORD;
- if (words_to_transfer > tx_fifo_avail)
- words_to_transfer = tx_fifo_avail;
- i2c_writesl(i2c_dev, buf, I2C_TX_FIFO, words_to_transfer);
+ /* It's very common to have < 4 bytes, so optimize that case. */
+ if (words_to_transfer) {
+ if (words_to_transfer > tx_fifo_avail)
+ words_to_transfer = tx_fifo_avail;
- buf += words_to_transfer * BYTES_PER_FIFO_WORD;
- buf_remaining -= words_to_transfer * BYTES_PER_FIFO_WORD;
- tx_fifo_avail -= words_to_transfer;
+ /*
+ * Update state before writing to FIFO. If this casues us
+ * to finish writing all bytes (AKA buf_remaining goes to 0) we
+ * have a potential for an interrupt (PACKET_XFER_COMPLETE is
+ * not maskable). We need to make sure that the isr sees
+ * buf_remaining as 0 and doesn't call us back re-entrantly.
+ */
+ buf_remaining -= words_to_transfer * BYTES_PER_FIFO_WORD;
+ tx_fifo_avail -= words_to_transfer;
+ i2c_dev->msg_buf_remaining = buf_remaining;
+ i2c_dev->msg_buf = buf +
+ words_to_transfer * BYTES_PER_FIFO_WORD;
+ barrier();
+
+ i2c_writesl(i2c_dev, buf, I2C_TX_FIFO, words_to_transfer);
+
+ buf += words_to_transfer * BYTES_PER_FIFO_WORD;
+ }
/*
* If there is a partial word at the end of buf, handle it manually to
@@ -287,14 +303,15 @@
if (tx_fifo_avail > 0 && buf_remaining > 0) {
BUG_ON(buf_remaining > 3);
memcpy(&val, buf, buf_remaining);
+
+ /* Again update before writing to FIFO to make sure isr sees. */
+ i2c_dev->msg_buf_remaining = 0;
+ i2c_dev->msg_buf = NULL;
+ barrier();
+
i2c_writel(i2c_dev, val, I2C_TX_FIFO);
- buf_remaining = 0;
- tx_fifo_avail--;
}
- BUG_ON(tx_fifo_avail > 0 && buf_remaining > 0);
- i2c_dev->msg_buf_remaining = buf_remaining;
- i2c_dev->msg_buf = buf;
return 0;
}
@@ -411,9 +428,10 @@
tegra_i2c_mask_irq(i2c_dev, I2C_INT_TX_FIFO_DATA_REQ);
}
- if ((status & I2C_INT_PACKET_XFER_COMPLETE) &&
- !i2c_dev->msg_buf_remaining)
+ if (status & I2C_INT_PACKET_XFER_COMPLETE) {
+ BUG_ON(i2c_dev->msg_buf_remaining);
complete(&i2c_dev->msg_complete);
+ }
i2c_writel(i2c_dev, status, I2C_INT_STATUS);
if (i2c_dev->is_dvc)
@@ -531,7 +549,7 @@
static u32 tegra_i2c_func(struct i2c_adapter *adap)
{
- return I2C_FUNC_I2C;
+ return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
}
static const struct i2c_algorithm tegra_i2c_algo = {
@@ -719,6 +737,17 @@
}
#endif
+#if defined(CONFIG_OF)
+/* Match table for of_platform binding */
+static const struct of_device_id tegra_i2c_of_match[] __devinitconst = {
+ { .compatible = "nvidia,tegra20-i2c", },
+ {},
+};
+MODULE_DEVICE_TABLE(of, tegra_i2c_of_match);
+#else
+#define tegra_i2c_of_match NULL
+#endif
+
static struct platform_driver tegra_i2c_driver = {
.probe = tegra_i2c_probe,
.remove = tegra_i2c_remove,
@@ -729,6 +758,7 @@
.driver = {
.name = "tegra-i2c",
.owner = THIS_MODULE,
+ .of_match_table = tegra_i2c_of_match,
},
};
diff --git a/drivers/input/joystick/analog.c b/drivers/input/joystick/analog.c
index 9882971..358cd7e 100644
--- a/drivers/input/joystick/analog.c
+++ b/drivers/input/joystick/analog.c
@@ -139,7 +139,7 @@
#include <linux/i8253.h>
#define GET_TIME(x) do { if (cpu_has_tsc) rdtscl(x); else x = get_time_pit(); } while (0)
-#define DELTA(x,y) (cpu_has_tsc ? ((y) - (x)) : ((x) - (y) + ((x) < (y) ? CLOCK_TICK_RATE / HZ : 0)))
+#define DELTA(x,y) (cpu_has_tsc ? ((y) - (x)) : ((x) - (y) + ((x) < (y) ? PIT_TICK_RATE / HZ : 0)))
#define TIME_NAME (cpu_has_tsc?"TSC":"PIT")
static unsigned int get_time_pit(void)
{
diff --git a/drivers/input/keyboard/ep93xx_keypad.c b/drivers/input/keyboard/ep93xx_keypad.c
index c8242dd..aa17e02 100644
--- a/drivers/input/keyboard/ep93xx_keypad.c
+++ b/drivers/input/keyboard/ep93xx_keypad.c
@@ -20,6 +20,7 @@
* flag.
*/
+#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/interrupt.h>
#include <linux/clk.h>
diff --git a/drivers/input/keyboard/tegra-kbc.c b/drivers/input/keyboard/tegra-kbc.c
index f270447..a5a7791 100644
--- a/drivers/input/keyboard/tegra-kbc.c
+++ b/drivers/input/keyboard/tegra-kbc.c
@@ -702,7 +702,7 @@
err_free_mem_region:
release_mem_region(res->start, resource_size(res));
err_free_mem:
- input_free_device(kbc->idev);
+ input_free_device(input_dev);
kfree(kbc);
return err;
diff --git a/drivers/input/misc/ad714x-i2c.c b/drivers/input/misc/ad714x-i2c.c
index e21deb1..025417d 100644
--- a/drivers/input/misc/ad714x-i2c.c
+++ b/drivers/input/misc/ad714x-i2c.c
@@ -1,7 +1,7 @@
/*
* AD714X CapTouch Programmable Controller driver (I2C bus)
*
- * Copyright 2009 Analog Devices Inc.
+ * Copyright 2009-2011 Analog Devices Inc.
*
* Licensed under the GPL-2 or later.
*/
@@ -27,54 +27,49 @@
static SIMPLE_DEV_PM_OPS(ad714x_i2c_pm, ad714x_i2c_suspend, ad714x_i2c_resume);
-static int ad714x_i2c_write(struct device *dev, unsigned short reg,
- unsigned short data)
+static int ad714x_i2c_write(struct ad714x_chip *chip,
+ unsigned short reg, unsigned short data)
{
- struct i2c_client *client = to_i2c_client(dev);
- int ret = 0;
- u8 *_reg = (u8 *)®
- u8 *_data = (u8 *)&data;
+ struct i2c_client *client = to_i2c_client(chip->dev);
+ int error;
- u8 tx[4] = {
- _reg[1],
- _reg[0],
- _data[1],
- _data[0]
- };
+ chip->xfer_buf[0] = cpu_to_be16(reg);
+ chip->xfer_buf[1] = cpu_to_be16(data);
- ret = i2c_master_send(client, tx, 4);
- if (ret < 0)
- dev_err(&client->dev, "I2C write error\n");
-
- return ret;
-}
-
-static int ad714x_i2c_read(struct device *dev, unsigned short reg,
- unsigned short *data)
-{
- struct i2c_client *client = to_i2c_client(dev);
- int ret = 0;
- u8 *_reg = (u8 *)®
- u8 *_data = (u8 *)data;
-
- u8 tx[2] = {
- _reg[1],
- _reg[0]
- };
- u8 rx[2];
-
- ret = i2c_master_send(client, tx, 2);
- if (ret >= 0)
- ret = i2c_master_recv(client, rx, 2);
-
- if (unlikely(ret < 0)) {
- dev_err(&client->dev, "I2C read error\n");
- } else {
- _data[0] = rx[1];
- _data[1] = rx[0];
+ error = i2c_master_send(client, (u8 *)chip->xfer_buf,
+ 2 * sizeof(*chip->xfer_buf));
+ if (unlikely(error < 0)) {
+ dev_err(&client->dev, "I2C write error: %d\n", error);
+ return error;
}
- return ret;
+ return 0;
+}
+
+static int ad714x_i2c_read(struct ad714x_chip *chip,
+ unsigned short reg, unsigned short *data, size_t len)
+{
+ struct i2c_client *client = to_i2c_client(chip->dev);
+ int i;
+ int error;
+
+ chip->xfer_buf[0] = cpu_to_be16(reg);
+
+ error = i2c_master_send(client, (u8 *)chip->xfer_buf,
+ sizeof(*chip->xfer_buf));
+ if (error >= 0)
+ error = i2c_master_recv(client, (u8 *)chip->xfer_buf,
+ len * sizeof(*chip->xfer_buf));
+
+ if (unlikely(error < 0)) {
+ dev_err(&client->dev, "I2C read error: %d\n", error);
+ return error;
+ }
+
+ for (i = 0; i < len; i++)
+ data[i] = be16_to_cpu(chip->xfer_buf[i]);
+
+ return 0;
}
static int __devinit ad714x_i2c_probe(struct i2c_client *client,
diff --git a/drivers/input/misc/ad714x-spi.c b/drivers/input/misc/ad714x-spi.c
index 4120dd5..875b508 100644
--- a/drivers/input/misc/ad714x-spi.c
+++ b/drivers/input/misc/ad714x-spi.c
@@ -1,12 +1,12 @@
/*
* AD714X CapTouch Programmable Controller driver (SPI bus)
*
- * Copyright 2009 Analog Devices Inc.
+ * Copyright 2009-2011 Analog Devices Inc.
*
* Licensed under the GPL-2 or later.
*/
-#include <linux/input.h> /* BUS_I2C */
+#include <linux/input.h> /* BUS_SPI */
#include <linux/module.h>
#include <linux/spi/spi.h>
#include <linux/pm.h>
@@ -30,30 +30,68 @@
static SIMPLE_DEV_PM_OPS(ad714x_spi_pm, ad714x_spi_suspend, ad714x_spi_resume);
-static int ad714x_spi_read(struct device *dev, unsigned short reg,
- unsigned short *data)
+static int ad714x_spi_read(struct ad714x_chip *chip,
+ unsigned short reg, unsigned short *data, size_t len)
{
- struct spi_device *spi = to_spi_device(dev);
- unsigned short tx = AD714x_SPI_CMD_PREFIX | AD714x_SPI_READ | reg;
+ struct spi_device *spi = to_spi_device(chip->dev);
+ struct spi_message message;
+ struct spi_transfer xfer[2];
+ int i;
+ int error;
- return spi_write_then_read(spi, (u8 *)&tx, 2, (u8 *)data, 2);
+ spi_message_init(&message);
+ memset(xfer, 0, sizeof(xfer));
+
+ chip->xfer_buf[0] = cpu_to_be16(AD714x_SPI_CMD_PREFIX |
+ AD714x_SPI_READ | reg);
+ xfer[0].tx_buf = &chip->xfer_buf[0];
+ xfer[0].len = sizeof(chip->xfer_buf[0]);
+ spi_message_add_tail(&xfer[0], &message);
+
+ xfer[1].rx_buf = &chip->xfer_buf[1];
+ xfer[1].len = sizeof(chip->xfer_buf[1]) * len;
+ spi_message_add_tail(&xfer[1], &message);
+
+ error = spi_sync(spi, &message);
+ if (unlikely(error)) {
+ dev_err(chip->dev, "SPI read error: %d\n", error);
+ return error;
+ }
+
+ for (i = 0; i < len; i++)
+ data[i] = be16_to_cpu(chip->xfer_buf[i + 1]);
+
+ return 0;
}
-static int ad714x_spi_write(struct device *dev, unsigned short reg,
- unsigned short data)
+static int ad714x_spi_write(struct ad714x_chip *chip,
+ unsigned short reg, unsigned short data)
{
- struct spi_device *spi = to_spi_device(dev);
- unsigned short tx[2] = {
- AD714x_SPI_CMD_PREFIX | reg,
- data
- };
+ struct spi_device *spi = to_spi_device(chip->dev);
+ int error;
- return spi_write(spi, (u8 *)tx, 4);
+ chip->xfer_buf[0] = cpu_to_be16(AD714x_SPI_CMD_PREFIX | reg);
+ chip->xfer_buf[1] = cpu_to_be16(data);
+
+ error = spi_write(spi, (u8 *)chip->xfer_buf,
+ 2 * sizeof(*chip->xfer_buf));
+ if (unlikely(error)) {
+ dev_err(chip->dev, "SPI write error: %d\n", error);
+ return error;
+ }
+
+ return 0;
}
static int __devinit ad714x_spi_probe(struct spi_device *spi)
{
struct ad714x_chip *chip;
+ int err;
+
+ spi->bits_per_word = 8;
+ err = spi_setup(spi);
+ if (err < 0)
+ return err;
chip = ad714x_probe(&spi->dev, BUS_SPI, spi->irq,
ad714x_spi_read, ad714x_spi_write);
diff --git a/drivers/input/misc/ad714x.c b/drivers/input/misc/ad714x.c
index c3a62c4..ca42c7d 100644
--- a/drivers/input/misc/ad714x.c
+++ b/drivers/input/misc/ad714x.c
@@ -1,7 +1,7 @@
/*
* AD714X CapTouch Programmable Controller driver supporting AD7142/3/7/8/7A
*
- * Copyright 2009 Analog Devices Inc.
+ * Copyright 2009-2011 Analog Devices Inc.
*
* Licensed under the GPL-2 or later.
*/
@@ -59,7 +59,6 @@
#define STAGE11_AMBIENT 0x27D
#define PER_STAGE_REG_NUM 36
-#define STAGE_NUM 12
#define STAGE_CFGREG_NUM 8
#define SYS_CFGREG_NUM 8
@@ -124,27 +123,6 @@
* information to integrate all things which will be private data
* of spi/i2c device
*/
-struct ad714x_chip {
- unsigned short h_state;
- unsigned short l_state;
- unsigned short c_state;
- unsigned short adc_reg[STAGE_NUM];
- unsigned short amb_reg[STAGE_NUM];
- unsigned short sensor_val[STAGE_NUM];
-
- struct ad714x_platform_data *hw;
- struct ad714x_driver_data *sw;
-
- int irq;
- struct device *dev;
- ad714x_read_t read;
- ad714x_write_t write;
-
- struct mutex mutex;
-
- unsigned product;
- unsigned version;
-};
static void ad714x_use_com_int(struct ad714x_chip *ad714x,
int start_stage, int end_stage)
@@ -154,13 +132,13 @@
mask = ((1 << (end_stage + 1)) - 1) - ((1 << start_stage) - 1);
- ad714x->read(ad714x->dev, STG_COM_INT_EN_REG, &data);
+ ad714x->read(ad714x, STG_COM_INT_EN_REG, &data, 1);
data |= 1 << end_stage;
- ad714x->write(ad714x->dev, STG_COM_INT_EN_REG, data);
+ ad714x->write(ad714x, STG_COM_INT_EN_REG, data);
- ad714x->read(ad714x->dev, STG_HIGH_INT_EN_REG, &data);
+ ad714x->read(ad714x, STG_HIGH_INT_EN_REG, &data, 1);
data &= ~mask;
- ad714x->write(ad714x->dev, STG_HIGH_INT_EN_REG, data);
+ ad714x->write(ad714x, STG_HIGH_INT_EN_REG, data);
}
static void ad714x_use_thr_int(struct ad714x_chip *ad714x,
@@ -171,13 +149,13 @@
mask = ((1 << (end_stage + 1)) - 1) - ((1 << start_stage) - 1);
- ad714x->read(ad714x->dev, STG_COM_INT_EN_REG, &data);
+ ad714x->read(ad714x, STG_COM_INT_EN_REG, &data, 1);
data &= ~(1 << end_stage);
- ad714x->write(ad714x->dev, STG_COM_INT_EN_REG, data);
+ ad714x->write(ad714x, STG_COM_INT_EN_REG, data);
- ad714x->read(ad714x->dev, STG_HIGH_INT_EN_REG, &data);
+ ad714x->read(ad714x, STG_HIGH_INT_EN_REG, &data, 1);
data |= mask;
- ad714x->write(ad714x->dev, STG_HIGH_INT_EN_REG, data);
+ ad714x->write(ad714x, STG_HIGH_INT_EN_REG, data);
}
static int ad714x_cal_highest_stage(struct ad714x_chip *ad714x,
@@ -273,15 +251,16 @@
struct ad714x_slider_plat *hw = &ad714x->hw->slider[idx];
int i;
- for (i = hw->start_stage; i <= hw->end_stage; i++) {
- ad714x->read(ad714x->dev, CDC_RESULT_S0 + i,
- &ad714x->adc_reg[i]);
- ad714x->read(ad714x->dev,
- STAGE0_AMBIENT + i * PER_STAGE_REG_NUM,
- &ad714x->amb_reg[i]);
+ ad714x->read(ad714x, CDC_RESULT_S0 + hw->start_stage,
+ &ad714x->adc_reg[hw->start_stage],
+ hw->end_stage - hw->start_stage + 1);
- ad714x->sensor_val[i] = abs(ad714x->adc_reg[i] -
- ad714x->amb_reg[i]);
+ for (i = hw->start_stage; i <= hw->end_stage; i++) {
+ ad714x->read(ad714x, STAGE0_AMBIENT + i * PER_STAGE_REG_NUM,
+ &ad714x->amb_reg[i], 1);
+
+ ad714x->sensor_val[i] =
+ abs(ad714x->adc_reg[i] - ad714x->amb_reg[i]);
}
}
@@ -444,15 +423,16 @@
struct ad714x_wheel_plat *hw = &ad714x->hw->wheel[idx];
int i;
+ ad714x->read(ad714x, CDC_RESULT_S0 + hw->start_stage,
+ &ad714x->adc_reg[hw->start_stage],
+ hw->end_stage - hw->start_stage + 1);
+
for (i = hw->start_stage; i <= hw->end_stage; i++) {
- ad714x->read(ad714x->dev, CDC_RESULT_S0 + i,
- &ad714x->adc_reg[i]);
- ad714x->read(ad714x->dev,
- STAGE0_AMBIENT + i * PER_STAGE_REG_NUM,
- &ad714x->amb_reg[i]);
+ ad714x->read(ad714x, STAGE0_AMBIENT + i * PER_STAGE_REG_NUM,
+ &ad714x->amb_reg[i], 1);
if (ad714x->adc_reg[i] > ad714x->amb_reg[i])
- ad714x->sensor_val[i] = ad714x->adc_reg[i] -
- ad714x->amb_reg[i];
+ ad714x->sensor_val[i] =
+ ad714x->adc_reg[i] - ad714x->amb_reg[i];
else
ad714x->sensor_val[i] = 0;
}
@@ -597,15 +577,16 @@
struct ad714x_touchpad_plat *hw = &ad714x->hw->touchpad[idx];
int i;
+ ad714x->read(ad714x, CDC_RESULT_S0 + hw->x_start_stage,
+ &ad714x->adc_reg[hw->x_start_stage],
+ hw->x_end_stage - hw->x_start_stage + 1);
+
for (i = hw->x_start_stage; i <= hw->x_end_stage; i++) {
- ad714x->read(ad714x->dev, CDC_RESULT_S0 + i,
- &ad714x->adc_reg[i]);
- ad714x->read(ad714x->dev,
- STAGE0_AMBIENT + i * PER_STAGE_REG_NUM,
- &ad714x->amb_reg[i]);
+ ad714x->read(ad714x, STAGE0_AMBIENT + i * PER_STAGE_REG_NUM,
+ &ad714x->amb_reg[i], 1);
if (ad714x->adc_reg[i] > ad714x->amb_reg[i])
- ad714x->sensor_val[i] = ad714x->adc_reg[i] -
- ad714x->amb_reg[i];
+ ad714x->sensor_val[i] =
+ ad714x->adc_reg[i] - ad714x->amb_reg[i];
else
ad714x->sensor_val[i] = 0;
}
@@ -891,7 +872,7 @@
{
unsigned short data;
- ad714x->read(ad714x->dev, AD714X_PARTID_REG, &data);
+ ad714x->read(ad714x, AD714X_PARTID_REG, &data, 1);
switch (data & 0xFFF0) {
case AD7142_PARTID:
ad714x->product = 0x7142;
@@ -940,23 +921,20 @@
for (i = 0; i < STAGE_NUM; i++) {
reg_base = AD714X_STAGECFG_REG + i * STAGE_CFGREG_NUM;
for (j = 0; j < STAGE_CFGREG_NUM; j++)
- ad714x->write(ad714x->dev, reg_base + j,
+ ad714x->write(ad714x, reg_base + j,
ad714x->hw->stage_cfg_reg[i][j]);
}
for (i = 0; i < SYS_CFGREG_NUM; i++)
- ad714x->write(ad714x->dev, AD714X_SYSCFG_REG + i,
+ ad714x->write(ad714x, AD714X_SYSCFG_REG + i,
ad714x->hw->sys_cfg_reg[i]);
for (i = 0; i < SYS_CFGREG_NUM; i++)
- ad714x->read(ad714x->dev, AD714X_SYSCFG_REG + i,
- &data);
+ ad714x->read(ad714x, AD714X_SYSCFG_REG + i, &data, 1);
- ad714x->write(ad714x->dev, AD714X_STG_CAL_EN_REG, 0xFFF);
+ ad714x->write(ad714x, AD714X_STG_CAL_EN_REG, 0xFFF);
/* clear all interrupts */
- ad714x->read(ad714x->dev, STG_LOW_INT_STA_REG, &data);
- ad714x->read(ad714x->dev, STG_HIGH_INT_STA_REG, &data);
- ad714x->read(ad714x->dev, STG_COM_INT_STA_REG, &data);
+ ad714x->read(ad714x, STG_LOW_INT_STA_REG, &ad714x->l_state, 3);
}
static irqreturn_t ad714x_interrupt_thread(int irq, void *data)
@@ -966,9 +944,7 @@
mutex_lock(&ad714x->mutex);
- ad714x->read(ad714x->dev, STG_LOW_INT_STA_REG, &ad714x->l_state);
- ad714x->read(ad714x->dev, STG_HIGH_INT_STA_REG, &ad714x->h_state);
- ad714x->read(ad714x->dev, STG_COM_INT_STA_REG, &ad714x->c_state);
+ ad714x->read(ad714x, STG_LOW_INT_STA_REG, &ad714x->l_state, 3);
for (i = 0; i < ad714x->hw->button_num; i++)
ad714x_button_state_machine(ad714x, i);
@@ -1245,7 +1221,7 @@
mutex_lock(&ad714x->mutex);
data = ad714x->hw->sys_cfg_reg[AD714X_PWR_CTRL] | 0x3;
- ad714x->write(ad714x->dev, AD714X_PWR_CTRL, data);
+ ad714x->write(ad714x, AD714X_PWR_CTRL, data);
mutex_unlock(&ad714x->mutex);
@@ -1255,24 +1231,20 @@
int ad714x_enable(struct ad714x_chip *ad714x)
{
- unsigned short data;
-
dev_dbg(ad714x->dev, "%s enter\n", __func__);
mutex_lock(&ad714x->mutex);
/* resume to non-shutdown mode */
- ad714x->write(ad714x->dev, AD714X_PWR_CTRL,
+ ad714x->write(ad714x, AD714X_PWR_CTRL,
ad714x->hw->sys_cfg_reg[AD714X_PWR_CTRL]);
/* make sure the interrupt output line is not low level after resume,
* otherwise we will get no chance to enter falling-edge irq again
*/
- ad714x->read(ad714x->dev, STG_LOW_INT_STA_REG, &data);
- ad714x->read(ad714x->dev, STG_HIGH_INT_STA_REG, &data);
- ad714x->read(ad714x->dev, STG_COM_INT_STA_REG, &data);
+ ad714x->read(ad714x, STG_LOW_INT_STA_REG, &ad714x->l_state, 3);
mutex_unlock(&ad714x->mutex);
diff --git a/drivers/input/misc/ad714x.h b/drivers/input/misc/ad714x.h
index 45c54fb..3c85455 100644
--- a/drivers/input/misc/ad714x.h
+++ b/drivers/input/misc/ad714x.h
@@ -1,7 +1,7 @@
/*
* AD714X CapTouch Programmable Controller driver (bus interfaces)
*
- * Copyright 2009 Analog Devices Inc.
+ * Copyright 2009-2011 Analog Devices Inc.
*
* Licensed under the GPL-2 or later.
*/
@@ -11,11 +11,40 @@
#include <linux/types.h>
+#define STAGE_NUM 12
+
struct device;
+struct ad714x_platform_data;
+struct ad714x_driver_data;
struct ad714x_chip;
-typedef int (*ad714x_read_t)(struct device *, unsigned short, unsigned short *);
-typedef int (*ad714x_write_t)(struct device *, unsigned short, unsigned short);
+typedef int (*ad714x_read_t)(struct ad714x_chip *, unsigned short, unsigned short *, size_t);
+typedef int (*ad714x_write_t)(struct ad714x_chip *, unsigned short, unsigned short);
+
+struct ad714x_chip {
+ unsigned short l_state;
+ unsigned short h_state;
+ unsigned short c_state;
+ unsigned short adc_reg[STAGE_NUM];
+ unsigned short amb_reg[STAGE_NUM];
+ unsigned short sensor_val[STAGE_NUM];
+
+ struct ad714x_platform_data *hw;
+ struct ad714x_driver_data *sw;
+
+ int irq;
+ struct device *dev;
+ ad714x_read_t read;
+ ad714x_write_t write;
+
+ struct mutex mutex;
+
+ unsigned product;
+ unsigned version;
+
+ __be16 xfer_buf[16] ____cacheline_aligned;
+
+};
int ad714x_disable(struct ad714x_chip *ad714x);
int ad714x_enable(struct ad714x_chip *ad714x);
diff --git a/drivers/input/misc/mma8450.c b/drivers/input/misc/mma8450.c
index 6c76cf7..0794778 100644
--- a/drivers/input/misc/mma8450.c
+++ b/drivers/input/misc/mma8450.c
@@ -234,7 +234,7 @@
{ .compatible = "fsl,mma8450", },
{ /* sentinel */ }
};
-MODULE_DEVICE_TABLE(i2c, mma8450_dt_ids);
+MODULE_DEVICE_TABLE(of, mma8450_dt_ids);
static struct i2c_driver mma8450_driver = {
.driver = {
diff --git a/drivers/input/misc/mpu3050.c b/drivers/input/misc/mpu3050.c
index b95fac1..f71dc72 100644
--- a/drivers/input/misc/mpu3050.c
+++ b/drivers/input/misc/mpu3050.c
@@ -282,7 +282,7 @@
err_pm_set_suspended:
pm_runtime_set_suspended(&client->dev);
err_free_mem:
- input_unregister_device(idev);
+ input_free_device(idev);
kfree(sensor);
return error;
}
diff --git a/drivers/input/mouse/bcm5974.c b/drivers/input/mouse/bcm5974.c
index 3126983..da28018 100644
--- a/drivers/input/mouse/bcm5974.c
+++ b/drivers/input/mouse/bcm5974.c
@@ -67,6 +67,14 @@
#define USB_DEVICE_ID_APPLE_WELLSPRING5_ANSI 0x0245
#define USB_DEVICE_ID_APPLE_WELLSPRING5_ISO 0x0246
#define USB_DEVICE_ID_APPLE_WELLSPRING5_JIS 0x0247
+/* MacbookAir4,2 (unibody, July 2011) */
+#define USB_DEVICE_ID_APPLE_WELLSPRING6_ANSI 0x024c
+#define USB_DEVICE_ID_APPLE_WELLSPRING6_ISO 0x024d
+#define USB_DEVICE_ID_APPLE_WELLSPRING6_JIS 0x024e
+/* Macbook8,2 (unibody) */
+#define USB_DEVICE_ID_APPLE_WELLSPRING5A_ANSI 0x0252
+#define USB_DEVICE_ID_APPLE_WELLSPRING5A_ISO 0x0253
+#define USB_DEVICE_ID_APPLE_WELLSPRING5A_JIS 0x0254
#define BCM5974_DEVICE(prod) { \
.match_flags = (USB_DEVICE_ID_MATCH_DEVICE | \
@@ -104,6 +112,14 @@
BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRING5_ANSI),
BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRING5_ISO),
BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRING5_JIS),
+ /* MacbookAir4,2 */
+ BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRING6_ANSI),
+ BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRING6_ISO),
+ BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRING6_JIS),
+ /* MacbookPro8,2 */
+ BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRING5A_ANSI),
+ BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRING5A_ISO),
+ BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRING5A_JIS),
/* Terminating entry */
{}
};
@@ -294,6 +310,30 @@
{ DIM_X, DIM_X / SN_COORD, -4415, 5050 },
{ DIM_Y, DIM_Y / SN_COORD, -55, 6680 }
},
+ {
+ USB_DEVICE_ID_APPLE_WELLSPRING6_ANSI,
+ USB_DEVICE_ID_APPLE_WELLSPRING6_ISO,
+ USB_DEVICE_ID_APPLE_WELLSPRING6_JIS,
+ HAS_INTEGRATED_BUTTON,
+ 0x84, sizeof(struct bt_data),
+ 0x81, TYPE2, FINGER_TYPE2, FINGER_TYPE2 + SIZEOF_ALL_FINGERS,
+ { DIM_PRESSURE, DIM_PRESSURE / SN_PRESSURE, 0, 300 },
+ { DIM_WIDTH, DIM_WIDTH / SN_WIDTH, 0, 2048 },
+ { DIM_X, DIM_X / SN_COORD, -4620, 5140 },
+ { DIM_Y, DIM_Y / SN_COORD, -150, 6600 }
+ },
+ {
+ USB_DEVICE_ID_APPLE_WELLSPRING5A_ANSI,
+ USB_DEVICE_ID_APPLE_WELLSPRING5A_ISO,
+ USB_DEVICE_ID_APPLE_WELLSPRING5A_JIS,
+ HAS_INTEGRATED_BUTTON,
+ 0x84, sizeof(struct bt_data),
+ 0x81, TYPE2, FINGER_TYPE2, FINGER_TYPE2 + SIZEOF_ALL_FINGERS,
+ { DIM_PRESSURE, DIM_PRESSURE / SN_PRESSURE, 0, 300 },
+ { DIM_WIDTH, DIM_WIDTH / SN_WIDTH, 0, 2048 },
+ { DIM_X, DIM_X / SN_COORD, -4750, 5280 },
+ { DIM_Y, DIM_Y / SN_COORD, -150, 6730 }
+ },
{}
};
diff --git a/drivers/input/tablet/wacom_sys.c b/drivers/input/tablet/wacom_sys.c
index 449c0a4..d27c9d9 100644
--- a/drivers/input/tablet/wacom_sys.c
+++ b/drivers/input/tablet/wacom_sys.c
@@ -49,6 +49,7 @@
#define USB_REQ_GET_REPORT 0x01
#define USB_REQ_SET_REPORT 0x09
#define WAC_HID_FEATURE_REPORT 0x03
+#define WAC_MSG_RETRIES 5
static int usb_get_report(struct usb_interface *intf, unsigned char type,
unsigned char id, void *buf, int size)
@@ -165,7 +166,7 @@
report,
hid_desc->wDescriptorLength,
5000); /* 5 secs */
- } while (result < 0 && limit++ < 5);
+ } while (result < 0 && limit++ < WAC_MSG_RETRIES);
/* No need to parse the Descriptor. It isn't an error though */
if (result < 0)
@@ -319,24 +320,26 @@
int limit = 0, report_id = 2;
int error = -ENOMEM;
- rep_data = kmalloc(2, GFP_KERNEL);
+ rep_data = kmalloc(4, GFP_KERNEL);
if (!rep_data)
return error;
- /* ask to report tablet data if it is 2FGT Tablet PC or
+ /* ask to report tablet data if it is MT Tablet PC or
* not a Tablet PC */
if (features->type == TABLETPC2FG) {
do {
rep_data[0] = 3;
rep_data[1] = 4;
+ rep_data[2] = 0;
+ rep_data[3] = 0;
report_id = 3;
error = usb_set_report(intf, WAC_HID_FEATURE_REPORT,
- report_id, rep_data, 2);
+ report_id, rep_data, 4);
if (error >= 0)
error = usb_get_report(intf,
WAC_HID_FEATURE_REPORT, report_id,
- rep_data, 3);
- } while ((error < 0 || rep_data[1] != 4) && limit++ < 5);
+ rep_data, 4);
+ } while ((error < 0 || rep_data[1] != 4) && limit++ < WAC_MSG_RETRIES);
} else if (features->type != TABLETPC) {
do {
rep_data[0] = 2;
@@ -347,7 +350,7 @@
error = usb_get_report(intf,
WAC_HID_FEATURE_REPORT, report_id,
rep_data, 2);
- } while ((error < 0 || rep_data[1] != 2) && limit++ < 5);
+ } while ((error < 0 || rep_data[1] != 2) && limit++ < WAC_MSG_RETRIES);
}
kfree(rep_data);
diff --git a/drivers/input/tablet/wacom_wac.c b/drivers/input/tablet/wacom_wac.c
index 03ebcc8..c1c2f7b 100644
--- a/drivers/input/tablet/wacom_wac.c
+++ b/drivers/input/tablet/wacom_wac.c
@@ -1460,6 +1460,9 @@
static const struct wacom_features wacom_features_0xD4 =
{ "Wacom Bamboo Pen", WACOM_PKGLEN_BBFUN, 14720, 9200, 1023,
63, BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
+static const struct wacom_features wacom_features_0xD5 =
+ { "Wacom Bamboo Pen 6x8", WACOM_PKGLEN_BBFUN, 21648, 13530, 1023,
+ 63, BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
static const struct wacom_features wacom_features_0xD6 =
{ "Wacom BambooPT 2FG 4x5", WACOM_PKGLEN_BBFUN, 14720, 9200, 1023,
63, BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
@@ -1564,6 +1567,7 @@
{ USB_DEVICE_WACOM(0xD2) },
{ USB_DEVICE_WACOM(0xD3) },
{ USB_DEVICE_WACOM(0xD4) },
+ { USB_DEVICE_WACOM(0xD5) },
{ USB_DEVICE_WACOM(0xD6) },
{ USB_DEVICE_WACOM(0xD7) },
{ USB_DEVICE_WACOM(0xD8) },
diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c
index ae00604..f5d6685 100644
--- a/drivers/input/touchscreen/atmel_mxt_ts.c
+++ b/drivers/input/touchscreen/atmel_mxt_ts.c
@@ -244,6 +244,7 @@
int x;
int y;
int area;
+ int pressure;
};
/* Each client has this additional data */
@@ -536,6 +537,8 @@
finger[id].x);
input_report_abs(input_dev, ABS_MT_POSITION_Y,
finger[id].y);
+ input_report_abs(input_dev, ABS_MT_PRESSURE,
+ finger[id].pressure);
} else {
finger[id].status = 0;
}
@@ -546,6 +549,8 @@
if (status != MXT_RELEASE) {
input_report_abs(input_dev, ABS_X, finger[single_id].x);
input_report_abs(input_dev, ABS_Y, finger[single_id].y);
+ input_report_abs(input_dev,
+ ABS_PRESSURE, finger[single_id].pressure);
}
input_sync(input_dev);
@@ -560,6 +565,7 @@
int x;
int y;
int area;
+ int pressure;
/* Check the touch is present on the screen */
if (!(status & MXT_DETECT)) {
@@ -584,6 +590,7 @@
y = y >> 2;
area = message->message[4];
+ pressure = message->message[5];
dev_dbg(dev, "[%d] %s x: %d, y: %d, area: %d\n", id,
status & MXT_MOVE ? "moved" : "pressed",
@@ -594,6 +601,7 @@
finger[id].x = x;
finger[id].y = y;
finger[id].area = area;
+ finger[id].pressure = pressure;
mxt_input_report(data, id);
}
@@ -1116,6 +1124,8 @@
0, data->max_x, 0, 0);
input_set_abs_params(input_dev, ABS_Y,
0, data->max_y, 0, 0);
+ input_set_abs_params(input_dev, ABS_PRESSURE,
+ 0, 255, 0, 0);
/* For multi touch */
input_mt_init_slots(input_dev, MXT_MAX_FINGER);
@@ -1125,6 +1135,8 @@
0, data->max_x, 0, 0);
input_set_abs_params(input_dev, ABS_MT_POSITION_Y,
0, data->max_y, 0, 0);
+ input_set_abs_params(input_dev, ABS_MT_PRESSURE,
+ 0, 255, 0, 0);
input_set_drvdata(input_dev, data);
i2c_set_clientdata(client, data);
diff --git a/drivers/input/touchscreen/max11801_ts.c b/drivers/input/touchscreen/max11801_ts.c
index 4f2713d..4627fe5 100644
--- a/drivers/input/touchscreen/max11801_ts.c
+++ b/drivers/input/touchscreen/max11801_ts.c
@@ -9,7 +9,8 @@
*
* 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.
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
*/
/*
diff --git a/drivers/input/touchscreen/tnetv107x-ts.c b/drivers/input/touchscreen/tnetv107x-ts.c
index 089b0a0..0e8f63e 100644
--- a/drivers/input/touchscreen/tnetv107x-ts.c
+++ b/drivers/input/touchscreen/tnetv107x-ts.c
@@ -13,6 +13,7 @@
* GNU General Public License for more details.
*/
+#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/err.h>
#include <linux/errno.h>
diff --git a/drivers/iommu/amd_iommu.c b/drivers/iommu/amd_iommu.c
index a14f8dc..0e4227f 100644
--- a/drivers/iommu/amd_iommu.c
+++ b/drivers/iommu/amd_iommu.c
@@ -605,7 +605,9 @@
* Writes the command to the IOMMUs command buffer and informs the
* hardware about the new command.
*/
-static int iommu_queue_command(struct amd_iommu *iommu, struct iommu_cmd *cmd)
+static int iommu_queue_command_sync(struct amd_iommu *iommu,
+ struct iommu_cmd *cmd,
+ bool sync)
{
u32 left, tail, head, next_tail;
unsigned long flags;
@@ -639,13 +641,18 @@
copy_cmd_to_buffer(iommu, cmd, tail);
/* We need to sync now to make sure all commands are processed */
- iommu->need_sync = true;
+ iommu->need_sync = sync;
spin_unlock_irqrestore(&iommu->lock, flags);
return 0;
}
+static int iommu_queue_command(struct amd_iommu *iommu, struct iommu_cmd *cmd)
+{
+ return iommu_queue_command_sync(iommu, cmd, true);
+}
+
/*
* This function queues a completion wait command into the command
* buffer of an IOMMU
@@ -661,7 +668,7 @@
build_completion_wait(&cmd, (u64)&sem);
- ret = iommu_queue_command(iommu, &cmd);
+ ret = iommu_queue_command_sync(iommu, &cmd, false);
if (ret)
return ret;
@@ -840,14 +847,9 @@
static void domain_flush_devices(struct protection_domain *domain)
{
struct iommu_dev_data *dev_data;
- unsigned long flags;
-
- spin_lock_irqsave(&domain->lock, flags);
list_for_each_entry(dev_data, &domain->dev_list, list)
device_flush_dte(dev_data);
-
- spin_unlock_irqrestore(&domain->lock, flags);
}
/****************************************************************************
diff --git a/drivers/leds/leds-ams-delta.c b/drivers/leds/leds-ams-delta.c
index b982603..8c00937 100644
--- a/drivers/leds/leds-ams-delta.c
+++ b/drivers/leds/leds-ams-delta.c
@@ -8,6 +8,7 @@
* published by the Free Software Foundation.
*/
+#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/platform_device.h>
diff --git a/drivers/leds/leds-bd2802.c b/drivers/leds/leds-bd2802.c
index 3ebe382..ea21855 100644
--- a/drivers/leds/leds-bd2802.c
+++ b/drivers/leds/leds-bd2802.c
@@ -662,6 +662,11 @@
static void bd2802_unregister_led_classdev(struct bd2802_led *led)
{
cancel_work_sync(&led->work);
+ led_classdev_unregister(&led->cdev_led2b);
+ led_classdev_unregister(&led->cdev_led2g);
+ led_classdev_unregister(&led->cdev_led2r);
+ led_classdev_unregister(&led->cdev_led1b);
+ led_classdev_unregister(&led->cdev_led1g);
led_classdev_unregister(&led->cdev_led1r);
}
diff --git a/drivers/leds/leds-hp6xx.c b/drivers/leds/leds-hp6xx.c
index e4ce1fd..bcfbd3a 100644
--- a/drivers/leds/leds-hp6xx.c
+++ b/drivers/leds/leds-hp6xx.c
@@ -10,6 +10,7 @@
* published by the Free Software Foundation.
*/
+#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/platform_device.h>
diff --git a/drivers/md/linear.h b/drivers/md/linear.h
index 0ce29b6..2f2da05 100644
--- a/drivers/md/linear.h
+++ b/drivers/md/linear.h
@@ -10,9 +10,9 @@
struct linear_private_data
{
+ struct rcu_head rcu;
sector_t array_sectors;
dev_info_t disks[0];
- struct rcu_head rcu;
};
diff --git a/drivers/md/md.c b/drivers/md/md.c
index 8e221a2..5404b22 100644
--- a/drivers/md/md.c
+++ b/drivers/md/md.c
@@ -848,7 +848,7 @@
bio->bi_end_io = super_written;
atomic_inc(&mddev->pending_writes);
- submit_bio(REQ_WRITE | REQ_SYNC | REQ_FLUSH | REQ_FUA, bio);
+ submit_bio(WRITE_FLUSH_FUA, bio);
}
void md_super_wait(mddev_t *mddev)
@@ -1138,8 +1138,11 @@
ret = 0;
}
rdev->sectors = rdev->sb_start;
+ /* Limit to 4TB as metadata cannot record more than that */
+ if (rdev->sectors >= (2ULL << 32))
+ rdev->sectors = (2ULL << 32) - 2;
- if (rdev->sectors < sb->size * 2 && sb->level > 1)
+ if (rdev->sectors < ((sector_t)sb->size) * 2 && sb->level >= 1)
/* "this cannot possibly happen" ... */
ret = -EINVAL;
@@ -1173,7 +1176,7 @@
mddev->clevel[0] = 0;
mddev->layout = sb->layout;
mddev->raid_disks = sb->raid_disks;
- mddev->dev_sectors = sb->size * 2;
+ mddev->dev_sectors = ((sector_t)sb->size) * 2;
mddev->events = ev1;
mddev->bitmap_info.offset = 0;
mddev->bitmap_info.default_offset = MD_SB_BYTES >> 9;
@@ -1415,6 +1418,11 @@
rdev->sb_start = calc_dev_sboffset(rdev);
if (!num_sectors || num_sectors > rdev->sb_start)
num_sectors = rdev->sb_start;
+ /* Limit to 4TB as metadata cannot record more than that.
+ * 4TB == 2^32 KB, or 2*2^32 sectors.
+ */
+ if (num_sectors >= (2ULL << 32))
+ num_sectors = (2ULL << 32) - 2;
md_super_write(rdev->mddev, rdev, rdev->sb_start, rdev->sb_size,
rdev->sb_page);
md_super_wait(rdev->mddev);
@@ -1738,6 +1746,11 @@
sb->level = cpu_to_le32(mddev->level);
sb->layout = cpu_to_le32(mddev->layout);
+ if (test_bit(WriteMostly, &rdev->flags))
+ sb->devflags |= WriteMostly1;
+ else
+ sb->devflags &= ~WriteMostly1;
+
if (mddev->bitmap && mddev->bitmap_info.file == NULL) {
sb->bitmap_offset = cpu_to_le32((__u32)mddev->bitmap_info.offset);
sb->feature_map = cpu_to_le32(MD_FEATURE_BITMAP_OFFSET);
@@ -2561,7 +2574,10 @@
int err = -EINVAL;
if (cmd_match(buf, "faulty") && rdev->mddev->pers) {
md_error(rdev->mddev, rdev);
- err = 0;
+ if (test_bit(Faulty, &rdev->flags))
+ err = 0;
+ else
+ err = -EBUSY;
} else if (cmd_match(buf, "remove")) {
if (rdev->raid_disk >= 0)
err = -EBUSY;
@@ -2584,7 +2600,7 @@
err = 0;
} else if (cmd_match(buf, "-blocked")) {
if (!test_bit(Faulty, &rdev->flags) &&
- test_bit(BlockedBadBlocks, &rdev->flags)) {
+ rdev->badblocks.unacked_exist) {
/* metadata handler doesn't understand badblocks,
* so we need to fail the device
*/
@@ -5983,6 +5999,8 @@
return -ENODEV;
md_error(mddev, rdev);
+ if (!test_bit(Faulty, &rdev->flags))
+ return -EBUSY;
return 0;
}
diff --git a/drivers/md/raid1.c b/drivers/md/raid1.c
index 32323f0..f4622dd 100644
--- a/drivers/md/raid1.c
+++ b/drivers/md/raid1.c
@@ -1099,12 +1099,11 @@
bio_list_add(&conf->pending_bio_list, mbio);
spin_unlock_irqrestore(&conf->device_lock, flags);
}
- r1_bio_write_done(r1_bio);
-
- /* In case raid1d snuck in to freeze_array */
- wake_up(&conf->wait_barrier);
-
+ /* Mustn't call r1_bio_write_done before this next test,
+ * as it could result in the bio being freed.
+ */
if (sectors_handled < (bio->bi_size >> 9)) {
+ r1_bio_write_done(r1_bio);
/* We need another r1_bio. It has already been counted
* in bio->bi_phys_segments
*/
@@ -1117,6 +1116,11 @@
goto retry_write;
}
+ r1_bio_write_done(r1_bio);
+
+ /* In case raid1d snuck in to freeze_array */
+ wake_up(&conf->wait_barrier);
+
if (do_sync || !bitmap || !plugged)
md_wakeup_thread(mddev->thread);
diff --git a/drivers/md/raid10.c b/drivers/md/raid10.c
index 8b29cd4..d7a8468 100644
--- a/drivers/md/raid10.c
+++ b/drivers/md/raid10.c
@@ -337,6 +337,21 @@
md_write_end(r10_bio->mddev);
}
+static void one_write_done(r10bio_t *r10_bio)
+{
+ if (atomic_dec_and_test(&r10_bio->remaining)) {
+ if (test_bit(R10BIO_WriteError, &r10_bio->state))
+ reschedule_retry(r10_bio);
+ else {
+ close_write(r10_bio);
+ if (test_bit(R10BIO_MadeGood, &r10_bio->state))
+ reschedule_retry(r10_bio);
+ else
+ raid_end_bio_io(r10_bio);
+ }
+ }
+}
+
static void raid10_end_write_request(struct bio *bio, int error)
{
int uptodate = test_bit(BIO_UPTODATE, &bio->bi_flags);
@@ -387,17 +402,7 @@
* Let's see if all mirrored write operations have finished
* already.
*/
- if (atomic_dec_and_test(&r10_bio->remaining)) {
- if (test_bit(R10BIO_WriteError, &r10_bio->state))
- reschedule_retry(r10_bio);
- else {
- close_write(r10_bio);
- if (test_bit(R10BIO_MadeGood, &r10_bio->state))
- reschedule_retry(r10_bio);
- else
- raid_end_bio_io(r10_bio);
- }
- }
+ one_write_done(r10_bio);
if (dec_rdev)
rdev_dec_pending(conf->mirrors[dev].rdev, conf->mddev);
}
@@ -1127,20 +1132,12 @@
spin_unlock_irqrestore(&conf->device_lock, flags);
}
- if (atomic_dec_and_test(&r10_bio->remaining)) {
- /* This matches the end of raid10_end_write_request() */
- bitmap_endwrite(r10_bio->mddev->bitmap, r10_bio->sector,
- r10_bio->sectors,
- !test_bit(R10BIO_Degraded, &r10_bio->state),
- 0);
- md_write_end(mddev);
- raid_end_bio_io(r10_bio);
- }
-
- /* In case raid10d snuck in to freeze_array */
- wake_up(&conf->wait_barrier);
+ /* Don't remove the bias on 'remaining' (one_write_done) until
+ * after checking if we need to go around again.
+ */
if (sectors_handled < (bio->bi_size >> 9)) {
+ one_write_done(r10_bio);
/* We need another r10_bio. It has already been counted
* in bio->bi_phys_segments.
*/
@@ -1154,6 +1151,10 @@
r10_bio->state = 0;
goto retry_write;
}
+ one_write_done(r10_bio);
+
+ /* In case raid10d snuck in to freeze_array */
+ wake_up(&conf->wait_barrier);
if (do_sync || !mddev->bitmap || !plugged)
md_wakeup_thread(mddev->thread);
diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c
index dbae459..43709fa 100644
--- a/drivers/md/raid5.c
+++ b/drivers/md/raid5.c
@@ -3336,7 +3336,7 @@
finish:
/* wait for this device to become unblocked */
- if (unlikely(s.blocked_rdev))
+ if (conf->mddev->external && unlikely(s.blocked_rdev))
md_wait_for_blocked_rdev(s.blocked_rdev, conf->mddev);
if (s.handle_bad_blocks)
diff --git a/drivers/media/dvb/dvb-usb/vp7045.c b/drivers/media/dvb/dvb-usb/vp7045.c
index 3db89e3..536c16c 100644
--- a/drivers/media/dvb/dvb-usb/vp7045.c
+++ b/drivers/media/dvb/dvb-usb/vp7045.c
@@ -224,26 +224,8 @@
static int vp7045_usb_probe(struct usb_interface *intf,
const struct usb_device_id *id)
{
- struct dvb_usb_device *d;
- int ret = dvb_usb_device_init(intf, &vp7045_properties,
- THIS_MODULE, &d, adapter_nr);
- if (ret)
- return ret;
-
- d->priv = kmalloc(20, GFP_KERNEL);
- if (!d->priv) {
- dvb_usb_device_exit(intf);
- return -ENOMEM;
- }
-
- return ret;
-}
-
-static void vp7045_usb_disconnect(struct usb_interface *intf)
-{
- struct dvb_usb_device *d = usb_get_intfdata(intf);
- kfree(d->priv);
- dvb_usb_device_exit(intf);
+ return dvb_usb_device_init(intf, &vp7045_properties,
+ THIS_MODULE, NULL, adapter_nr);
}
static struct usb_device_id vp7045_usb_table [] = {
@@ -258,7 +240,7 @@
static struct dvb_usb_device_properties vp7045_properties = {
.usb_ctrl = CYPRESS_FX2,
.firmware = "dvb-usb-vp7045-01.fw",
- .size_of_priv = sizeof(u8 *),
+ .size_of_priv = 20,
.num_adapters = 1,
.adapter = {
@@ -305,7 +287,7 @@
static struct usb_driver vp7045_usb_driver = {
.name = "dvb_usb_vp7045",
.probe = vp7045_usb_probe,
- .disconnect = vp7045_usb_disconnect,
+ .disconnect = dvb_usb_device_exit,
.id_table = vp7045_usb_table,
};
diff --git a/drivers/media/rc/nuvoton-cir.c b/drivers/media/rc/nuvoton-cir.c
index eae05b5..144f3f5 100644
--- a/drivers/media/rc/nuvoton-cir.c
+++ b/drivers/media/rc/nuvoton-cir.c
@@ -618,7 +618,6 @@
static void nvt_process_rx_ir_data(struct nvt_dev *nvt)
{
DEFINE_IR_RAW_EVENT(rawir);
- unsigned int count;
u32 carrier;
u8 sample;
int i;
@@ -631,65 +630,38 @@
if (nvt->carrier_detect_enabled)
carrier = nvt_rx_carrier_detect(nvt);
- count = nvt->pkts;
- nvt_dbg_verbose("Processing buffer of len %d", count);
+ nvt_dbg_verbose("Processing buffer of len %d", nvt->pkts);
init_ir_raw_event(&rawir);
- for (i = 0; i < count; i++) {
- nvt->pkts--;
+ for (i = 0; i < nvt->pkts; i++) {
sample = nvt->buf[i];
rawir.pulse = ((sample & BUF_PULSE_BIT) != 0);
rawir.duration = US_TO_NS((sample & BUF_LEN_MASK)
* SAMPLE_PERIOD);
- if ((sample & BUF_LEN_MASK) == BUF_LEN_MASK) {
- if (nvt->rawir.pulse == rawir.pulse)
- nvt->rawir.duration += rawir.duration;
- else {
- nvt->rawir.duration = rawir.duration;
- nvt->rawir.pulse = rawir.pulse;
- }
- continue;
- }
+ nvt_dbg("Storing %s with duration %d",
+ rawir.pulse ? "pulse" : "space", rawir.duration);
- rawir.duration += nvt->rawir.duration;
-
- init_ir_raw_event(&nvt->rawir);
- nvt->rawir.duration = 0;
- nvt->rawir.pulse = rawir.pulse;
-
- if (sample == BUF_PULSE_BIT)
- rawir.pulse = false;
-
- if (rawir.duration) {
- nvt_dbg("Storing %s with duration %d",
- rawir.pulse ? "pulse" : "space",
- rawir.duration);
-
- ir_raw_event_store_with_filter(nvt->rdev, &rawir);
- }
+ ir_raw_event_store_with_filter(nvt->rdev, &rawir);
/*
* BUF_PULSE_BIT indicates end of IR data, BUF_REPEAT_BYTE
* indicates end of IR signal, but new data incoming. In both
* cases, it means we're ready to call ir_raw_event_handle
*/
- if ((sample == BUF_PULSE_BIT) && nvt->pkts) {
+ if ((sample == BUF_PULSE_BIT) && (i + 1 < nvt->pkts)) {
nvt_dbg("Calling ir_raw_event_handle (signal end)\n");
ir_raw_event_handle(nvt->rdev);
}
}
+ nvt->pkts = 0;
+
nvt_dbg("Calling ir_raw_event_handle (buffer empty)\n");
ir_raw_event_handle(nvt->rdev);
- if (nvt->pkts) {
- nvt_dbg("Odd, pkts should be 0 now... (its %u)", nvt->pkts);
- nvt->pkts = 0;
- }
-
nvt_dbg_verbose("%s done", __func__);
}
@@ -1048,7 +1020,6 @@
spin_lock_init(&nvt->nvt_lock);
spin_lock_init(&nvt->tx.lock);
- init_ir_raw_event(&nvt->rawir);
ret = -EBUSY;
/* now claim resources */
diff --git a/drivers/media/rc/nuvoton-cir.h b/drivers/media/rc/nuvoton-cir.h
index 1241fc8..0d5e087 100644
--- a/drivers/media/rc/nuvoton-cir.h
+++ b/drivers/media/rc/nuvoton-cir.h
@@ -67,7 +67,6 @@
struct nvt_dev {
struct pnp_dev *pdev;
struct rc_dev *rdev;
- struct ir_raw_event rawir;
spinlock_t nvt_lock;
diff --git a/drivers/media/video/gspca/ov519.c b/drivers/media/video/gspca/ov519.c
index 0800433..18305c8 100644
--- a/drivers/media/video/gspca/ov519.c
+++ b/drivers/media/video/gspca/ov519.c
@@ -2858,7 +2858,6 @@
case 0x60:
PDEBUG(D_PROBE, "Sensor is a OV7660");
sd->sensor = SEN_OV7660;
- sd->invert_led = 0;
break;
default:
PDEBUG(D_PROBE, "Unknown sensor: 0x76%x", low);
@@ -3337,7 +3336,6 @@
case BRIDGE_OV519:
cam->cam_mode = ov519_vga_mode;
cam->nmodes = ARRAY_SIZE(ov519_vga_mode);
- sd->invert_led = !sd->invert_led;
break;
case BRIDGE_OVFX2:
cam->cam_mode = ov519_vga_mode;
@@ -5005,24 +5003,24 @@
/* -- module initialisation -- */
static const struct usb_device_id device_table[] = {
{USB_DEVICE(0x041e, 0x4003), .driver_info = BRIDGE_W9968CF },
- {USB_DEVICE(0x041e, 0x4052), .driver_info = BRIDGE_OV519 },
- {USB_DEVICE(0x041e, 0x405f),
+ {USB_DEVICE(0x041e, 0x4052),
.driver_info = BRIDGE_OV519 | BRIDGE_INVERT_LED },
+ {USB_DEVICE(0x041e, 0x405f), .driver_info = BRIDGE_OV519 },
{USB_DEVICE(0x041e, 0x4060), .driver_info = BRIDGE_OV519 },
{USB_DEVICE(0x041e, 0x4061), .driver_info = BRIDGE_OV519 },
- {USB_DEVICE(0x041e, 0x4064),
- .driver_info = BRIDGE_OV519 | BRIDGE_INVERT_LED },
+ {USB_DEVICE(0x041e, 0x4064), .driver_info = BRIDGE_OV519 },
{USB_DEVICE(0x041e, 0x4067), .driver_info = BRIDGE_OV519 },
- {USB_DEVICE(0x041e, 0x4068),
+ {USB_DEVICE(0x041e, 0x4068), .driver_info = BRIDGE_OV519 },
+ {USB_DEVICE(0x045e, 0x028c),
.driver_info = BRIDGE_OV519 | BRIDGE_INVERT_LED },
- {USB_DEVICE(0x045e, 0x028c), .driver_info = BRIDGE_OV519 },
{USB_DEVICE(0x054c, 0x0154), .driver_info = BRIDGE_OV519 },
- {USB_DEVICE(0x054c, 0x0155),
- .driver_info = BRIDGE_OV519 | BRIDGE_INVERT_LED },
+ {USB_DEVICE(0x054c, 0x0155), .driver_info = BRIDGE_OV519 },
{USB_DEVICE(0x05a9, 0x0511), .driver_info = BRIDGE_OV511 },
{USB_DEVICE(0x05a9, 0x0518), .driver_info = BRIDGE_OV518 },
- {USB_DEVICE(0x05a9, 0x0519), .driver_info = BRIDGE_OV519 },
- {USB_DEVICE(0x05a9, 0x0530), .driver_info = BRIDGE_OV519 },
+ {USB_DEVICE(0x05a9, 0x0519),
+ .driver_info = BRIDGE_OV519 | BRIDGE_INVERT_LED },
+ {USB_DEVICE(0x05a9, 0x0530),
+ .driver_info = BRIDGE_OV519 | BRIDGE_INVERT_LED },
{USB_DEVICE(0x05a9, 0x2800), .driver_info = BRIDGE_OVFX2 },
{USB_DEVICE(0x05a9, 0x4519), .driver_info = BRIDGE_OV519 },
{USB_DEVICE(0x05a9, 0x8519), .driver_info = BRIDGE_OV519 },
diff --git a/drivers/media/video/gspca/sonixj.c b/drivers/media/video/gspca/sonixj.c
index 81b8a60..c477ad1 100644
--- a/drivers/media/video/gspca/sonixj.c
+++ b/drivers/media/video/gspca/sonixj.c
@@ -2386,7 +2386,7 @@
reg_w1(gspca_dev, 0x01, 0x22);
msleep(100);
reg01 = SCL_SEL_OD | S_PDN_INV;
- reg17 &= MCK_SIZE_MASK;
+ reg17 &= ~MCK_SIZE_MASK;
reg17 |= 0x04; /* clock / 4 */
break;
}
@@ -2532,6 +2532,10 @@
if (!mode) { /* if 640x480 */
reg17 &= ~MCK_SIZE_MASK;
reg17 |= 0x04; /* clock / 4 */
+ } else {
+ reg01 &= ~SYS_SEL_48M; /* clk 24Mz */
+ reg17 &= ~MCK_SIZE_MASK;
+ reg17 |= 0x02; /* clock / 2 */
}
break;
case SENSOR_OV7630:
diff --git a/drivers/media/video/pwc/pwc-v4l.c b/drivers/media/video/pwc/pwc-v4l.c
index e9a0e94..8c70e64 100644
--- a/drivers/media/video/pwc/pwc-v4l.c
+++ b/drivers/media/video/pwc/pwc-v4l.c
@@ -338,7 +338,7 @@
if (pdev->restore_factory)
pdev->restore_factory->flags = V4L2_CTRL_FLAG_UPDATE;
- if (!pdev->features & FEATURE_MOTOR_PANTILT)
+ if (!(pdev->features & FEATURE_MOTOR_PANTILT))
return hdl->error;
/* Motor pan / tilt / reset */
diff --git a/drivers/media/video/via-camera.c b/drivers/media/video/via-camera.c
index 85d3048..bb7f17f 100644
--- a/drivers/media/video/via-camera.c
+++ b/drivers/media/video/via-camera.c
@@ -1332,6 +1332,8 @@
struct pci_bus *pbus = pci_find_bus(0, 0);
u8 cbyte;
+ if (!pbus)
+ return false;
pci_bus_read_config_byte(pbus, VIACAM_SERIAL_DEVFN,
VIACAM_SERIAL_CREG, &cbyte);
if ((cbyte & VIACAM_SERIAL_BIT) == 0)
diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig
index 0a4d86c..2d6423c 100644
--- a/drivers/misc/Kconfig
+++ b/drivers/misc/Kconfig
@@ -146,6 +146,7 @@
config INTEL_MID_PTI
tristate "Parallel Trace Interface for MIPI P1149.7 cJTAG standard"
+ depends on PCI
default n
help
The PTI (Parallel Trace Interface) driver directs
diff --git a/drivers/misc/ab8500-pwm.c b/drivers/misc/ab8500-pwm.c
index 54e3d05..3590315 100644
--- a/drivers/misc/ab8500-pwm.c
+++ b/drivers/misc/ab8500-pwm.c
@@ -164,5 +164,5 @@
module_exit(ab8500_pwm_exit);
MODULE_AUTHOR("Arun MURTHY <arun.murthy@stericsson.com>");
MODULE_DESCRIPTION("AB8500 Pulse Width Modulation Driver");
-MODULE_ALIAS("AB8500 PWM driver");
+MODULE_ALIAS("platform:ab8500-pwm");
MODULE_LICENSE("GPL v2");
diff --git a/drivers/misc/fsa9480.c b/drivers/misc/fsa9480.c
index 5325a7e..27dc0d2 100644
--- a/drivers/misc/fsa9480.c
+++ b/drivers/misc/fsa9480.c
@@ -455,7 +455,7 @@
fail2:
if (client->irq)
- free_irq(client->irq, NULL);
+ free_irq(client->irq, usbsw);
fail1:
i2c_set_clientdata(client, NULL);
kfree(usbsw);
@@ -466,7 +466,7 @@
{
struct fsa9480_usbsw *usbsw = i2c_get_clientdata(client);
if (client->irq)
- free_irq(client->irq, NULL);
+ free_irq(client->irq, usbsw);
i2c_set_clientdata(client, NULL);
sysfs_remove_group(&client->dev.kobj, &fsa9480_group);
diff --git a/drivers/misc/pti.c b/drivers/misc/pti.c
index 8653bd0..06df187 100644
--- a/drivers/misc/pti.c
+++ b/drivers/misc/pti.c
@@ -33,6 +33,8 @@
#include <linux/mutex.h>
#include <linux/miscdevice.h>
#include <linux/pti.h>
+#include <linux/slab.h>
+#include <linux/uaccess.h>
#define DRIVERNAME "pti"
#define PCINAME "pciPTI"
diff --git a/drivers/misc/ti-st/st_core.c b/drivers/misc/ti-st/st_core.c
index 54c91ff..ba168a7 100644
--- a/drivers/misc/ti-st/st_core.c
+++ b/drivers/misc/ti-st/st_core.c
@@ -338,6 +338,12 @@
/* Unknow packet? */
default:
type = *ptr;
+ if (st_gdata->list[type] == NULL) {
+ pr_err("chip/interface misbehavior dropping"
+ " frame starting with 0x%02x", type);
+ goto done;
+
+ }
st_gdata->rx_skb = alloc_skb(
st_gdata->list[type]->max_frame_size,
GFP_ATOMIC);
@@ -354,6 +360,7 @@
ptr++;
count--;
}
+done:
spin_unlock_irqrestore(&st_gdata->lock, flags);
pr_debug("done %s", __func__);
return;
@@ -717,9 +724,10 @@
*/
spin_lock_irqsave(&st_gdata->lock, flags);
for (i = ST_BT; i < ST_MAX_CHANNELS; i++) {
- if (st_gdata->list[i] != NULL)
+ if (st_gdata->is_registered[i] == true)
pr_err("%d not un-registered", i);
st_gdata->list[i] = NULL;
+ st_gdata->is_registered[i] = false;
}
st_gdata->protos_registered = 0;
spin_unlock_irqrestore(&st_gdata->lock, flags);
diff --git a/drivers/misc/ti-st/st_kim.c b/drivers/misc/ti-st/st_kim.c
index 38fd2f0..3a35805 100644
--- a/drivers/misc/ti-st/st_kim.c
+++ b/drivers/misc/ti-st/st_kim.c
@@ -68,6 +68,7 @@
if (unlikely(skb->data[5] != 0)) {
pr_err("no proper response during fw download");
pr_err("data6 %x", skb->data[5]);
+ kfree_skb(skb);
return; /* keep waiting for the proper response */
}
/* becos of all the script being downloaded */
@@ -210,6 +211,7 @@
pr_err(" waiting for ver info- timed out ");
return -ETIMEDOUT;
}
+ INIT_COMPLETION(kim_gdata->kim_rcvd);
version =
MAKEWORD(kim_gdata->resp_buffer[13],
@@ -298,6 +300,7 @@
switch (((struct bts_action *)ptr)->type) {
case ACTION_SEND_COMMAND: /* action send */
+ pr_debug("S");
action_ptr = &(((struct bts_action *)ptr)->data[0]);
if (unlikely
(((struct hci_command *)action_ptr)->opcode ==
@@ -335,6 +338,10 @@
release_firmware(kim_gdata->fw_entry);
return -ETIMEDOUT;
}
+ /* reinit completion before sending for the
+ * relevant wait
+ */
+ INIT_COMPLETION(kim_gdata->kim_rcvd);
/*
* Free space found in uart buffer, call st_int_write
@@ -361,6 +368,7 @@
}
break;
case ACTION_WAIT_EVENT: /* wait */
+ pr_debug("W");
if (!wait_for_completion_timeout
(&kim_gdata->kim_rcvd,
msecs_to_jiffies(CMD_RESP_TIME))) {
@@ -434,11 +442,17 @@
{
long err = 0;
long retry = POR_RETRY_COUNT;
+ struct ti_st_plat_data *pdata;
struct kim_data_s *kim_gdata = (struct kim_data_s *)kim_data;
pr_info(" %s", __func__);
+ pdata = kim_gdata->kim_pdev->dev.platform_data;
do {
+ /* platform specific enabling code here */
+ if (pdata->chip_enable)
+ pdata->chip_enable(kim_gdata);
+
/* Configure BT nShutdown to HIGH state */
gpio_set_value(kim_gdata->nshutdown, GPIO_LOW);
mdelay(5); /* FIXME: a proper toggle */
@@ -460,6 +474,12 @@
pr_info("ldisc_install = 0");
sysfs_notify(&kim_gdata->kim_pdev->dev.kobj,
NULL, "install");
+ /* the following wait is never going to be completed,
+ * since the ldisc was never installed, hence serving
+ * as a mdelay of LDISC_TIME msecs */
+ err = wait_for_completion_timeout
+ (&kim_gdata->ldisc_installed,
+ msecs_to_jiffies(LDISC_TIME));
err = -ETIMEDOUT;
continue;
} else {
@@ -472,6 +492,13 @@
pr_info("ldisc_install = 0");
sysfs_notify(&kim_gdata->kim_pdev->dev.kobj,
NULL, "install");
+ /* this wait might be completed, though in the
+ * tty_close() since the ldisc is already
+ * installed */
+ err = wait_for_completion_timeout
+ (&kim_gdata->ldisc_installed,
+ msecs_to_jiffies(LDISC_TIME));
+ err = -EINVAL;
continue;
} else { /* on success don't retry */
break;
@@ -489,6 +516,8 @@
{
long err = 0;
struct kim_data_s *kim_gdata = (struct kim_data_s *)kim_data;
+ struct ti_st_plat_data *pdata =
+ kim_gdata->kim_pdev->dev.platform_data;
INIT_COMPLETION(kim_gdata->ldisc_installed);
@@ -515,6 +544,10 @@
gpio_set_value(kim_gdata->nshutdown, GPIO_HIGH);
mdelay(1);
gpio_set_value(kim_gdata->nshutdown, GPIO_LOW);
+
+ /* platform specific disable */
+ if (pdata->chip_disable)
+ pdata->chip_disable(kim_gdata);
return err;
}
diff --git a/drivers/misc/ti-st/st_ll.c b/drivers/misc/ti-st/st_ll.c
index 3f24951..1ff460a 100644
--- a/drivers/misc/ti-st/st_ll.c
+++ b/drivers/misc/ti-st/st_ll.c
@@ -22,6 +22,7 @@
#define pr_fmt(fmt) "(stll) :" fmt
#include <linux/skbuff.h>
#include <linux/module.h>
+#include <linux/platform_device.h>
#include <linux/ti_wilink_st.h>
/**********************************************************************/
@@ -37,6 +38,9 @@
static void ll_device_want_to_sleep(struct st_data_s *st_data)
{
+ struct kim_data_s *kim_data;
+ struct ti_st_plat_data *pdata;
+
pr_debug("%s", __func__);
/* sanity check */
if (st_data->ll_state != ST_LL_AWAKE)
@@ -46,10 +50,19 @@
send_ll_cmd(st_data, LL_SLEEP_ACK);
/* update state */
st_data->ll_state = ST_LL_ASLEEP;
+
+ /* communicate to platform about chip asleep */
+ kim_data = st_data->kim_data;
+ pdata = kim_data->kim_pdev->dev.platform_data;
+ if (pdata->chip_asleep)
+ pdata->chip_asleep(NULL);
}
static void ll_device_want_to_wakeup(struct st_data_s *st_data)
{
+ struct kim_data_s *kim_data;
+ struct ti_st_plat_data *pdata;
+
/* diff actions in diff states */
switch (st_data->ll_state) {
case ST_LL_ASLEEP:
@@ -70,6 +83,12 @@
}
/* update state */
st_data->ll_state = ST_LL_AWAKE;
+
+ /* communicate to platform about chip wakeup */
+ kim_data = st_data->kim_data;
+ pdata = kim_data->kim_pdev->dev.platform_data;
+ if (pdata->chip_asleep)
+ pdata->chip_awake(NULL);
}
/**********************************************************************/
diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c
index 91a0a74..b27b940 100644
--- a/drivers/mmc/core/core.c
+++ b/drivers/mmc/core/core.c
@@ -133,7 +133,7 @@
if (mrq->done)
mrq->done(mrq);
- mmc_host_clk_gate(host);
+ mmc_host_clk_release(host);
}
}
@@ -192,7 +192,7 @@
mrq->stop->mrq = mrq;
}
}
- mmc_host_clk_ungate(host);
+ mmc_host_clk_hold(host);
led_trigger_event(host->led, LED_FULL);
host->ops->request(host, mrq);
}
@@ -728,15 +728,17 @@
*/
void mmc_set_chip_select(struct mmc_host *host, int mode)
{
+ mmc_host_clk_hold(host);
host->ios.chip_select = mode;
mmc_set_ios(host);
+ mmc_host_clk_release(host);
}
/*
* Sets the host clock to the highest possible frequency that
* is below "hz".
*/
-void mmc_set_clock(struct mmc_host *host, unsigned int hz)
+static void __mmc_set_clock(struct mmc_host *host, unsigned int hz)
{
WARN_ON(hz < host->f_min);
@@ -747,6 +749,13 @@
mmc_set_ios(host);
}
+void mmc_set_clock(struct mmc_host *host, unsigned int hz)
+{
+ mmc_host_clk_hold(host);
+ __mmc_set_clock(host, hz);
+ mmc_host_clk_release(host);
+}
+
#ifdef CONFIG_MMC_CLKGATE
/*
* This gates the clock by setting it to 0 Hz.
@@ -779,7 +788,7 @@
if (host->clk_old) {
BUG_ON(host->ios.clock);
/* This call will also set host->clk_gated to false */
- mmc_set_clock(host, host->clk_old);
+ __mmc_set_clock(host, host->clk_old);
}
}
@@ -807,8 +816,10 @@
*/
void mmc_set_bus_mode(struct mmc_host *host, unsigned int mode)
{
+ mmc_host_clk_hold(host);
host->ios.bus_mode = mode;
mmc_set_ios(host);
+ mmc_host_clk_release(host);
}
/*
@@ -816,8 +827,10 @@
*/
void mmc_set_bus_width(struct mmc_host *host, unsigned int width)
{
+ mmc_host_clk_hold(host);
host->ios.bus_width = width;
mmc_set_ios(host);
+ mmc_host_clk_release(host);
}
/**
@@ -1015,8 +1028,10 @@
ocr &= 3 << bit;
+ mmc_host_clk_hold(host);
host->ios.vdd = bit;
mmc_set_ios(host);
+ mmc_host_clk_release(host);
} else {
pr_warning("%s: host doesn't support card's voltages\n",
mmc_hostname(host));
@@ -1063,8 +1078,10 @@
*/
void mmc_set_timing(struct mmc_host *host, unsigned int timing)
{
+ mmc_host_clk_hold(host);
host->ios.timing = timing;
mmc_set_ios(host);
+ mmc_host_clk_release(host);
}
/*
@@ -1072,8 +1089,10 @@
*/
void mmc_set_driver_type(struct mmc_host *host, unsigned int drv_type)
{
+ mmc_host_clk_hold(host);
host->ios.drv_type = drv_type;
mmc_set_ios(host);
+ mmc_host_clk_release(host);
}
/*
@@ -1091,6 +1110,8 @@
{
int bit;
+ mmc_host_clk_hold(host);
+
/* If ocr is set, we use it */
if (host->ocr)
bit = ffs(host->ocr) - 1;
@@ -1126,10 +1147,14 @@
* time required to reach a stable voltage.
*/
mmc_delay(10);
+
+ mmc_host_clk_release(host);
}
static void mmc_power_off(struct mmc_host *host)
{
+ mmc_host_clk_hold(host);
+
host->ios.clock = 0;
host->ios.vdd = 0;
@@ -1147,6 +1172,8 @@
host->ios.bus_width = MMC_BUS_WIDTH_1;
host->ios.timing = MMC_TIMING_LEGACY;
mmc_set_ios(host);
+
+ mmc_host_clk_release(host);
}
/*
diff --git a/drivers/mmc/core/host.c b/drivers/mmc/core/host.c
index b29d3e8..793d0a0 100644
--- a/drivers/mmc/core/host.c
+++ b/drivers/mmc/core/host.c
@@ -119,14 +119,14 @@
}
/**
- * mmc_host_clk_ungate - ungate hardware MCI clocks
+ * mmc_host_clk_hold - ungate hardware MCI clocks
* @host: host to ungate.
*
* Makes sure the host ios.clock is restored to a non-zero value
* past this call. Increase clock reference count and ungate clock
* if we're the first user.
*/
-void mmc_host_clk_ungate(struct mmc_host *host)
+void mmc_host_clk_hold(struct mmc_host *host)
{
unsigned long flags;
@@ -164,14 +164,14 @@
}
/**
- * mmc_host_clk_gate - gate off hardware MCI clocks
+ * mmc_host_clk_release - gate off hardware MCI clocks
* @host: host to gate.
*
* Calls the host driver with ios.clock set to zero as often as possible
* in order to gate off hardware MCI clocks. Decrease clock reference
* count and schedule disabling of clock.
*/
-void mmc_host_clk_gate(struct mmc_host *host)
+void mmc_host_clk_release(struct mmc_host *host)
{
unsigned long flags;
@@ -179,7 +179,7 @@
host->clk_requests--;
if (mmc_host_may_gate_card(host->card) &&
!host->clk_requests)
- schedule_work(&host->clk_gate_work);
+ queue_work(system_nrt_wq, &host->clk_gate_work);
spin_unlock_irqrestore(&host->clk_lock, flags);
}
@@ -231,7 +231,7 @@
if (cancel_work_sync(&host->clk_gate_work))
mmc_host_clk_gate_delayed(host);
if (host->clk_gated)
- mmc_host_clk_ungate(host);
+ mmc_host_clk_hold(host);
/* There should be only one user now */
WARN_ON(host->clk_requests > 1);
}
diff --git a/drivers/mmc/core/host.h b/drivers/mmc/core/host.h
index de199f9..fb8a5cd 100644
--- a/drivers/mmc/core/host.h
+++ b/drivers/mmc/core/host.h
@@ -16,16 +16,16 @@
void mmc_unregister_host_class(void);
#ifdef CONFIG_MMC_CLKGATE
-void mmc_host_clk_ungate(struct mmc_host *host);
-void mmc_host_clk_gate(struct mmc_host *host);
+void mmc_host_clk_hold(struct mmc_host *host);
+void mmc_host_clk_release(struct mmc_host *host);
unsigned int mmc_host_clk_rate(struct mmc_host *host);
#else
-static inline void mmc_host_clk_ungate(struct mmc_host *host)
+static inline void mmc_host_clk_hold(struct mmc_host *host)
{
}
-static inline void mmc_host_clk_gate(struct mmc_host *host)
+static inline void mmc_host_clk_release(struct mmc_host *host)
{
}
diff --git a/drivers/mmc/core/sd.c b/drivers/mmc/core/sd.c
index 633975f..0370e03 100644
--- a/drivers/mmc/core/sd.c
+++ b/drivers/mmc/core/sd.c
@@ -469,56 +469,75 @@
return 0;
}
-static int sd_set_bus_speed_mode(struct mmc_card *card, u8 *status)
+static void sd_update_bus_speed_mode(struct mmc_card *card)
{
- unsigned int bus_speed = 0, timing = 0;
- int err;
-
/*
* If the host doesn't support any of the UHS-I modes, fallback on
* default speed.
*/
if (!(card->host->caps & (MMC_CAP_UHS_SDR12 | MMC_CAP_UHS_SDR25 |
- MMC_CAP_UHS_SDR50 | MMC_CAP_UHS_SDR104 | MMC_CAP_UHS_DDR50)))
- return 0;
+ MMC_CAP_UHS_SDR50 | MMC_CAP_UHS_SDR104 | MMC_CAP_UHS_DDR50))) {
+ card->sd_bus_speed = 0;
+ return;
+ }
if ((card->host->caps & MMC_CAP_UHS_SDR104) &&
(card->sw_caps.sd3_bus_mode & SD_MODE_UHS_SDR104)) {
- bus_speed = UHS_SDR104_BUS_SPEED;
- timing = MMC_TIMING_UHS_SDR104;
- card->sw_caps.uhs_max_dtr = UHS_SDR104_MAX_DTR;
+ card->sd_bus_speed = UHS_SDR104_BUS_SPEED;
} else if ((card->host->caps & MMC_CAP_UHS_DDR50) &&
(card->sw_caps.sd3_bus_mode & SD_MODE_UHS_DDR50)) {
- bus_speed = UHS_DDR50_BUS_SPEED;
- timing = MMC_TIMING_UHS_DDR50;
- card->sw_caps.uhs_max_dtr = UHS_DDR50_MAX_DTR;
+ card->sd_bus_speed = UHS_DDR50_BUS_SPEED;
} else if ((card->host->caps & (MMC_CAP_UHS_SDR104 |
MMC_CAP_UHS_SDR50)) && (card->sw_caps.sd3_bus_mode &
SD_MODE_UHS_SDR50)) {
- bus_speed = UHS_SDR50_BUS_SPEED;
- timing = MMC_TIMING_UHS_SDR50;
- card->sw_caps.uhs_max_dtr = UHS_SDR50_MAX_DTR;
+ card->sd_bus_speed = UHS_SDR50_BUS_SPEED;
} else if ((card->host->caps & (MMC_CAP_UHS_SDR104 |
MMC_CAP_UHS_SDR50 | MMC_CAP_UHS_SDR25)) &&
(card->sw_caps.sd3_bus_mode & SD_MODE_UHS_SDR25)) {
- bus_speed = UHS_SDR25_BUS_SPEED;
- timing = MMC_TIMING_UHS_SDR25;
- card->sw_caps.uhs_max_dtr = UHS_SDR25_MAX_DTR;
+ card->sd_bus_speed = UHS_SDR25_BUS_SPEED;
} else if ((card->host->caps & (MMC_CAP_UHS_SDR104 |
MMC_CAP_UHS_SDR50 | MMC_CAP_UHS_SDR25 |
MMC_CAP_UHS_SDR12)) && (card->sw_caps.sd3_bus_mode &
SD_MODE_UHS_SDR12)) {
- bus_speed = UHS_SDR12_BUS_SPEED;
- timing = MMC_TIMING_UHS_SDR12;
- card->sw_caps.uhs_max_dtr = UHS_SDR12_MAX_DTR;
+ card->sd_bus_speed = UHS_SDR12_BUS_SPEED;
+ }
+}
+
+static int sd_set_bus_speed_mode(struct mmc_card *card, u8 *status)
+{
+ int err;
+ unsigned int timing = 0;
+
+ switch (card->sd_bus_speed) {
+ case UHS_SDR104_BUS_SPEED:
+ timing = MMC_TIMING_UHS_SDR104;
+ card->sw_caps.uhs_max_dtr = UHS_SDR104_MAX_DTR;
+ break;
+ case UHS_DDR50_BUS_SPEED:
+ timing = MMC_TIMING_UHS_DDR50;
+ card->sw_caps.uhs_max_dtr = UHS_DDR50_MAX_DTR;
+ break;
+ case UHS_SDR50_BUS_SPEED:
+ timing = MMC_TIMING_UHS_SDR50;
+ card->sw_caps.uhs_max_dtr = UHS_SDR50_MAX_DTR;
+ break;
+ case UHS_SDR25_BUS_SPEED:
+ timing = MMC_TIMING_UHS_SDR25;
+ card->sw_caps.uhs_max_dtr = UHS_SDR25_MAX_DTR;
+ break;
+ case UHS_SDR12_BUS_SPEED:
+ timing = MMC_TIMING_UHS_SDR12;
+ card->sw_caps.uhs_max_dtr = UHS_SDR12_MAX_DTR;
+ break;
+ default:
+ return 0;
}
- card->sd_bus_speed = bus_speed;
- err = mmc_sd_switch(card, 1, 0, bus_speed, status);
+ err = mmc_sd_switch(card, 1, 0, card->sd_bus_speed, status);
if (err)
return err;
- if ((status[16] & 0xF) != bus_speed)
+ if ((status[16] & 0xF) != card->sd_bus_speed)
printk(KERN_WARNING "%s: Problem setting bus speed mode!\n",
mmc_hostname(card->host));
else {
@@ -618,18 +637,24 @@
mmc_set_bus_width(card->host, MMC_BUS_WIDTH_4);
}
+ /*
+ * Select the bus speed mode depending on host
+ * and card capability.
+ */
+ sd_update_bus_speed_mode(card);
+
/* Set the driver strength for the card */
err = sd_select_driver_type(card, status);
if (err)
goto out;
- /* Set bus speed mode of the card */
- err = sd_set_bus_speed_mode(card, status);
+ /* Set current limit for the card */
+ err = sd_set_current_limit(card, status);
if (err)
goto out;
- /* Set current limit for the card */
- err = sd_set_current_limit(card, status);
+ /* Set bus speed mode of the card */
+ err = sd_set_bus_speed_mode(card, status);
if (err)
goto out;
diff --git a/drivers/mmc/host/sdhci-esdhc-imx.c b/drivers/mmc/host/sdhci-esdhc-imx.c
index 0e9780f..4dc0028 100644
--- a/drivers/mmc/host/sdhci-esdhc-imx.c
+++ b/drivers/mmc/host/sdhci-esdhc-imx.c
@@ -16,6 +16,7 @@
#include <linux/err.h>
#include <linux/clk.h>
#include <linux/gpio.h>
+#include <linux/module.h>
#include <linux/slab.h>
#include <linux/mmc/host.h>
#include <linux/mmc/mmc.h>
diff --git a/drivers/mmc/host/sdhci-s3c.c b/drivers/mmc/host/sdhci-s3c.c
index 2bd7bf4..fe886d6 100644
--- a/drivers/mmc/host/sdhci-s3c.c
+++ b/drivers/mmc/host/sdhci-s3c.c
@@ -302,6 +302,8 @@
ctrl &= ~SDHCI_CTRL_8BITBUS;
break;
default:
+ ctrl &= ~SDHCI_CTRL_4BITBUS;
+ ctrl &= ~SDHCI_CTRL_8BITBUS;
break;
}
diff --git a/drivers/mmc/host/sh_mobile_sdhi.c b/drivers/mmc/host/sh_mobile_sdhi.c
index 774f643..0c4a672 100644
--- a/drivers/mmc/host/sh_mobile_sdhi.c
+++ b/drivers/mmc/host/sh_mobile_sdhi.c
@@ -120,11 +120,11 @@
mmc_data->hclk = clk_get_rate(priv->clk);
mmc_data->set_pwr = sh_mobile_sdhi_set_pwr;
mmc_data->get_cd = sh_mobile_sdhi_get_cd;
- if (mmc_data->flags & TMIO_MMC_HAS_IDLE_WAIT)
- mmc_data->write16_hook = sh_mobile_sdhi_write16_hook;
mmc_data->capabilities = MMC_CAP_MMC_HIGHSPEED;
if (p) {
mmc_data->flags = p->tmio_flags;
+ if (mmc_data->flags & TMIO_MMC_HAS_IDLE_WAIT)
+ mmc_data->write16_hook = sh_mobile_sdhi_write16_hook;
mmc_data->ocr_mask = p->tmio_ocr_mask;
mmc_data->capabilities |= p->tmio_caps;
diff --git a/drivers/mtd/ubi/debug.h b/drivers/mtd/ubi/debug.h
index 65b5b76..64fbb00 100644
--- a/drivers/mtd/ubi/debug.h
+++ b/drivers/mtd/ubi/debug.h
@@ -181,7 +181,7 @@
#define ubi_dbg_msg(fmt, ...) do { \
if (0) \
- pr_debug(fmt "\n", ##__VA_ARGS__); \
+ printk(KERN_DEBUG fmt "\n", ##__VA_ARGS__); \
} while (0)
#define dbg_msg(fmt, ...) ubi_dbg_msg(fmt, ##__VA_ARGS__)
diff --git a/drivers/net/arm/am79c961a.c b/drivers/net/arm/am79c961a.c
index 52fe21e..3b1416e 100644
--- a/drivers/net/arm/am79c961a.c
+++ b/drivers/net/arm/am79c961a.c
@@ -308,8 +308,11 @@
struct net_device *dev = (struct net_device *)data;
struct dev_priv *priv = netdev_priv(dev);
unsigned int lnkstat, carrier;
+ unsigned long flags;
+ spin_lock_irqsave(&priv->chip_lock, flags);
lnkstat = read_ireg(dev->base_addr, ISALED0) & ISALED0_LNKST;
+ spin_unlock_irqrestore(&priv->chip_lock, flags);
carrier = netif_carrier_ok(dev);
if (lnkstat && !carrier) {
diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c
index 38a83ac..43f2ea5 100644
--- a/drivers/net/bonding/bond_main.c
+++ b/drivers/net/bonding/bond_main.c
@@ -3419,9 +3419,27 @@
static int bond_open(struct net_device *bond_dev)
{
struct bonding *bond = netdev_priv(bond_dev);
+ struct slave *slave;
+ int i;
bond->kill_timers = 0;
+ /* reset slave->backup and slave->inactive */
+ read_lock(&bond->lock);
+ if (bond->slave_cnt > 0) {
+ read_lock(&bond->curr_slave_lock);
+ bond_for_each_slave(bond, slave, i) {
+ if ((bond->params.mode == BOND_MODE_ACTIVEBACKUP)
+ && (slave != bond->curr_active_slave)) {
+ bond_set_slave_inactive_flags(slave);
+ } else {
+ bond_set_slave_active_flags(slave);
+ }
+ }
+ read_unlock(&bond->curr_slave_lock);
+ }
+ read_unlock(&bond->lock);
+
INIT_DELAYED_WORK(&bond->mcast_work, bond_resend_igmp_join_requests_delayed);
if (bond_is_lb(bond)) {
diff --git a/drivers/net/can/sja1000/plx_pci.c b/drivers/net/can/sja1000/plx_pci.c
index 231385b..c7f3d4e 100644
--- a/drivers/net/can/sja1000/plx_pci.c
+++ b/drivers/net/can/sja1000/plx_pci.c
@@ -408,7 +408,7 @@
struct sja1000_priv *priv;
int i = 0;
- for (i = 0; i < card->channels; i++) {
+ for (i = 0; i < PLX_PCI_MAX_CHAN; i++) {
dev = card->net_dev[i];
if (!dev)
continue;
@@ -536,7 +536,6 @@
if (err) {
dev_err(&pdev->dev, "Registering device failed "
"(err=%d)\n", err);
- free_sja1000dev(dev);
goto failure_cleanup;
}
@@ -549,6 +548,7 @@
dev_err(&pdev->dev, "Channel #%d not detected\n",
i + 1);
free_sja1000dev(dev);
+ card->net_dev[i] = NULL;
}
}
diff --git a/drivers/net/can/ti_hecc.c b/drivers/net/can/ti_hecc.c
index f7bbde9..a812492 100644
--- a/drivers/net/can/ti_hecc.c
+++ b/drivers/net/can/ti_hecc.c
@@ -503,9 +503,9 @@
spin_unlock_irqrestore(&priv->mbx_lock, flags);
/* Prepare mailbox for transmission */
+ data = cf->can_dlc | (get_tx_head_prio(priv) << 8);
if (cf->can_id & CAN_RTR_FLAG) /* Remote transmission request */
data |= HECC_CANMCF_RTR;
- data |= get_tx_head_prio(priv) << 8;
hecc_write_mbx(priv, mbxno, HECC_CANMCF, data);
if (cf->can_id & CAN_EFF_FLAG) /* Extended frame format */
@@ -923,6 +923,7 @@
priv->can.do_get_state = ti_hecc_get_state;
priv->can.ctrlmode_supported = CAN_CTRLMODE_3_SAMPLES;
+ spin_lock_init(&priv->mbx_lock);
ndev->irq = irq->start;
ndev->flags |= IFF_ECHO;
platform_set_drvdata(pdev, ndev);
diff --git a/drivers/net/cassini.c b/drivers/net/cassini.c
index 646c86b..fdb7a17 100644
--- a/drivers/net/cassini.c
+++ b/drivers/net/cassini.c
@@ -2452,14 +2452,13 @@
struct net_device *dev = dev_id;
struct cas *cp = netdev_priv(dev);
unsigned long flags;
- int ring;
+ int ring = (irq == cp->pci_irq_INTC) ? 2 : 3;
u32 status = readl(cp->regs + REG_PLUS_INTRN_STATUS(ring));
/* check for shared irq */
if (status == 0)
return IRQ_NONE;
- ring = (irq == cp->pci_irq_INTC) ? 2 : 3;
spin_lock_irqsave(&cp->lock, flags);
if (status & INTR_RX_DONE_ALT) { /* handle rx separately */
#ifdef USE_NAPI
diff --git a/drivers/net/e1000e/e1000.h b/drivers/net/e1000e/e1000.h
index 35916f4..8533ad7 100644
--- a/drivers/net/e1000e/e1000.h
+++ b/drivers/net/e1000e/e1000.h
@@ -155,6 +155,9 @@
#define HV_M_STATUS_SPEED_1000 0x0200
#define HV_M_STATUS_LINK_UP 0x0040
+#define E1000_ICH_FWSM_PCIM2PCI 0x01000000 /* ME PCIm-to-PCI active */
+#define E1000_ICH_FWSM_PCIM2PCI_COUNT 2000
+
/* Time to wait before putting the device into D3 if there's no link (in ms). */
#define LINK_TIMEOUT 100
@@ -454,6 +457,7 @@
#define FLAG2_DISABLE_AIM (1 << 8)
#define FLAG2_CHECK_PHY_HANG (1 << 9)
#define FLAG2_NO_DISABLE_RX (1 << 10)
+#define FLAG2_PCIM2PCI_ARBITER_WA (1 << 11)
#define E1000_RX_DESC_PS(R, i) \
(&(((union e1000_rx_desc_packet_split *)((R).desc))[i]))
diff --git a/drivers/net/e1000e/ich8lan.c b/drivers/net/e1000e/ich8lan.c
index 4e36978..54add27 100644
--- a/drivers/net/e1000e/ich8lan.c
+++ b/drivers/net/e1000e/ich8lan.c
@@ -137,8 +137,9 @@
#define HV_PM_CTRL PHY_REG(770, 17)
/* PHY Low Power Idle Control */
-#define I82579_LPI_CTRL PHY_REG(772, 20)
-#define I82579_LPI_CTRL_ENABLE_MASK 0x6000
+#define I82579_LPI_CTRL PHY_REG(772, 20)
+#define I82579_LPI_CTRL_ENABLE_MASK 0x6000
+#define I82579_LPI_CTRL_FORCE_PLL_LOCK_COUNT 0x80
/* EMI Registers */
#define I82579_EMI_ADDR 0x10
@@ -163,6 +164,11 @@
#define HV_KMRN_MODE_CTRL PHY_REG(769, 16)
#define HV_KMRN_MDIO_SLOW 0x0400
+/* KMRN FIFO Control and Status */
+#define HV_KMRN_FIFO_CTRLSTA PHY_REG(770, 16)
+#define HV_KMRN_FIFO_CTRLSTA_PREAMBLE_MASK 0x7000
+#define HV_KMRN_FIFO_CTRLSTA_PREAMBLE_SHIFT 12
+
/* ICH GbE Flash Hardware Sequencing Flash Status Register bit breakdown */
/* Offset 04h HSFSTS */
union ich8_hws_flash_status {
@@ -657,6 +663,7 @@
struct e1000_mac_info *mac = &hw->mac;
s32 ret_val;
bool link;
+ u16 phy_reg;
/*
* We only want to go out to the PHY registers to see if Auto-Neg
@@ -689,16 +696,35 @@
mac->get_link_status = false;
- if (hw->phy.type == e1000_phy_82578) {
- ret_val = e1000_link_stall_workaround_hv(hw);
- if (ret_val)
- goto out;
- }
-
- if (hw->mac.type == e1000_pch2lan) {
+ switch (hw->mac.type) {
+ case e1000_pch2lan:
ret_val = e1000_k1_workaround_lv(hw);
if (ret_val)
goto out;
+ /* fall-thru */
+ case e1000_pchlan:
+ if (hw->phy.type == e1000_phy_82578) {
+ ret_val = e1000_link_stall_workaround_hv(hw);
+ if (ret_val)
+ goto out;
+ }
+
+ /*
+ * Workaround for PCHx parts in half-duplex:
+ * Set the number of preambles removed from the packet
+ * when it is passed from the PHY to the MAC to prevent
+ * the MAC from misinterpreting the packet type.
+ */
+ e1e_rphy(hw, HV_KMRN_FIFO_CTRLSTA, &phy_reg);
+ phy_reg &= ~HV_KMRN_FIFO_CTRLSTA_PREAMBLE_MASK;
+
+ if ((er32(STATUS) & E1000_STATUS_FD) != E1000_STATUS_FD)
+ phy_reg |= (1 << HV_KMRN_FIFO_CTRLSTA_PREAMBLE_SHIFT);
+
+ e1e_wphy(hw, HV_KMRN_FIFO_CTRLSTA, phy_reg);
+ break;
+ default:
+ break;
}
/*
@@ -788,6 +814,11 @@
(adapter->hw.phy.type == e1000_phy_igp_3))
adapter->flags |= FLAG_LSC_GIG_SPEED_DROP;
+ /* Enable workaround for 82579 w/ ME enabled */
+ if ((adapter->hw.mac.type == e1000_pch2lan) &&
+ (er32(FWSM) & E1000_ICH_FWSM_FW_VALID))
+ adapter->flags2 |= FLAG2_PCIM2PCI_ARBITER_WA;
+
/* Disable EEE by default until IEEE802.3az spec is finalized */
if (adapter->flags2 & FLAG2_HAS_EEE)
adapter->hw.dev_spec.ich8lan.eee_disable = true;
@@ -1355,7 +1386,7 @@
return ret_val;
/* Preamble tuning for SSC */
- ret_val = e1e_wphy(hw, PHY_REG(770, 16), 0xA204);
+ ret_val = e1e_wphy(hw, HV_KMRN_FIFO_CTRLSTA, 0xA204);
if (ret_val)
return ret_val;
}
@@ -1645,6 +1676,7 @@
s32 ret_val = 0;
u16 status_reg = 0;
u32 mac_reg;
+ u16 phy_reg;
if (hw->mac.type != e1000_pch2lan)
goto out;
@@ -1659,12 +1691,19 @@
mac_reg = er32(FEXTNVM4);
mac_reg &= ~E1000_FEXTNVM4_BEACON_DURATION_MASK;
- if (status_reg & HV_M_STATUS_SPEED_1000)
- mac_reg |= E1000_FEXTNVM4_BEACON_DURATION_8USEC;
- else
- mac_reg |= E1000_FEXTNVM4_BEACON_DURATION_16USEC;
+ ret_val = e1e_rphy(hw, I82579_LPI_CTRL, &phy_reg);
+ if (ret_val)
+ goto out;
+ if (status_reg & HV_M_STATUS_SPEED_1000) {
+ mac_reg |= E1000_FEXTNVM4_BEACON_DURATION_8USEC;
+ phy_reg &= ~I82579_LPI_CTRL_FORCE_PLL_LOCK_COUNT;
+ } else {
+ mac_reg |= E1000_FEXTNVM4_BEACON_DURATION_16USEC;
+ phy_reg |= I82579_LPI_CTRL_FORCE_PLL_LOCK_COUNT;
+ }
ew32(FEXTNVM4, mac_reg);
+ ret_val = e1e_wphy(hw, I82579_LPI_CTRL, phy_reg);
}
out:
diff --git a/drivers/net/e1000e/netdev.c b/drivers/net/e1000e/netdev.c
index 362f703..2198e61 100644
--- a/drivers/net/e1000e/netdev.c
+++ b/drivers/net/e1000e/netdev.c
@@ -519,6 +519,63 @@
}
/**
+ * e1000e_update_tail_wa - helper function for e1000e_update_[rt]dt_wa()
+ * @hw: pointer to the HW structure
+ * @tail: address of tail descriptor register
+ * @i: value to write to tail descriptor register
+ *
+ * When updating the tail register, the ME could be accessing Host CSR
+ * registers at the same time. Normally, this is handled in h/w by an
+ * arbiter but on some parts there is a bug that acknowledges Host accesses
+ * later than it should which could result in the descriptor register to
+ * have an incorrect value. Workaround this by checking the FWSM register
+ * which has bit 24 set while ME is accessing Host CSR registers, wait
+ * if it is set and try again a number of times.
+ **/
+static inline s32 e1000e_update_tail_wa(struct e1000_hw *hw, u8 __iomem * tail,
+ unsigned int i)
+{
+ unsigned int j = 0;
+
+ while ((j++ < E1000_ICH_FWSM_PCIM2PCI_COUNT) &&
+ (er32(FWSM) & E1000_ICH_FWSM_PCIM2PCI))
+ udelay(50);
+
+ writel(i, tail);
+
+ if ((j == E1000_ICH_FWSM_PCIM2PCI_COUNT) && (i != readl(tail)))
+ return E1000_ERR_SWFW_SYNC;
+
+ return 0;
+}
+
+static void e1000e_update_rdt_wa(struct e1000_adapter *adapter, unsigned int i)
+{
+ u8 __iomem *tail = (adapter->hw.hw_addr + adapter->rx_ring->tail);
+ struct e1000_hw *hw = &adapter->hw;
+
+ if (e1000e_update_tail_wa(hw, tail, i)) {
+ u32 rctl = er32(RCTL);
+ ew32(RCTL, rctl & ~E1000_RCTL_EN);
+ e_err("ME firmware caused invalid RDT - resetting\n");
+ schedule_work(&adapter->reset_task);
+ }
+}
+
+static void e1000e_update_tdt_wa(struct e1000_adapter *adapter, unsigned int i)
+{
+ u8 __iomem *tail = (adapter->hw.hw_addr + adapter->tx_ring->tail);
+ struct e1000_hw *hw = &adapter->hw;
+
+ if (e1000e_update_tail_wa(hw, tail, i)) {
+ u32 tctl = er32(TCTL);
+ ew32(TCTL, tctl & ~E1000_TCTL_EN);
+ e_err("ME firmware caused invalid TDT - resetting\n");
+ schedule_work(&adapter->reset_task);
+ }
+}
+
+/**
* e1000_alloc_rx_buffers - Replace used receive buffers; legacy & extended
* @adapter: address of board private structure
**/
@@ -573,7 +630,10 @@
* such as IA-64).
*/
wmb();
- writel(i, adapter->hw.hw_addr + rx_ring->tail);
+ if (adapter->flags2 & FLAG2_PCIM2PCI_ARBITER_WA)
+ e1000e_update_rdt_wa(adapter, i);
+ else
+ writel(i, adapter->hw.hw_addr + rx_ring->tail);
}
i++;
if (i == rx_ring->count)
@@ -673,7 +733,11 @@
* such as IA-64).
*/
wmb();
- writel(i << 1, adapter->hw.hw_addr + rx_ring->tail);
+ if (adapter->flags2 & FLAG2_PCIM2PCI_ARBITER_WA)
+ e1000e_update_rdt_wa(adapter, i << 1);
+ else
+ writel(i << 1,
+ adapter->hw.hw_addr + rx_ring->tail);
}
i++;
@@ -756,7 +820,10 @@
* applicable for weak-ordered memory model archs,
* such as IA-64). */
wmb();
- writel(i, adapter->hw.hw_addr + rx_ring->tail);
+ if (adapter->flags2 & FLAG2_PCIM2PCI_ARBITER_WA)
+ e1000e_update_rdt_wa(adapter, i);
+ else
+ writel(i, adapter->hw.hw_addr + rx_ring->tail);
}
}
@@ -4689,7 +4756,12 @@
wmb();
tx_ring->next_to_use = i;
- writel(i, adapter->hw.hw_addr + tx_ring->tail);
+
+ if (adapter->flags2 & FLAG2_PCIM2PCI_ARBITER_WA)
+ e1000e_update_tdt_wa(adapter, i);
+ else
+ writel(i, adapter->hw.hw_addr + tx_ring->tail);
+
/*
* we need this if more than one processor can write to our tail
* at a time, it synchronizes IO on IA64/Altix systems
diff --git a/drivers/net/forcedeth.c b/drivers/net/forcedeth.c
index e55df30..6d5fbd4 100644
--- a/drivers/net/forcedeth.c
+++ b/drivers/net/forcedeth.c
@@ -5615,7 +5615,8 @@
goto out_error;
}
- nv_vlan_mode(dev, dev->features);
+ if (id->driver_data & DEV_HAS_VLAN)
+ nv_vlan_mode(dev, dev->features);
netif_carrier_off(dev);
diff --git a/drivers/net/gianfar.c b/drivers/net/gianfar.c
index 2659daa..31d5c57 100644
--- a/drivers/net/gianfar.c
+++ b/drivers/net/gianfar.c
@@ -2710,8 +2710,13 @@
/* Tell the skb what kind of packet this is */
skb->protocol = eth_type_trans(skb, dev);
- /* Set vlan tag */
- if (fcb->flags & RXFCB_VLN)
+ /*
+ * There's need to check for NETIF_F_HW_VLAN_RX here.
+ * Even if vlan rx accel is disabled, on some chips
+ * RXFCB_VLN is pseudo randomly set.
+ */
+ if (dev->features & NETIF_F_HW_VLAN_RX &&
+ fcb->flags & RXFCB_VLN)
__vlan_hwaccel_put_tag(skb, fcb->vlctl);
/* Send the packet up the stack */
diff --git a/drivers/net/gianfar_ethtool.c b/drivers/net/gianfar_ethtool.c
index 6e35069..25a8c2a 100644
--- a/drivers/net/gianfar_ethtool.c
+++ b/drivers/net/gianfar_ethtool.c
@@ -686,10 +686,21 @@
{
unsigned int last_rule_idx = priv->cur_filer_idx;
unsigned int cmp_rqfpr;
- unsigned int local_rqfpr[MAX_FILER_IDX + 1];
- unsigned int local_rqfcr[MAX_FILER_IDX + 1];
+ unsigned int *local_rqfpr;
+ unsigned int *local_rqfcr;
int i = 0x0, k = 0x0;
int j = MAX_FILER_IDX, l = 0x0;
+ int ret = 1;
+
+ local_rqfpr = kmalloc(sizeof(unsigned int) * (MAX_FILER_IDX + 1),
+ GFP_KERNEL);
+ local_rqfcr = kmalloc(sizeof(unsigned int) * (MAX_FILER_IDX + 1),
+ GFP_KERNEL);
+ if (!local_rqfpr || !local_rqfcr) {
+ pr_err("Out of memory\n");
+ ret = 0;
+ goto err;
+ }
switch (class) {
case TCP_V4_FLOW:
@@ -706,7 +717,8 @@
break;
default:
pr_err("Right now this class is not supported\n");
- return 0;
+ ret = 0;
+ goto err;
}
for (i = 0; i < MAX_FILER_IDX + 1; i++) {
@@ -721,7 +733,8 @@
if (i == MAX_FILER_IDX + 1) {
pr_err("No parse rule found, can't create hash rules\n");
- return 0;
+ ret = 0;
+ goto err;
}
/* If a match was found, then it begins the starting of a cluster rule
@@ -765,7 +778,10 @@
priv->cur_filer_idx = priv->cur_filer_idx - 1;
}
- return 1;
+err:
+ kfree(local_rqfcr);
+ kfree(local_rqfpr);
+ return ret;
}
static int gfar_set_hash_opts(struct gfar_private *priv, struct ethtool_rxnfc *cmd)
diff --git a/drivers/net/ibmveth.c b/drivers/net/ibmveth.c
index ba99af0..3e66792 100644
--- a/drivers/net/ibmveth.c
+++ b/drivers/net/ibmveth.c
@@ -395,7 +395,7 @@
}
/* recycle the current buffer on the rx queue */
-static void ibmveth_rxq_recycle_buffer(struct ibmveth_adapter *adapter)
+static int ibmveth_rxq_recycle_buffer(struct ibmveth_adapter *adapter)
{
u32 q_index = adapter->rx_queue.index;
u64 correlator = adapter->rx_queue.queue_addr[q_index].correlator;
@@ -403,6 +403,7 @@
unsigned int index = correlator & 0xffffffffUL;
union ibmveth_buf_desc desc;
unsigned long lpar_rc;
+ int ret = 1;
BUG_ON(pool >= IBMVETH_NUM_BUFF_POOLS);
BUG_ON(index >= adapter->rx_buff_pool[pool].size);
@@ -410,7 +411,7 @@
if (!adapter->rx_buff_pool[pool].active) {
ibmveth_rxq_harvest_buffer(adapter);
ibmveth_free_buffer_pool(adapter, &adapter->rx_buff_pool[pool]);
- return;
+ goto out;
}
desc.fields.flags_len = IBMVETH_BUF_VALID |
@@ -423,12 +424,16 @@
netdev_dbg(adapter->netdev, "h_add_logical_lan_buffer failed "
"during recycle rc=%ld", lpar_rc);
ibmveth_remove_buffer_from_pool(adapter, adapter->rx_queue.queue_addr[adapter->rx_queue.index].correlator);
+ ret = 0;
}
if (++adapter->rx_queue.index == adapter->rx_queue.num_slots) {
adapter->rx_queue.index = 0;
adapter->rx_queue.toggle = !adapter->rx_queue.toggle;
}
+
+out:
+ return ret;
}
static void ibmveth_rxq_harvest_buffer(struct ibmveth_adapter *adapter)
@@ -1084,8 +1089,9 @@
if (rx_flush)
ibmveth_flush_buffer(skb->data,
length + offset);
+ if (!ibmveth_rxq_recycle_buffer(adapter))
+ kfree_skb(skb);
skb = new_skb;
- ibmveth_rxq_recycle_buffer(adapter);
} else {
ibmveth_rxq_harvest_buffer(adapter);
skb_reserve(skb, offset);
diff --git a/drivers/net/ixgbe/ixgbe_main.c b/drivers/net/ixgbe/ixgbe_main.c
index e86297b..2279039 100644
--- a/drivers/net/ixgbe/ixgbe_main.c
+++ b/drivers/net/ixgbe/ixgbe_main.c
@@ -1459,8 +1459,10 @@
if (ixgbe_rx_is_fcoe(adapter, rx_desc)) {
ddp_bytes = ixgbe_fcoe_ddp(adapter, rx_desc, skb,
staterr);
- if (!ddp_bytes)
+ if (!ddp_bytes) {
+ dev_kfree_skb_any(skb);
goto next_desc;
+ }
}
#endif /* IXGBE_FCOE */
ixgbe_receive_skb(q_vector, skb, staterr, rx_ring, rx_desc);
diff --git a/drivers/net/phy/national.c b/drivers/net/phy/national.c
index 0620ba9..04bb8fc 100644
--- a/drivers/net/phy/national.c
+++ b/drivers/net/phy/national.c
@@ -25,8 +25,9 @@
/* DP83865 phy identifier values */
#define DP83865_PHY_ID 0x20005c7a
-#define DP83865_INT_MASK_REG 0x15
-#define DP83865_INT_MASK_STATUS 0x14
+#define DP83865_INT_STATUS 0x14
+#define DP83865_INT_MASK 0x15
+#define DP83865_INT_CLEAR 0x17
#define DP83865_INT_REMOTE_FAULT 0x0008
#define DP83865_INT_ANE_COMPLETED 0x0010
@@ -68,21 +69,25 @@
int err;
if (phydev->interrupts == PHY_INTERRUPT_ENABLED)
- err = phy_write(phydev, DP83865_INT_MASK_REG,
+ err = phy_write(phydev, DP83865_INT_MASK,
DP83865_INT_MASK_DEFAULT);
else
- err = phy_write(phydev, DP83865_INT_MASK_REG, 0);
+ err = phy_write(phydev, DP83865_INT_MASK, 0);
return err;
}
static int ns_ack_interrupt(struct phy_device *phydev)
{
- int ret = phy_read(phydev, DP83865_INT_MASK_STATUS);
+ int ret = phy_read(phydev, DP83865_INT_STATUS);
if (ret < 0)
return ret;
- return 0;
+ /* Clear the interrupt status bit by writing a “1”
+ * to the corresponding bit in INT_CLEAR (2:0 are reserved) */
+ ret = phy_write(phydev, DP83865_INT_CLEAR, ret & ~0x7);
+
+ return ret;
}
static void ns_giga_speed_fallback(struct phy_device *phydev, int mode)
diff --git a/drivers/net/rionet.c b/drivers/net/rionet.c
index 86ac38c..3bb1311 100644
--- a/drivers/net/rionet.c
+++ b/drivers/net/rionet.c
@@ -80,13 +80,13 @@
*/
static struct rio_dev **rionet_active;
-#define is_rionet_capable(pef, src_ops, dst_ops) \
- ((pef & RIO_PEF_INB_MBOX) && \
- (pef & RIO_PEF_INB_DOORBELL) && \
+#define is_rionet_capable(src_ops, dst_ops) \
+ ((src_ops & RIO_SRC_OPS_DATA_MSG) && \
+ (dst_ops & RIO_DST_OPS_DATA_MSG) && \
(src_ops & RIO_SRC_OPS_DOORBELL) && \
(dst_ops & RIO_DST_OPS_DOORBELL))
#define dev_rionet_capable(dev) \
- is_rionet_capable(dev->pef, dev->src_ops, dev->dst_ops)
+ is_rionet_capable(dev->src_ops, dev->dst_ops)
#define RIONET_MAC_MATCH(x) (*(u32 *)x == 0x00010001)
#define RIONET_GET_DESTID(x) (*(u16 *)(x + 4))
@@ -282,7 +282,6 @@
{
int i, rc = 0;
struct rionet_peer *peer, *tmp;
- u32 pwdcsr;
struct rionet_private *rnet = netdev_priv(ndev);
if (netif_msg_ifup(rnet))
@@ -332,13 +331,8 @@
continue;
}
- /*
- * If device has initialized inbound doorbells,
- * send a join message
- */
- rio_read_config_32(peer->rdev, RIO_WRITE_PORT_CSR, &pwdcsr);
- if (pwdcsr & RIO_DOORBELL_AVAIL)
- rio_send_doorbell(peer->rdev, RIONET_DOORBELL_JOIN);
+ /* Send a join message */
+ rio_send_doorbell(peer->rdev, RIONET_DOORBELL_JOIN);
}
out:
@@ -492,7 +486,7 @@
static int rionet_probe(struct rio_dev *rdev, const struct rio_device_id *id)
{
int rc = -ENODEV;
- u32 lpef, lsrc_ops, ldst_ops;
+ u32 lsrc_ops, ldst_ops;
struct rionet_peer *peer;
struct net_device *ndev = NULL;
@@ -515,12 +509,11 @@
* on later probes
*/
if (!rionet_check) {
- rio_local_read_config_32(rdev->net->hport, RIO_PEF_CAR, &lpef);
rio_local_read_config_32(rdev->net->hport, RIO_SRC_OPS_CAR,
&lsrc_ops);
rio_local_read_config_32(rdev->net->hport, RIO_DST_OPS_CAR,
&ldst_ops);
- if (!is_rionet_capable(lpef, lsrc_ops, ldst_ops)) {
+ if (!is_rionet_capable(lsrc_ops, ldst_ops)) {
printk(KERN_ERR
"%s: local device is not network capable\n",
DRV_NAME);
diff --git a/drivers/net/sh_eth.c b/drivers/net/sh_eth.c
index ad35c21..1c1666e 100644
--- a/drivers/net/sh_eth.c
+++ b/drivers/net/sh_eth.c
@@ -21,6 +21,7 @@
*/
#include <linux/init.h>
+#include <linux/interrupt.h>
#include <linux/dma-mapping.h>
#include <linux/etherdevice.h>
#include <linux/delay.h>
@@ -30,6 +31,7 @@
#include <linux/phy.h>
#include <linux/cache.h>
#include <linux/io.h>
+#include <linux/interrupt.h>
#include <linux/pm_runtime.h>
#include <linux/slab.h>
#include <linux/ethtool.h>
diff --git a/drivers/net/usb/cdc_ncm.c b/drivers/net/usb/cdc_ncm.c
index a03336e0..f06fb78 100644
--- a/drivers/net/usb/cdc_ncm.c
+++ b/drivers/net/usb/cdc_ncm.c
@@ -228,23 +228,40 @@
if (ctx->rx_max != le32_to_cpu(ctx->ncm_parm.dwNtbInMaxSize)) {
if (flags & USB_CDC_NCM_NCAP_NTB_INPUT_SIZE) {
- struct usb_cdc_ncm_ndp_input_size ndp_in_sz;
- err = usb_control_msg(ctx->udev,
- usb_sndctrlpipe(ctx->udev, 0),
- USB_CDC_SET_NTB_INPUT_SIZE,
- USB_TYPE_CLASS | USB_DIR_OUT
- | USB_RECIP_INTERFACE,
- 0, iface_no, &ndp_in_sz, 8, 1000);
- } else {
- __le32 dwNtbInMaxSize = cpu_to_le32(ctx->rx_max);
- err = usb_control_msg(ctx->udev,
- usb_sndctrlpipe(ctx->udev, 0),
- USB_CDC_SET_NTB_INPUT_SIZE,
- USB_TYPE_CLASS | USB_DIR_OUT
- | USB_RECIP_INTERFACE,
- 0, iface_no, &dwNtbInMaxSize, 4, 1000);
- }
+ struct usb_cdc_ncm_ndp_input_size *ndp_in_sz;
+ ndp_in_sz = kzalloc(sizeof(*ndp_in_sz), GFP_KERNEL);
+ if (!ndp_in_sz) {
+ err = -ENOMEM;
+ goto size_err;
+ }
+
+ err = usb_control_msg(ctx->udev,
+ usb_sndctrlpipe(ctx->udev, 0),
+ USB_CDC_SET_NTB_INPUT_SIZE,
+ USB_TYPE_CLASS | USB_DIR_OUT
+ | USB_RECIP_INTERFACE,
+ 0, iface_no, ndp_in_sz, 8, 1000);
+ kfree(ndp_in_sz);
+ } else {
+ __le32 *dwNtbInMaxSize;
+ dwNtbInMaxSize = kzalloc(sizeof(*dwNtbInMaxSize),
+ GFP_KERNEL);
+ if (!dwNtbInMaxSize) {
+ err = -ENOMEM;
+ goto size_err;
+ }
+ *dwNtbInMaxSize = cpu_to_le32(ctx->rx_max);
+
+ err = usb_control_msg(ctx->udev,
+ usb_sndctrlpipe(ctx->udev, 0),
+ USB_CDC_SET_NTB_INPUT_SIZE,
+ USB_TYPE_CLASS | USB_DIR_OUT
+ | USB_RECIP_INTERFACE,
+ 0, iface_no, dwNtbInMaxSize, 4, 1000);
+ kfree(dwNtbInMaxSize);
+ }
+size_err:
if (err < 0)
pr_debug("Setting NTB Input Size failed\n");
}
@@ -325,19 +342,29 @@
/* set Max Datagram Size (MTU) */
if (flags & USB_CDC_NCM_NCAP_MAX_DATAGRAM_SIZE) {
- __le16 max_datagram_size;
+ __le16 *max_datagram_size;
u16 eth_max_sz = le16_to_cpu(ctx->ether_desc->wMaxSegmentSize);
+
+ max_datagram_size = kzalloc(sizeof(*max_datagram_size),
+ GFP_KERNEL);
+ if (!max_datagram_size) {
+ err = -ENOMEM;
+ goto max_dgram_err;
+ }
+
err = usb_control_msg(ctx->udev, usb_rcvctrlpipe(ctx->udev, 0),
USB_CDC_GET_MAX_DATAGRAM_SIZE,
USB_TYPE_CLASS | USB_DIR_IN
| USB_RECIP_INTERFACE,
- 0, iface_no, &max_datagram_size,
+ 0, iface_no, max_datagram_size,
2, 1000);
if (err < 0) {
pr_debug("GET_MAX_DATAGRAM_SIZE failed, use size=%u\n",
CDC_NCM_MIN_DATAGRAM_SIZE);
+ kfree(max_datagram_size);
} else {
- ctx->max_datagram_size = le16_to_cpu(max_datagram_size);
+ ctx->max_datagram_size =
+ le16_to_cpu(*max_datagram_size);
/* Check Eth descriptor value */
if (eth_max_sz < CDC_NCM_MAX_DATAGRAM_SIZE) {
if (ctx->max_datagram_size > eth_max_sz)
@@ -360,8 +387,10 @@
USB_TYPE_CLASS | USB_DIR_OUT
| USB_RECIP_INTERFACE,
0,
- iface_no, &max_datagram_size,
+ iface_no, max_datagram_size,
2, 1000);
+ kfree(max_datagram_size);
+max_dgram_err:
if (err < 0)
pr_debug("SET_MAX_DATAGRAM_SIZE failed\n");
}
diff --git a/drivers/net/via-velocity.c b/drivers/net/via-velocity.c
index deb1eca..7c5336c 100644
--- a/drivers/net/via-velocity.c
+++ b/drivers/net/via-velocity.c
@@ -515,10 +515,6 @@
mac_set_cam_mask(regs, vptr->mCAMmask);
/* Enable VCAMs */
-
- if (test_bit(0, vptr->active_vlans))
- WORD_REG_BITS_ON(MCFG_RTGOPT, ®s->MCFG);
-
for_each_set_bit(vid, vptr->active_vlans, VLAN_N_VID) {
mac_set_vlan_cam(regs, i, (u8 *) &vid);
vptr->vCAMmask[i / 8] |= 0x1 << (i % 8);
diff --git a/drivers/net/vmxnet3/vmxnet3_drv.c b/drivers/net/vmxnet3/vmxnet3_drv.c
index 1cbacb3..0959583 100644
--- a/drivers/net/vmxnet3/vmxnet3_drv.c
+++ b/drivers/net/vmxnet3/vmxnet3_drv.c
@@ -1929,14 +1929,17 @@
vmxnet3_vlan_rx_add_vid(struct net_device *netdev, u16 vid)
{
struct vmxnet3_adapter *adapter = netdev_priv(netdev);
- u32 *vfTable = adapter->shared->devRead.rxFilterConf.vfTable;
- unsigned long flags;
- VMXNET3_SET_VFTABLE_ENTRY(vfTable, vid);
- spin_lock_irqsave(&adapter->cmd_lock, flags);
- VMXNET3_WRITE_BAR1_REG(adapter, VMXNET3_REG_CMD,
- VMXNET3_CMD_UPDATE_VLAN_FILTERS);
- spin_unlock_irqrestore(&adapter->cmd_lock, flags);
+ if (!(netdev->flags & IFF_PROMISC)) {
+ u32 *vfTable = adapter->shared->devRead.rxFilterConf.vfTable;
+ unsigned long flags;
+
+ VMXNET3_SET_VFTABLE_ENTRY(vfTable, vid);
+ spin_lock_irqsave(&adapter->cmd_lock, flags);
+ VMXNET3_WRITE_BAR1_REG(adapter, VMXNET3_REG_CMD,
+ VMXNET3_CMD_UPDATE_VLAN_FILTERS);
+ spin_unlock_irqrestore(&adapter->cmd_lock, flags);
+ }
set_bit(vid, adapter->active_vlans);
}
@@ -1946,14 +1949,17 @@
vmxnet3_vlan_rx_kill_vid(struct net_device *netdev, u16 vid)
{
struct vmxnet3_adapter *adapter = netdev_priv(netdev);
- u32 *vfTable = adapter->shared->devRead.rxFilterConf.vfTable;
- unsigned long flags;
- VMXNET3_CLEAR_VFTABLE_ENTRY(vfTable, vid);
- spin_lock_irqsave(&adapter->cmd_lock, flags);
- VMXNET3_WRITE_BAR1_REG(adapter, VMXNET3_REG_CMD,
- VMXNET3_CMD_UPDATE_VLAN_FILTERS);
- spin_unlock_irqrestore(&adapter->cmd_lock, flags);
+ if (!(netdev->flags & IFF_PROMISC)) {
+ u32 *vfTable = adapter->shared->devRead.rxFilterConf.vfTable;
+ unsigned long flags;
+
+ VMXNET3_CLEAR_VFTABLE_ENTRY(vfTable, vid);
+ spin_lock_irqsave(&adapter->cmd_lock, flags);
+ VMXNET3_WRITE_BAR1_REG(adapter, VMXNET3_REG_CMD,
+ VMXNET3_CMD_UPDATE_VLAN_FILTERS);
+ spin_unlock_irqrestore(&adapter->cmd_lock, flags);
+ }
clear_bit(vid, adapter->active_vlans);
}
diff --git a/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c b/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c
index c34bef1..1b94003 100644
--- a/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c
+++ b/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c
@@ -69,7 +69,7 @@
static const struct ar9300_eeprom ar9300_default = {
.eepromVersion = 2,
.templateVersion = 2,
- .macAddr = {1, 2, 3, 4, 5, 6},
+ .macAddr = {0, 2, 3, 4, 5, 6},
.custData = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
.baseEepHeader = {
diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c
index 9098aaa..6530694 100644
--- a/drivers/net/wireless/ath/ath9k/main.c
+++ b/drivers/net/wireless/ath/ath9k/main.c
@@ -2283,7 +2283,11 @@
mutex_lock(&sc->mutex);
ah->coverage_class = coverage_class;
+
+ ath9k_ps_wakeup(sc);
ath9k_hw_init_global_settings(ah);
+ ath9k_ps_restore(sc);
+
mutex_unlock(&sc->mutex);
}
diff --git a/drivers/net/wireless/ath/carl9170/main.c b/drivers/net/wireless/ath/carl9170/main.c
index 0122930..0474e663 100644
--- a/drivers/net/wireless/ath/carl9170/main.c
+++ b/drivers/net/wireless/ath/carl9170/main.c
@@ -1066,8 +1066,10 @@
* the high througput speed in 802.11n networks.
*/
- if (!is_main_vif(ar, vif))
+ if (!is_main_vif(ar, vif)) {
+ mutex_lock(&ar->mutex);
goto err_softw;
+ }
/*
* While the hardware supports *catch-all* key, for offloading
diff --git a/drivers/net/wireless/iwlwifi/iwl-pci.c b/drivers/net/wireless/iwlwifi/iwl-pci.c
index 69d4ec4..2fdbffa 100644
--- a/drivers/net/wireless/iwlwifi/iwl-pci.c
+++ b/drivers/net/wireless/iwlwifi/iwl-pci.c
@@ -478,27 +478,22 @@
return err;
}
-static void iwl_pci_down(struct iwl_bus *bus)
-{
- struct iwl_pci_bus *pci_bus = (struct iwl_pci_bus *) bus->bus_specific;
-
- pci_disable_msi(pci_bus->pci_dev);
- pci_iounmap(pci_bus->pci_dev, pci_bus->hw_base);
- pci_release_regions(pci_bus->pci_dev);
- pci_disable_device(pci_bus->pci_dev);
- pci_set_drvdata(pci_bus->pci_dev, NULL);
-
- kfree(bus);
-}
-
static void __devexit iwl_pci_remove(struct pci_dev *pdev)
{
struct iwl_priv *priv = pci_get_drvdata(pdev);
- void *bus_specific = priv->bus->bus_specific;
+ struct iwl_bus *bus = priv->bus;
+ struct iwl_pci_bus *pci_bus = IWL_BUS_GET_PCI_BUS(bus);
+ struct pci_dev *pci_dev = IWL_BUS_GET_PCI_DEV(bus);
iwl_remove(priv);
- iwl_pci_down(bus_specific);
+ pci_disable_msi(pci_dev);
+ pci_iounmap(pci_dev, pci_bus->hw_base);
+ pci_release_regions(pci_dev);
+ pci_disable_device(pci_dev);
+ pci_set_drvdata(pci_dev, NULL);
+
+ kfree(bus);
}
#ifdef CONFIG_PM
diff --git a/drivers/net/wireless/rt2x00/rt2800usb.c b/drivers/net/wireless/rt2x00/rt2800usb.c
index 9395631..dbf501c 100644
--- a/drivers/net/wireless/rt2x00/rt2800usb.c
+++ b/drivers/net/wireless/rt2x00/rt2800usb.c
@@ -464,6 +464,15 @@
int wcid, ack, pid;
int tx_wcid, tx_ack, tx_pid;
+ if (test_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags) ||
+ !test_bit(ENTRY_DATA_STATUS_PENDING, &entry->flags)) {
+ WARNING(entry->queue->rt2x00dev,
+ "Data pending for entry %u in queue %u\n",
+ entry->entry_idx, entry->queue->qid);
+ cond_resched();
+ return false;
+ }
+
wcid = rt2x00_get_field32(reg, TX_STA_FIFO_WCID);
ack = rt2x00_get_field32(reg, TX_STA_FIFO_TX_ACK_REQUIRED);
pid = rt2x00_get_field32(reg, TX_STA_FIFO_PID_TYPE);
@@ -529,12 +538,11 @@
entry = rt2x00queue_get_entry(queue, Q_INDEX_DONE);
if (rt2800usb_txdone_entry_check(entry, reg))
break;
+ entry = NULL;
}
- if (!entry || rt2x00queue_empty(queue))
- break;
-
- rt2800_txdone_entry(entry, reg);
+ if (entry)
+ rt2800_txdone_entry(entry, reg);
}
}
@@ -558,8 +566,10 @@
while (!rt2x00queue_empty(queue)) {
entry = rt2x00queue_get_entry(queue, Q_INDEX_DONE);
- if (test_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags))
+ if (test_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags) ||
+ !test_bit(ENTRY_DATA_STATUS_PENDING, &entry->flags))
break;
+
if (test_bit(ENTRY_DATA_IO_FAILED, &entry->flags))
rt2x00lib_txdone_noinfo(entry, TXDONE_FAILURE);
else if (rt2x00queue_status_timeout(entry))
diff --git a/drivers/net/wireless/rt2x00/rt2x00usb.c b/drivers/net/wireless/rt2x00/rt2x00usb.c
index b6b4542..1e31050 100644
--- a/drivers/net/wireless/rt2x00/rt2x00usb.c
+++ b/drivers/net/wireless/rt2x00/rt2x00usb.c
@@ -262,23 +262,20 @@
struct queue_entry *entry = (struct queue_entry *)urb->context;
struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev;
- if (!test_and_clear_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags))
+ if (!test_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags))
return;
-
- if (rt2x00dev->ops->lib->tx_dma_done)
- rt2x00dev->ops->lib->tx_dma_done(entry);
-
- /*
- * Report the frame as DMA done
- */
- rt2x00lib_dmadone(entry);
-
/*
* Check if the frame was correctly uploaded
*/
if (urb->status)
set_bit(ENTRY_DATA_IO_FAILED, &entry->flags);
+ /*
+ * Report the frame as DMA done
+ */
+ rt2x00lib_dmadone(entry);
+ if (rt2x00dev->ops->lib->tx_dma_done)
+ rt2x00dev->ops->lib->tx_dma_done(entry);
/*
* Schedule the delayed work for reading the TX status
* from the device.
@@ -874,18 +871,8 @@
{
struct ieee80211_hw *hw = usb_get_intfdata(usb_intf);
struct rt2x00_dev *rt2x00dev = hw->priv;
- int retval;
- retval = rt2x00lib_suspend(rt2x00dev, state);
- if (retval)
- return retval;
-
- /*
- * Decrease usbdev refcount.
- */
- usb_put_dev(interface_to_usbdev(usb_intf));
-
- return 0;
+ return rt2x00lib_suspend(rt2x00dev, state);
}
EXPORT_SYMBOL_GPL(rt2x00usb_suspend);
@@ -894,8 +881,6 @@
struct ieee80211_hw *hw = usb_get_intfdata(usb_intf);
struct rt2x00_dev *rt2x00dev = hw->priv;
- usb_get_dev(interface_to_usbdev(usb_intf));
-
return rt2x00lib_resume(rt2x00dev);
}
EXPORT_SYMBOL_GPL(rt2x00usb_resume);
diff --git a/drivers/net/wireless/wl12xx/acx.c b/drivers/net/wireless/wl12xx/acx.c
index 7e33f1f..34f6ab5 100644
--- a/drivers/net/wireless/wl12xx/acx.c
+++ b/drivers/net/wireless/wl12xx/acx.c
@@ -77,8 +77,6 @@
auth->sleep_auth = sleep_auth;
ret = wl1271_cmd_configure(wl, ACX_SLEEP_AUTH, auth, sizeof(*auth));
- if (ret < 0)
- return ret;
out:
kfree(auth);
@@ -624,10 +622,8 @@
ret = wl1271_cmd_configure(wl, ACX_CCA_THRESHOLD,
detection, sizeof(*detection));
- if (ret < 0) {
+ if (ret < 0)
wl1271_warning("failed to set cca threshold: %d", ret);
- return ret;
- }
out:
kfree(detection);
diff --git a/drivers/net/wireless/wl12xx/main.c b/drivers/net/wireless/wl12xx/main.c
index e58c22d..b70ae40 100644
--- a/drivers/net/wireless/wl12xx/main.c
+++ b/drivers/net/wireless/wl12xx/main.c
@@ -4283,6 +4283,7 @@
wl->hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
BIT(NL80211_IFTYPE_ADHOC) | BIT(NL80211_IFTYPE_AP);
wl->hw->wiphy->max_scan_ssids = 1;
+ wl->hw->wiphy->max_sched_scan_ssids = 1;
/*
* Maximum length of elements in scanning probe request templates
* should be the maximum length possible for a template, without
diff --git a/drivers/net/wireless/wl12xx/sdio.c b/drivers/net/wireless/wl12xx/sdio.c
index 5cf18c2..fb1fd5a 100644
--- a/drivers/net/wireless/wl12xx/sdio.c
+++ b/drivers/net/wireless/wl12xx/sdio.c
@@ -164,7 +164,7 @@
/* If enabled, tell runtime PM not to power off the card */
if (pm_runtime_enabled(&func->dev)) {
ret = pm_runtime_get_sync(&func->dev);
- if (ret)
+ if (ret < 0)
goto out;
} else {
/* Runtime PM is disabled: power up the card manually */
diff --git a/drivers/net/wireless/wl12xx/testmode.c b/drivers/net/wireless/wl12xx/testmode.c
index 5d5e1ef..4ae8eff 100644
--- a/drivers/net/wireless/wl12xx/testmode.c
+++ b/drivers/net/wireless/wl12xx/testmode.c
@@ -36,7 +36,6 @@
WL1271_TM_CMD_TEST,
WL1271_TM_CMD_INTERROGATE,
WL1271_TM_CMD_CONFIGURE,
- WL1271_TM_CMD_NVS_PUSH,
WL1271_TM_CMD_SET_PLT_MODE,
WL1271_TM_CMD_RECOVER,
@@ -139,12 +138,15 @@
if (ret < 0) {
wl1271_warning("testmode cmd interrogate failed: %d", ret);
+ kfree(cmd);
return ret;
}
skb = cfg80211_testmode_alloc_reply_skb(wl->hw->wiphy, sizeof(*cmd));
- if (!skb)
+ if (!skb) {
+ kfree(cmd);
return -ENOMEM;
+ }
NLA_PUT(skb, WL1271_TM_ATTR_DATA, sizeof(*cmd), cmd);
@@ -187,48 +189,6 @@
return 0;
}
-static int wl1271_tm_cmd_nvs_push(struct wl1271 *wl, struct nlattr *tb[])
-{
- int ret = 0;
- size_t len;
- void *buf;
-
- wl1271_debug(DEBUG_TESTMODE, "testmode cmd nvs push");
-
- if (!tb[WL1271_TM_ATTR_DATA])
- return -EINVAL;
-
- buf = nla_data(tb[WL1271_TM_ATTR_DATA]);
- len = nla_len(tb[WL1271_TM_ATTR_DATA]);
-
- mutex_lock(&wl->mutex);
-
- kfree(wl->nvs);
-
- if ((wl->chip.id == CHIP_ID_1283_PG20) &&
- (len != sizeof(struct wl128x_nvs_file)))
- return -EINVAL;
- else if (len != sizeof(struct wl1271_nvs_file))
- return -EINVAL;
-
- wl->nvs = kzalloc(len, GFP_KERNEL);
- if (!wl->nvs) {
- wl1271_error("could not allocate memory for the nvs file");
- ret = -ENOMEM;
- goto out;
- }
-
- memcpy(wl->nvs, buf, len);
- wl->nvs_len = len;
-
- wl1271_debug(DEBUG_TESTMODE, "testmode pushed nvs");
-
-out:
- mutex_unlock(&wl->mutex);
-
- return ret;
-}
-
static int wl1271_tm_cmd_set_plt_mode(struct wl1271 *wl, struct nlattr *tb[])
{
u32 val;
@@ -285,8 +245,6 @@
return wl1271_tm_cmd_interrogate(wl, tb);
case WL1271_TM_CMD_CONFIGURE:
return wl1271_tm_cmd_configure(wl, tb);
- case WL1271_TM_CMD_NVS_PUSH:
- return wl1271_tm_cmd_nvs_push(wl, tb);
case WL1271_TM_CMD_SET_PLT_MODE:
return wl1271_tm_cmd_set_plt_mode(wl, tb);
case WL1271_TM_CMD_RECOVER:
diff --git a/drivers/pci/hotplug/pcihp_slot.c b/drivers/pci/hotplug/pcihp_slot.c
index 753b21a..3ffd9c1a 100644
--- a/drivers/pci/hotplug/pcihp_slot.c
+++ b/drivers/pci/hotplug/pcihp_slot.c
@@ -169,7 +169,9 @@
(dev->class >> 8) == PCI_CLASS_BRIDGE_PCI)))
return;
- pcie_bus_configure_settings(dev->bus, dev->bus->self->pcie_mpss);
+ if (dev->bus && dev->bus->self)
+ pcie_bus_configure_settings(dev->bus,
+ dev->bus->self->pcie_mpss);
memset(&hpp, 0, sizeof(hpp));
ret = pci_get_hp_params(dev, &hpp);
diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
index 0ce6742..4e84fd4 100644
--- a/drivers/pci/pci.c
+++ b/drivers/pci/pci.c
@@ -77,7 +77,7 @@
unsigned long pci_hotplug_io_size = DEFAULT_HOTPLUG_IO_SIZE;
unsigned long pci_hotplug_mem_size = DEFAULT_HOTPLUG_MEM_SIZE;
-enum pcie_bus_config_types pcie_bus_config = PCIE_BUS_PERFORMANCE;
+enum pcie_bus_config_types pcie_bus_config = PCIE_BUS_SAFE;
/*
* The default CLS is used if arch didn't set CLS explicitly and not
diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c
index 8473727..b1187ff 100644
--- a/drivers/pci/probe.c
+++ b/drivers/pci/probe.c
@@ -1396,34 +1396,37 @@
static void pcie_write_mrrs(struct pci_dev *dev, int mps)
{
- int rc, mrrs;
+ int rc, mrrs, dev_mpss;
- if (pcie_bus_config == PCIE_BUS_PERFORMANCE) {
- int dev_mpss = 128 << dev->pcie_mpss;
+ /* In the "safe" case, do not configure the MRRS. There appear to be
+ * issues with setting MRRS to 0 on a number of devices.
+ */
- /* For Max performance, the MRRS must be set to the largest
- * supported value. However, it cannot be configured larger
- * than the MPS the device or the bus can support. This assumes
- * that the largest MRRS available on the device cannot be
- * smaller than the device MPSS.
- */
- mrrs = mps < dev_mpss ? mps : dev_mpss;
- } else
- /* In the "safe" case, configure the MRRS for fairness on the
- * bus by making all devices have the same size
- */
- mrrs = mps;
+ if (pcie_bus_config != PCIE_BUS_PERFORMANCE)
+ return;
+ dev_mpss = 128 << dev->pcie_mpss;
+
+ /* For Max performance, the MRRS must be set to the largest supported
+ * value. However, it cannot be configured larger than the MPS the
+ * device or the bus can support. This assumes that the largest MRRS
+ * available on the device cannot be smaller than the device MPSS.
+ */
+ mrrs = min(mps, dev_mpss);
/* MRRS is a R/W register. Invalid values can be written, but a
- * subsiquent read will verify if the value is acceptable or not.
+ * subsequent read will verify if the value is acceptable or not.
* If the MRRS value provided is not acceptable (e.g., too large),
* shrink the value until it is acceptable to the HW.
*/
while (mrrs != pcie_get_readrq(dev) && mrrs >= 128) {
+ dev_warn(&dev->dev, "Attempting to modify the PCI-E MRRS value"
+ " to %d. If any issues are encountered, please try "
+ "running with pci=pcie_bus_safe\n", mrrs);
rc = pcie_set_readrq(dev, mrrs);
if (rc)
- dev_err(&dev->dev, "Failed attempting to set the MRRS\n");
+ dev_err(&dev->dev,
+ "Failed attempting to set the MRRS\n");
mrrs /= 2;
}
@@ -1436,13 +1439,13 @@
if (!pci_is_pcie(dev))
return 0;
- dev_info(&dev->dev, "Dev MPS %d MPSS %d MRRS %d\n",
+ dev_dbg(&dev->dev, "Dev MPS %d MPSS %d MRRS %d\n",
pcie_get_mps(dev), 128<<dev->pcie_mpss, pcie_get_readrq(dev));
pcie_write_mps(dev, mps);
pcie_write_mrrs(dev, mps);
- dev_info(&dev->dev, "Dev MPS %d MPSS %d MRRS %d\n",
+ dev_dbg(&dev->dev, "Dev MPS %d MPSS %d MRRS %d\n",
pcie_get_mps(dev), 128<<dev->pcie_mpss, pcie_get_readrq(dev));
return 0;
@@ -1456,9 +1459,6 @@
{
u8 smpss = mpss;
- if (!bus->self)
- return;
-
if (!pci_is_pcie(bus->self))
return;
diff --git a/drivers/power/max8997_charger.c b/drivers/power/max8997_charger.c
index 7106b49..ffc5033 100644
--- a/drivers/power/max8997_charger.c
+++ b/drivers/power/max8997_charger.c
@@ -20,6 +20,7 @@
*/
#include <linux/err.h>
+#include <linux/module.h>
#include <linux/slab.h>
#include <linux/platform_device.h>
#include <linux/power_supply.h>
diff --git a/drivers/power/max8998_charger.c b/drivers/power/max8998_charger.c
index cc21fa2..ef8efad 100644
--- a/drivers/power/max8998_charger.c
+++ b/drivers/power/max8998_charger.c
@@ -20,6 +20,7 @@
*/
#include <linux/err.h>
+#include <linux/module.h>
#include <linux/slab.h>
#include <linux/platform_device.h>
#include <linux/power_supply.h>
diff --git a/drivers/power/s3c_adc_battery.c b/drivers/power/s3c_adc_battery.c
index a675e31..d32d0d7 100644
--- a/drivers/power/s3c_adc_battery.c
+++ b/drivers/power/s3c_adc_battery.c
@@ -20,6 +20,7 @@
#include <linux/s3c_adc_battery.h>
#include <linux/errno.h>
#include <linux/init.h>
+#include <linux/module.h>
#include <plat/adc.h>
diff --git a/drivers/rapidio/rio-scan.c b/drivers/rapidio/rio-scan.c
index ee89358..ebe77dd 100644
--- a/drivers/rapidio/rio-scan.c
+++ b/drivers/rapidio/rio-scan.c
@@ -505,8 +505,7 @@
rdev->dev.dma_mask = &rdev->dma_mask;
rdev->dev.coherent_dma_mask = DMA_BIT_MASK(32);
- if ((rdev->pef & RIO_PEF_INB_DOORBELL) &&
- (rdev->dst_ops & RIO_DST_OPS_DOORBELL))
+ if (rdev->dst_ops & RIO_DST_OPS_DOORBELL)
rio_init_dbell_res(&rdev->riores[RIO_DOORBELL_RESOURCE],
0, 0xffff);
diff --git a/drivers/rtc/rtc-ep93xx.c b/drivers/rtc/rtc-ep93xx.c
index 335551d..14a42a1 100644
--- a/drivers/rtc/rtc-ep93xx.c
+++ b/drivers/rtc/rtc-ep93xx.c
@@ -36,6 +36,7 @@
*/
struct ep93xx_rtc {
void __iomem *mmio_base;
+ struct rtc_device *rtc;
};
static int ep93xx_rtc_get_swcomp(struct device *dev, unsigned short *preload,
@@ -130,7 +131,6 @@
{
struct ep93xx_rtc *ep93xx_rtc;
struct resource *res;
- struct rtc_device *rtc;
int err;
ep93xx_rtc = devm_kzalloc(&pdev->dev, sizeof(*ep93xx_rtc), GFP_KERNEL);
@@ -151,12 +151,12 @@
return -ENXIO;
pdev->dev.platform_data = ep93xx_rtc;
- platform_set_drvdata(pdev, rtc);
+ platform_set_drvdata(pdev, ep93xx_rtc);
- rtc = rtc_device_register(pdev->name,
+ ep93xx_rtc->rtc = rtc_device_register(pdev->name,
&pdev->dev, &ep93xx_rtc_ops, THIS_MODULE);
- if (IS_ERR(rtc)) {
- err = PTR_ERR(rtc);
+ if (IS_ERR(ep93xx_rtc->rtc)) {
+ err = PTR_ERR(ep93xx_rtc->rtc);
goto exit;
}
@@ -167,7 +167,7 @@
return 0;
fail:
- rtc_device_unregister(rtc);
+ rtc_device_unregister(ep93xx_rtc->rtc);
exit:
platform_set_drvdata(pdev, NULL);
pdev->dev.platform_data = NULL;
@@ -176,11 +176,11 @@
static int __exit ep93xx_rtc_remove(struct platform_device *pdev)
{
- struct rtc_device *rtc = platform_get_drvdata(pdev);
+ struct ep93xx_rtc *ep93xx_rtc = platform_get_drvdata(pdev);
sysfs_remove_group(&pdev->dev.kobj, &ep93xx_rtc_sysfs_files);
platform_set_drvdata(pdev, NULL);
- rtc_device_unregister(rtc);
+ rtc_device_unregister(ep93xx_rtc->rtc);
pdev->dev.platform_data = NULL;
return 0;
diff --git a/drivers/rtc/rtc-lib.c b/drivers/rtc/rtc-lib.c
index 075f170..c4cf057 100644
--- a/drivers/rtc/rtc-lib.c
+++ b/drivers/rtc/rtc-lib.c
@@ -85,6 +85,8 @@
time -= tm->tm_hour * 3600;
tm->tm_min = time / 60;
tm->tm_sec = time - tm->tm_min * 60;
+
+ tm->tm_isdst = 0;
}
EXPORT_SYMBOL(rtc_time_to_tm);
diff --git a/drivers/rtc/rtc-s3c.c b/drivers/rtc/rtc-s3c.c
index 9329dbb..4e7c04e 100644
--- a/drivers/rtc/rtc-s3c.c
+++ b/drivers/rtc/rtc-s3c.c
@@ -152,10 +152,6 @@
goto retry_get_time;
}
- pr_debug("read time %04d.%02d.%02d %02d:%02d:%02d\n",
- 1900 + rtc_tm->tm_year, rtc_tm->tm_mon, rtc_tm->tm_mday,
- rtc_tm->tm_hour, rtc_tm->tm_min, rtc_tm->tm_sec);
-
rtc_tm->tm_sec = bcd2bin(rtc_tm->tm_sec);
rtc_tm->tm_min = bcd2bin(rtc_tm->tm_min);
rtc_tm->tm_hour = bcd2bin(rtc_tm->tm_hour);
@@ -164,6 +160,11 @@
rtc_tm->tm_year = bcd2bin(rtc_tm->tm_year);
rtc_tm->tm_year += 100;
+
+ pr_debug("read time %04d.%02d.%02d %02d:%02d:%02d\n",
+ 1900 + rtc_tm->tm_year, rtc_tm->tm_mon, rtc_tm->tm_mday,
+ rtc_tm->tm_hour, rtc_tm->tm_min, rtc_tm->tm_sec);
+
rtc_tm->tm_mon -= 1;
clk_disable(rtc_clk);
@@ -269,10 +270,9 @@
clk_enable(rtc_clk);
pr_debug("s3c_rtc_setalarm: %d, %04d.%02d.%02d %02d:%02d:%02d\n",
alrm->enabled,
- 1900 + tm->tm_year, tm->tm_mon, tm->tm_mday,
+ 1900 + tm->tm_year, tm->tm_mon + 1, tm->tm_mday,
tm->tm_hour, tm->tm_min, tm->tm_sec);
-
alrm_en = readb(base + S3C2410_RTCALM) & S3C2410_RTCALM_ALMEN;
writeb(0x00, base + S3C2410_RTCALM);
@@ -319,49 +319,7 @@
return 0;
}
-static int s3c_rtc_open(struct device *dev)
-{
- struct platform_device *pdev = to_platform_device(dev);
- struct rtc_device *rtc_dev = platform_get_drvdata(pdev);
- int ret;
-
- ret = request_irq(s3c_rtc_alarmno, s3c_rtc_alarmirq,
- IRQF_DISABLED, "s3c2410-rtc alarm", rtc_dev);
-
- if (ret) {
- dev_err(dev, "IRQ%d error %d\n", s3c_rtc_alarmno, ret);
- return ret;
- }
-
- ret = request_irq(s3c_rtc_tickno, s3c_rtc_tickirq,
- IRQF_DISABLED, "s3c2410-rtc tick", rtc_dev);
-
- if (ret) {
- dev_err(dev, "IRQ%d error %d\n", s3c_rtc_tickno, ret);
- goto tick_err;
- }
-
- return ret;
-
- tick_err:
- free_irq(s3c_rtc_alarmno, rtc_dev);
- return ret;
-}
-
-static void s3c_rtc_release(struct device *dev)
-{
- struct platform_device *pdev = to_platform_device(dev);
- struct rtc_device *rtc_dev = platform_get_drvdata(pdev);
-
- /* do not clear AIE here, it may be needed for wake */
-
- free_irq(s3c_rtc_alarmno, rtc_dev);
- free_irq(s3c_rtc_tickno, rtc_dev);
-}
-
static const struct rtc_class_ops s3c_rtcops = {
- .open = s3c_rtc_open,
- .release = s3c_rtc_release,
.read_time = s3c_rtc_gettime,
.set_time = s3c_rtc_settime,
.read_alarm = s3c_rtc_getalarm,
@@ -425,6 +383,9 @@
{
struct rtc_device *rtc = platform_get_drvdata(dev);
+ free_irq(s3c_rtc_alarmno, rtc);
+ free_irq(s3c_rtc_tickno, rtc);
+
platform_set_drvdata(dev, NULL);
rtc_device_unregister(rtc);
@@ -548,10 +509,32 @@
s3c_rtc_setfreq(&pdev->dev, 1);
+ ret = request_irq(s3c_rtc_alarmno, s3c_rtc_alarmirq,
+ IRQF_DISABLED, "s3c2410-rtc alarm", rtc);
+ if (ret) {
+ dev_err(&pdev->dev, "IRQ%d error %d\n", s3c_rtc_alarmno, ret);
+ goto err_alarm_irq;
+ }
+
+ ret = request_irq(s3c_rtc_tickno, s3c_rtc_tickirq,
+ IRQF_DISABLED, "s3c2410-rtc tick", rtc);
+ if (ret) {
+ dev_err(&pdev->dev, "IRQ%d error %d\n", s3c_rtc_tickno, ret);
+ free_irq(s3c_rtc_alarmno, rtc);
+ goto err_tick_irq;
+ }
+
clk_disable(rtc_clk);
return 0;
+ err_tick_irq:
+ free_irq(s3c_rtc_alarmno, rtc);
+
+ err_alarm_irq:
+ platform_set_drvdata(pdev, NULL);
+ rtc_device_unregister(rtc);
+
err_nortc:
s3c_rtc_enable(pdev, 0);
clk_disable(rtc_clk);
diff --git a/drivers/rtc/rtc-twl.c b/drivers/rtc/rtc-twl.c
index 9a81f77..20687d5 100644
--- a/drivers/rtc/rtc-twl.c
+++ b/drivers/rtc/rtc-twl.c
@@ -362,14 +362,6 @@
int res;
u8 rd_reg;
-#ifdef CONFIG_LOCKDEP
- /* WORKAROUND for lockdep forcing IRQF_DISABLED on us, which
- * we don't want and can't tolerate. Although it might be
- * friendlier not to borrow this thread context...
- */
- local_irq_enable();
-#endif
-
res = twl_rtc_read_u8(&rd_reg, REG_RTC_STATUS_REG);
if (res)
goto out;
@@ -428,24 +420,12 @@
static int __devinit twl_rtc_probe(struct platform_device *pdev)
{
struct rtc_device *rtc;
- int ret = 0;
+ int ret = -EINVAL;
int irq = platform_get_irq(pdev, 0);
u8 rd_reg;
if (irq <= 0)
- return -EINVAL;
-
- rtc = rtc_device_register(pdev->name,
- &pdev->dev, &twl_rtc_ops, THIS_MODULE);
- if (IS_ERR(rtc)) {
- ret = PTR_ERR(rtc);
- dev_err(&pdev->dev, "can't register RTC device, err %ld\n",
- PTR_ERR(rtc));
- goto out0;
-
- }
-
- platform_set_drvdata(pdev, rtc);
+ goto out1;
ret = twl_rtc_read_u8(&rd_reg, REG_RTC_STATUS_REG);
if (ret < 0)
@@ -462,14 +442,6 @@
if (ret < 0)
goto out1;
- ret = request_irq(irq, twl_rtc_interrupt,
- IRQF_TRIGGER_RISING,
- dev_name(&rtc->dev), rtc);
- if (ret < 0) {
- dev_err(&pdev->dev, "IRQ is not free.\n");
- goto out1;
- }
-
if (twl_class_is_6030()) {
twl6030_interrupt_unmask(TWL6030_RTC_INT_MASK,
REG_INT_MSK_LINE_A);
@@ -480,28 +452,44 @@
/* Check RTC module status, Enable if it is off */
ret = twl_rtc_read_u8(&rd_reg, REG_RTC_CTRL_REG);
if (ret < 0)
- goto out2;
+ goto out1;
if (!(rd_reg & BIT_RTC_CTRL_REG_STOP_RTC_M)) {
dev_info(&pdev->dev, "Enabling TWL-RTC.\n");
rd_reg = BIT_RTC_CTRL_REG_STOP_RTC_M;
ret = twl_rtc_write_u8(rd_reg, REG_RTC_CTRL_REG);
if (ret < 0)
- goto out2;
+ goto out1;
}
/* init cached IRQ enable bits */
ret = twl_rtc_read_u8(&rtc_irq_bits, REG_RTC_INTERRUPTS_REG);
if (ret < 0)
- goto out2;
+ goto out1;
- return ret;
+ rtc = rtc_device_register(pdev->name,
+ &pdev->dev, &twl_rtc_ops, THIS_MODULE);
+ if (IS_ERR(rtc)) {
+ ret = PTR_ERR(rtc);
+ dev_err(&pdev->dev, "can't register RTC device, err %ld\n",
+ PTR_ERR(rtc));
+ goto out1;
+ }
+
+ ret = request_threaded_irq(irq, NULL, twl_rtc_interrupt,
+ IRQF_TRIGGER_RISING,
+ dev_name(&rtc->dev), rtc);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "IRQ is not free.\n");
+ goto out2;
+ }
+
+ platform_set_drvdata(pdev, rtc);
+ return 0;
out2:
- free_irq(irq, rtc);
-out1:
rtc_device_unregister(rtc);
-out0:
+out1:
return ret;
}
diff --git a/drivers/s390/block/dasd_ioctl.c b/drivers/s390/block/dasd_ioctl.c
index eb4e034..f1a2016 100644
--- a/drivers/s390/block/dasd_ioctl.c
+++ b/drivers/s390/block/dasd_ioctl.c
@@ -249,6 +249,7 @@
static int dasd_ioctl_read_profile(struct dasd_block *block, void __user *argp)
{
struct dasd_profile_info_t *data;
+ int rc = 0;
data = kmalloc(sizeof(*data), GFP_KERNEL);
if (!data)
@@ -279,11 +280,14 @@
spin_unlock_bh(&block->profile.lock);
} else {
spin_unlock_bh(&block->profile.lock);
- return -EIO;
+ rc = -EIO;
+ goto out;
}
if (copy_to_user(argp, data, sizeof(*data)))
- return -EFAULT;
- return 0;
+ rc = -EFAULT;
+out:
+ kfree(data);
+ return rc;
}
#else
static int dasd_ioctl_reset_profile(struct dasd_block *block)
diff --git a/drivers/s390/char/sclp_cmd.c b/drivers/s390/char/sclp_cmd.c
index be55fb2..837e010 100644
--- a/drivers/s390/char/sclp_cmd.c
+++ b/drivers/s390/char/sclp_cmd.c
@@ -383,8 +383,10 @@
switch (sccb->header.response_code) {
case 0x0020:
set_bit(id, sclp_storage_ids);
- for (i = 0; i < sccb->assigned; i++)
- sclp_unassign_storage(sccb->entries[i] >> 16);
+ for (i = 0; i < sccb->assigned; i++) {
+ if (sccb->entries[i])
+ sclp_unassign_storage(sccb->entries[i] >> 16);
+ }
break;
default:
rc = -EIO;
diff --git a/drivers/scsi/qla4xxx/Kconfig b/drivers/scsi/qla4xxx/Kconfig
index 2c33ce6..0f5599e 100644
--- a/drivers/scsi/qla4xxx/Kconfig
+++ b/drivers/scsi/qla4xxx/Kconfig
@@ -1,6 +1,6 @@
config SCSI_QLA_ISCSI
tristate "QLogic ISP4XXX and ISP82XX host adapter family support"
- depends on PCI && SCSI
+ depends on PCI && SCSI && NET
select SCSI_ISCSI_ATTRS
---help---
This driver supports the QLogic 40xx (ISP4XXX) and 8022 (ISP82XX)
diff --git a/drivers/sh/intc/chip.c b/drivers/sh/intc/chip.c
index f33e2dd..33b2ed4 100644
--- a/drivers/sh/intc/chip.c
+++ b/drivers/sh/intc/chip.c
@@ -186,6 +186,9 @@
!defined(CONFIG_CPU_SUBTYPE_SH7709)
[IRQ_TYPE_LEVEL_HIGH] = VALID(3),
#endif
+#if defined(CONFIG_ARCH_SH7372)
+ [IRQ_TYPE_EDGE_BOTH] = VALID(4),
+#endif
};
static int intc_set_type(struct irq_data *data, unsigned int type)
diff --git a/drivers/staging/brcm80211/brcmsmac/otp.c b/drivers/staging/brcm80211/brcmsmac/otp.c
index 34253cf..4a70180 100644
--- a/drivers/staging/brcm80211/brcmsmac/otp.c
+++ b/drivers/staging/brcm80211/brcmsmac/otp.c
@@ -16,6 +16,7 @@
#include <linux/io.h>
#include <linux/errno.h>
+#include <linux/string.h>
#include <brcm_hw_ids.h>
#include <chipcommon.h>
diff --git a/drivers/staging/brcm80211/brcmsmac/types.h b/drivers/staging/brcm80211/brcmsmac/types.h
index bbf2189..823b5e4 100644
--- a/drivers/staging/brcm80211/brcmsmac/types.h
+++ b/drivers/staging/brcm80211/brcmsmac/types.h
@@ -18,6 +18,7 @@
#define _BRCM_TYPES_H_
#include <linux/types.h>
+#include <linux/io.h>
/* Bus types */
#define SI_BUS 0 /* SOC Interconnect */
diff --git a/drivers/staging/octeon/ethernet-rgmii.c b/drivers/staging/octeon/ethernet-rgmii.c
index 9c0d293..c3d73f8 100644
--- a/drivers/staging/octeon/ethernet-rgmii.c
+++ b/drivers/staging/octeon/ethernet-rgmii.c
@@ -26,6 +26,7 @@
**********************************************************************/
#include <linux/kernel.h>
#include <linux/netdevice.h>
+#include <linux/interrupt.h>
#include <linux/phy.h>
#include <linux/ratelimit.h>
#include <net/dst.h>
diff --git a/drivers/staging/octeon/ethernet-spi.c b/drivers/staging/octeon/ethernet-spi.c
index 9708254..d0e2d51 100644
--- a/drivers/staging/octeon/ethernet-spi.c
+++ b/drivers/staging/octeon/ethernet-spi.c
@@ -26,6 +26,7 @@
**********************************************************************/
#include <linux/kernel.h>
#include <linux/netdevice.h>
+#include <linux/interrupt.h>
#include <net/dst.h>
#include <asm/octeon/octeon.h>
diff --git a/drivers/staging/tidspbridge/core/dsp-clock.c b/drivers/staging/tidspbridge/core/dsp-clock.c
index 589a055..3d1279c 100644
--- a/drivers/staging/tidspbridge/core/dsp-clock.c
+++ b/drivers/staging/tidspbridge/core/dsp-clock.c
@@ -209,7 +209,6 @@
break;
#ifdef CONFIG_OMAP_MCBSP
case MCBSP_CLK:
- omap_mcbsp_set_io_type(MCBSP_ID(clk_id), OMAP_MCBSP_POLL_IO);
omap_mcbsp_request(MCBSP_ID(clk_id));
omap2_mcbsp_set_clks_src(MCBSP_ID(clk_id), MCBSP_CLKS_PAD_SRC);
break;
diff --git a/drivers/staging/zcache/tmem.c b/drivers/staging/zcache/tmem.c
index 975e34b..1ca66ea 100644
--- a/drivers/staging/zcache/tmem.c
+++ b/drivers/staging/zcache/tmem.c
@@ -604,7 +604,7 @@
struct tmem_obj *obj;
void *pampd;
bool ephemeral = is_ephemeral(pool);
- uint32_t ret = -1;
+ int ret = -1;
struct tmem_hashbucket *hb;
bool free = (get_and_free == 1) || ((get_and_free == 0) && ephemeral);
bool lock_held = false;
diff --git a/drivers/staging/zcache/zcache-main.c b/drivers/staging/zcache/zcache-main.c
index 855a5bb..a3f5162 100644
--- a/drivers/staging/zcache/zcache-main.c
+++ b/drivers/staging/zcache/zcache-main.c
@@ -1158,7 +1158,7 @@
size_t clen;
int ret;
unsigned long count;
- struct page *page = virt_to_page(data);
+ struct page *page = (struct page *)(data);
struct zcache_client *cli = pool->client;
uint16_t client_id = get_client_id_from_client(cli);
unsigned long zv_mean_zsize;
@@ -1227,7 +1227,7 @@
int ret = 0;
BUG_ON(is_ephemeral(pool));
- zv_decompress(virt_to_page(data), pampd);
+ zv_decompress((struct page *)(data), pampd);
return ret;
}
@@ -1539,7 +1539,7 @@
goto out;
if (!zcache_freeze && zcache_do_preload(pool) == 0) {
/* preload does preempt_disable on success */
- ret = tmem_put(pool, oidp, index, page_address(page),
+ ret = tmem_put(pool, oidp, index, (char *)(page),
PAGE_SIZE, 0, is_ephemeral(pool));
if (ret < 0) {
if (is_ephemeral(pool))
@@ -1572,7 +1572,7 @@
pool = zcache_get_pool_by_id(cli_id, pool_id);
if (likely(pool != NULL)) {
if (atomic_read(&pool->obj_count) > 0)
- ret = tmem_get(pool, oidp, index, page_address(page),
+ ret = tmem_get(pool, oidp, index, (char *)(page),
&size, 0, is_ephemeral(pool));
zcache_put_pool(pool);
}
diff --git a/drivers/target/iscsi/iscsi_target.c b/drivers/target/iscsi/iscsi_target.c
index c24fb10..6a4ea29 100644
--- a/drivers/target/iscsi/iscsi_target.c
+++ b/drivers/target/iscsi/iscsi_target.c
@@ -2243,7 +2243,6 @@
case 0:
return iscsit_handle_recovery_datain_or_r2t(conn, buf,
hdr->itt, hdr->ttt, hdr->begrun, hdr->runlength);
- return 0;
case ISCSI_FLAG_SNACK_TYPE_STATUS:
return iscsit_handle_status_snack(conn, hdr->itt, hdr->ttt,
hdr->begrun, hdr->runlength);
diff --git a/drivers/target/iscsi/iscsi_target_configfs.c b/drivers/target/iscsi/iscsi_target_configfs.c
index f095e65..f1643db 100644
--- a/drivers/target/iscsi/iscsi_target_configfs.c
+++ b/drivers/target/iscsi/iscsi_target_configfs.c
@@ -268,7 +268,7 @@
ISCSI_TCP);
if (IS_ERR(tpg_np)) {
iscsit_put_tpg(tpg);
- return ERR_PTR(PTR_ERR(tpg_np));
+ return ERR_CAST(tpg_np);
}
pr_debug("LIO_Target_ConfigFS: addnptotpg done!\n");
@@ -1285,7 +1285,7 @@
tiqn = iscsit_add_tiqn((unsigned char *)name);
if (IS_ERR(tiqn))
- return ERR_PTR(PTR_ERR(tiqn));
+ return ERR_CAST(tiqn);
/*
* Setup struct iscsi_wwn_stat_grps for se_wwn->fabric_stat_group.
*/
diff --git a/drivers/target/iscsi/iscsi_target_erl1.c b/drivers/target/iscsi/iscsi_target_erl1.c
index 9806507..c4c68da 100644
--- a/drivers/target/iscsi/iscsi_target_erl1.c
+++ b/drivers/target/iscsi/iscsi_target_erl1.c
@@ -834,7 +834,7 @@
*/
list_for_each_entry(ooo_tmp, &sess->sess_ooo_cmdsn_list,
ooo_list) {
- while (ooo_tmp->cmdsn < ooo_cmdsn->cmdsn)
+ if (ooo_tmp->cmdsn < ooo_cmdsn->cmdsn)
continue;
list_add(&ooo_cmdsn->ooo_list,
diff --git a/drivers/target/iscsi/iscsi_target_login.c b/drivers/target/iscsi/iscsi_target_login.c
index bcaf82f..daad362 100644
--- a/drivers/target/iscsi/iscsi_target_login.c
+++ b/drivers/target/iscsi/iscsi_target_login.c
@@ -1013,19 +1013,9 @@
ISCSI_LOGIN_STATUS_TARGET_ERROR);
goto new_sess_out;
}
-#if 0
- if (!iscsi_ntop6((const unsigned char *)
- &sock_in6.sin6_addr.in6_u,
- (char *)&conn->ipv6_login_ip[0],
- IPV6_ADDRESS_SPACE)) {
- pr_err("iscsi_ntop6() failed\n");
- iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_TARGET_ERR,
- ISCSI_LOGIN_STATUS_TARGET_ERROR);
- goto new_sess_out;
- }
-#else
- pr_debug("Skipping iscsi_ntop6()\n");
-#endif
+ snprintf(conn->login_ip, sizeof(conn->login_ip), "%pI6c",
+ &sock_in6.sin6_addr.in6_u);
+ conn->login_port = ntohs(sock_in6.sin6_port);
} else {
memset(&sock_in, 0, sizeof(struct sockaddr_in));
diff --git a/drivers/target/iscsi/iscsi_target_parameters.c b/drivers/target/iscsi/iscsi_target_parameters.c
index 252e246..497b2e7 100644
--- a/drivers/target/iscsi/iscsi_target_parameters.c
+++ b/drivers/target/iscsi/iscsi_target_parameters.c
@@ -545,13 +545,13 @@
struct iscsi_param_list *src_param_list,
int leading)
{
- struct iscsi_param *new_param = NULL, *param = NULL;
+ struct iscsi_param *param = NULL;
+ struct iscsi_param *new_param = NULL;
struct iscsi_param_list *param_list = NULL;
param_list = kzalloc(sizeof(struct iscsi_param_list), GFP_KERNEL);
if (!param_list) {
- pr_err("Unable to allocate memory for"
- " struct iscsi_param_list.\n");
+ pr_err("Unable to allocate memory for struct iscsi_param_list.\n");
goto err_out;
}
INIT_LIST_HEAD(¶m_list->param_list);
@@ -567,8 +567,17 @@
new_param = kzalloc(sizeof(struct iscsi_param), GFP_KERNEL);
if (!new_param) {
- pr_err("Unable to allocate memory for"
- " struct iscsi_param.\n");
+ pr_err("Unable to allocate memory for struct iscsi_param.\n");
+ goto err_out;
+ }
+
+ new_param->name = kstrdup(param->name, GFP_KERNEL);
+ new_param->value = kstrdup(param->value, GFP_KERNEL);
+ if (!new_param->value || !new_param->name) {
+ kfree(new_param->value);
+ kfree(new_param->name);
+ kfree(new_param);
+ pr_err("Unable to allocate memory for parameter name/value.\n");
goto err_out;
}
@@ -580,32 +589,12 @@
new_param->use = param->use;
new_param->type_range = param->type_range;
- new_param->name = kzalloc(strlen(param->name) + 1, GFP_KERNEL);
- if (!new_param->name) {
- pr_err("Unable to allocate memory for"
- " parameter name.\n");
- goto err_out;
- }
-
- new_param->value = kzalloc(strlen(param->value) + 1,
- GFP_KERNEL);
- if (!new_param->value) {
- pr_err("Unable to allocate memory for"
- " parameter value.\n");
- goto err_out;
- }
-
- memcpy(new_param->name, param->name, strlen(param->name));
- new_param->name[strlen(param->name)] = '\0';
- memcpy(new_param->value, param->value, strlen(param->value));
- new_param->value[strlen(param->value)] = '\0';
-
list_add_tail(&new_param->p_list, ¶m_list->param_list);
}
- if (!list_empty(¶m_list->param_list))
+ if (!list_empty(¶m_list->param_list)) {
*dst_param_list = param_list;
- else {
+ } else {
pr_err("No parameters allocated.\n");
goto err_out;
}
diff --git a/drivers/target/iscsi/iscsi_target_util.c b/drivers/target/iscsi/iscsi_target_util.c
index a1acb01..a0d23bc 100644
--- a/drivers/target/iscsi/iscsi_target_util.c
+++ b/drivers/target/iscsi/iscsi_target_util.c
@@ -243,7 +243,7 @@
if (!cmd->tmr_req) {
pr_err("Unable to allocate memory for"
" Task Management command!\n");
- return NULL;
+ goto out;
}
/*
* TASK_REASSIGN for ERL=2 / connection stays inside of
@@ -298,8 +298,6 @@
return cmd;
out:
iscsit_release_cmd(cmd);
- if (se_cmd)
- transport_free_se_cmd(se_cmd);
return NULL;
}
diff --git a/drivers/target/target_core_cdb.c b/drivers/target/target_core_cdb.c
index 8ae09a1..89ae923 100644
--- a/drivers/target/target_core_cdb.c
+++ b/drivers/target/target_core_cdb.c
@@ -67,6 +67,7 @@
{
struct se_lun *lun = cmd->se_lun;
struct se_device *dev = cmd->se_dev;
+ struct se_portal_group *tpg = lun->lun_sep->sep_tpg;
unsigned char *buf;
/*
@@ -81,9 +82,13 @@
buf = transport_kmap_first_data_page(cmd);
- buf[0] = dev->transport->get_device_type(dev);
- if (buf[0] == TYPE_TAPE)
- buf[1] = 0x80;
+ if (dev == tpg->tpg_virt_lun0.lun_se_dev) {
+ buf[0] = 0x3f; /* Not connected */
+ } else {
+ buf[0] = dev->transport->get_device_type(dev);
+ if (buf[0] == TYPE_TAPE)
+ buf[1] = 0x80;
+ }
buf[2] = dev->transport->get_device_rev(dev);
/*
@@ -915,8 +920,8 @@
length += target_modesense_control(dev, &buf[offset+length]);
break;
default:
- pr_err("Got Unknown Mode Page: 0x%02x\n",
- cdb[2] & 0x3f);
+ pr_err("MODE SENSE: unimplemented page/subpage: 0x%02x/0x%02x\n",
+ cdb[2] & 0x3f, cdb[3]);
return PYX_TRANSPORT_UNKNOWN_MODE_PAGE;
}
offset += length;
@@ -1072,8 +1077,6 @@
size -= 16;
}
- task->task_scsi_status = GOOD;
- transport_complete_task(task, 1);
err:
transport_kunmap_first_data_page(cmd);
@@ -1085,24 +1088,17 @@
* Note this is not used for TCM/pSCSI passthrough
*/
static int
-target_emulate_write_same(struct se_task *task, int write_same32)
+target_emulate_write_same(struct se_task *task, u32 num_blocks)
{
struct se_cmd *cmd = task->task_se_cmd;
struct se_device *dev = cmd->se_dev;
sector_t range;
sector_t lba = cmd->t_task_lba;
- unsigned int num_blocks;
int ret;
/*
- * Extract num_blocks from the WRITE_SAME_* CDB. Then use the explict
- * range when non zero is supplied, otherwise calculate the remaining
- * range based on ->get_blocks() - starting LBA.
+ * Use the explicit range when non zero is supplied, otherwise calculate
+ * the remaining range based on ->get_blocks() - starting LBA.
*/
- if (write_same32)
- num_blocks = get_unaligned_be32(&cmd->t_task_cdb[28]);
- else
- num_blocks = get_unaligned_be32(&cmd->t_task_cdb[10]);
-
if (num_blocks != 0)
range = num_blocks;
else
@@ -1117,8 +1113,6 @@
return ret;
}
- task->task_scsi_status = GOOD;
- transport_complete_task(task, 1);
return 0;
}
@@ -1165,13 +1159,23 @@
}
ret = target_emulate_unmap(task);
break;
+ case WRITE_SAME:
+ if (!dev->transport->do_discard) {
+ pr_err("WRITE_SAME emulation not supported"
+ " for: %s\n", dev->transport->name);
+ return PYX_TRANSPORT_UNKNOWN_SAM_OPCODE;
+ }
+ ret = target_emulate_write_same(task,
+ get_unaligned_be16(&cmd->t_task_cdb[7]));
+ break;
case WRITE_SAME_16:
if (!dev->transport->do_discard) {
pr_err("WRITE_SAME_16 emulation not supported"
" for: %s\n", dev->transport->name);
return PYX_TRANSPORT_UNKNOWN_SAM_OPCODE;
}
- ret = target_emulate_write_same(task, 0);
+ ret = target_emulate_write_same(task,
+ get_unaligned_be32(&cmd->t_task_cdb[10]));
break;
case VARIABLE_LENGTH_CMD:
service_action =
@@ -1184,7 +1188,8 @@
dev->transport->name);
return PYX_TRANSPORT_UNKNOWN_SAM_OPCODE;
}
- ret = target_emulate_write_same(task, 1);
+ ret = target_emulate_write_same(task,
+ get_unaligned_be32(&cmd->t_task_cdb[28]));
break;
default:
pr_err("Unsupported VARIABLE_LENGTH_CMD SA:"
@@ -1219,8 +1224,14 @@
if (ret < 0)
return ret;
- task->task_scsi_status = GOOD;
- transport_complete_task(task, 1);
+ /*
+ * Handle the successful completion here unless a caller
+ * has explictly requested an asychronous completion.
+ */
+ if (!(cmd->se_cmd_flags & SCF_EMULATE_CDB_ASYNC)) {
+ task->task_scsi_status = GOOD;
+ transport_complete_task(task, 1);
+ }
return PYX_TRANSPORT_SENT_TO_TRANSPORT;
}
diff --git a/drivers/target/target_core_device.c b/drivers/target/target_core_device.c
index b38b6c9..ca6e4a4 100644
--- a/drivers/target/target_core_device.c
+++ b/drivers/target/target_core_device.c
@@ -472,9 +472,9 @@
struct se_dev_entry *deve;
u32 i;
- spin_lock_bh(&tpg->acl_node_lock);
+ spin_lock_irq(&tpg->acl_node_lock);
list_for_each_entry(nacl, &tpg->acl_node_list, acl_list) {
- spin_unlock_bh(&tpg->acl_node_lock);
+ spin_unlock_irq(&tpg->acl_node_lock);
spin_lock_irq(&nacl->device_list_lock);
for (i = 0; i < TRANSPORT_MAX_LUNS_PER_TPG; i++) {
@@ -491,9 +491,9 @@
}
spin_unlock_irq(&nacl->device_list_lock);
- spin_lock_bh(&tpg->acl_node_lock);
+ spin_lock_irq(&tpg->acl_node_lock);
}
- spin_unlock_bh(&tpg->acl_node_lock);
+ spin_unlock_irq(&tpg->acl_node_lock);
}
static struct se_port *core_alloc_port(struct se_device *dev)
@@ -839,6 +839,24 @@
return ret;
}
+u32 se_dev_align_max_sectors(u32 max_sectors, u32 block_size)
+{
+ u32 tmp, aligned_max_sectors;
+ /*
+ * Limit max_sectors to a PAGE_SIZE aligned value for modern
+ * transport_allocate_data_tasks() operation.
+ */
+ tmp = rounddown((max_sectors * block_size), PAGE_SIZE);
+ aligned_max_sectors = (tmp / block_size);
+ if (max_sectors != aligned_max_sectors) {
+ printk(KERN_INFO "Rounding down aligned max_sectors from %u"
+ " to %u\n", max_sectors, aligned_max_sectors);
+ return aligned_max_sectors;
+ }
+
+ return max_sectors;
+}
+
void se_dev_set_default_attribs(
struct se_device *dev,
struct se_dev_limits *dev_limits)
@@ -878,6 +896,11 @@
* max_sectors is based on subsystem plugin dependent requirements.
*/
dev->se_sub_dev->se_dev_attrib.hw_max_sectors = limits->max_hw_sectors;
+ /*
+ * Align max_sectors down to PAGE_SIZE to follow transport_allocate_data_tasks()
+ */
+ limits->max_sectors = se_dev_align_max_sectors(limits->max_sectors,
+ limits->logical_block_size);
dev->se_sub_dev->se_dev_attrib.max_sectors = limits->max_sectors;
/*
* Set optimal_sectors from max_sectors, which can be lowered via
@@ -1242,6 +1265,11 @@
return -EINVAL;
}
}
+ /*
+ * Align max_sectors down to PAGE_SIZE to follow transport_allocate_data_tasks()
+ */
+ max_sectors = se_dev_align_max_sectors(max_sectors,
+ dev->se_sub_dev->se_dev_attrib.block_size);
dev->se_sub_dev->se_dev_attrib.max_sectors = max_sectors;
pr_debug("dev[%p]: SE Device max_sectors changed to %u\n",
@@ -1344,15 +1372,17 @@
*/
if (tpg->se_tpg_tfo->tpg_check_demo_mode(tpg)) {
struct se_node_acl *acl;
- spin_lock_bh(&tpg->acl_node_lock);
+ spin_lock_irq(&tpg->acl_node_lock);
list_for_each_entry(acl, &tpg->acl_node_list, acl_list) {
- if (acl->dynamic_node_acl) {
- spin_unlock_bh(&tpg->acl_node_lock);
+ if (acl->dynamic_node_acl &&
+ (!tpg->se_tpg_tfo->tpg_check_demo_mode_login_only ||
+ !tpg->se_tpg_tfo->tpg_check_demo_mode_login_only(tpg))) {
+ spin_unlock_irq(&tpg->acl_node_lock);
core_tpg_add_node_to_devs(acl, tpg);
- spin_lock_bh(&tpg->acl_node_lock);
+ spin_lock_irq(&tpg->acl_node_lock);
}
}
- spin_unlock_bh(&tpg->acl_node_lock);
+ spin_unlock_irq(&tpg->acl_node_lock);
}
return lun_p;
diff --git a/drivers/target/target_core_fabric_configfs.c b/drivers/target/target_core_fabric_configfs.c
index f165469..55bbe08 100644
--- a/drivers/target/target_core_fabric_configfs.c
+++ b/drivers/target/target_core_fabric_configfs.c
@@ -481,7 +481,7 @@
se_nacl = tf->tf_ops.fabric_make_nodeacl(se_tpg, group, name);
if (IS_ERR(se_nacl))
- return ERR_PTR(PTR_ERR(se_nacl));
+ return ERR_CAST(se_nacl);
nacl_cg = &se_nacl->acl_group;
nacl_cg->default_groups = se_nacl->acl_default_groups;
diff --git a/drivers/target/target_core_pr.c b/drivers/target/target_core_pr.c
index 1c1b849..7fd3a16 100644
--- a/drivers/target/target_core_pr.c
+++ b/drivers/target/target_core_pr.c
@@ -1598,14 +1598,14 @@
* from the decoded fabric module specific TransportID
* at *i_str.
*/
- spin_lock_bh(&tmp_tpg->acl_node_lock);
+ spin_lock_irq(&tmp_tpg->acl_node_lock);
dest_node_acl = __core_tpg_get_initiator_node_acl(
tmp_tpg, i_str);
if (dest_node_acl) {
atomic_inc(&dest_node_acl->acl_pr_ref_count);
smp_mb__after_atomic_inc();
}
- spin_unlock_bh(&tmp_tpg->acl_node_lock);
+ spin_unlock_irq(&tmp_tpg->acl_node_lock);
if (!dest_node_acl) {
core_scsi3_tpg_undepend_item(tmp_tpg);
@@ -3496,14 +3496,14 @@
/*
* Locate the destination struct se_node_acl from the received Transport ID
*/
- spin_lock_bh(&dest_se_tpg->acl_node_lock);
+ spin_lock_irq(&dest_se_tpg->acl_node_lock);
dest_node_acl = __core_tpg_get_initiator_node_acl(dest_se_tpg,
initiator_str);
if (dest_node_acl) {
atomic_inc(&dest_node_acl->acl_pr_ref_count);
smp_mb__after_atomic_inc();
}
- spin_unlock_bh(&dest_se_tpg->acl_node_lock);
+ spin_unlock_irq(&dest_se_tpg->acl_node_lock);
if (!dest_node_acl) {
pr_err("Unable to locate %s dest_node_acl for"
diff --git a/drivers/target/target_core_rd.c b/drivers/target/target_core_rd.c
index 3dd81d2..e567e12 100644
--- a/drivers/target/target_core_rd.c
+++ b/drivers/target/target_core_rd.c
@@ -390,12 +390,10 @@
length = req->rd_size;
dst = sg_virt(&sg_d[i++]) + dst_offset;
- if (!dst)
- BUG();
+ BUG_ON(!dst);
src = sg_virt(&sg_s[j]) + src_offset;
- if (!src)
- BUG();
+ BUG_ON(!src);
dst_offset = 0;
src_offset = length;
@@ -415,8 +413,7 @@
length = req->rd_size;
dst = sg_virt(&sg_d[i]) + dst_offset;
- if (!dst)
- BUG();
+ BUG_ON(!dst);
if (sg_d[i].length == length) {
i++;
@@ -425,8 +422,7 @@
dst_offset = length;
src = sg_virt(&sg_s[j++]) + src_offset;
- if (!src)
- BUG();
+ BUG_ON(!src);
src_offset = 0;
page_end = 1;
@@ -510,12 +506,10 @@
length = req->rd_size;
src = sg_virt(&sg_s[i++]) + src_offset;
- if (!src)
- BUG();
+ BUG_ON(!src);
dst = sg_virt(&sg_d[j]) + dst_offset;
- if (!dst)
- BUG();
+ BUG_ON(!dst);
src_offset = 0;
dst_offset = length;
@@ -535,8 +529,7 @@
length = req->rd_size;
src = sg_virt(&sg_s[i]) + src_offset;
- if (!src)
- BUG();
+ BUG_ON(!src);
if (sg_s[i].length == length) {
i++;
@@ -545,8 +538,7 @@
src_offset = length;
dst = sg_virt(&sg_d[j++]) + dst_offset;
- if (!dst)
- BUG();
+ BUG_ON(!dst);
dst_offset = 0;
page_end = 1;
diff --git a/drivers/target/target_core_tpg.c b/drivers/target/target_core_tpg.c
index 4f1ba4c..162b736 100644
--- a/drivers/target/target_core_tpg.c
+++ b/drivers/target/target_core_tpg.c
@@ -137,15 +137,15 @@
{
struct se_node_acl *acl;
- spin_lock_bh(&tpg->acl_node_lock);
+ spin_lock_irq(&tpg->acl_node_lock);
list_for_each_entry(acl, &tpg->acl_node_list, acl_list) {
if (!strcmp(acl->initiatorname, initiatorname) &&
!acl->dynamic_node_acl) {
- spin_unlock_bh(&tpg->acl_node_lock);
+ spin_unlock_irq(&tpg->acl_node_lock);
return acl;
}
}
- spin_unlock_bh(&tpg->acl_node_lock);
+ spin_unlock_irq(&tpg->acl_node_lock);
return NULL;
}
@@ -298,13 +298,21 @@
tpg->se_tpg_tfo->tpg_release_fabric_acl(tpg, acl);
return NULL;
}
+ /*
+ * Here we only create demo-mode MappedLUNs from the active
+ * TPG LUNs if the fabric is not explictly asking for
+ * tpg_check_demo_mode_login_only() == 1.
+ */
+ if ((tpg->se_tpg_tfo->tpg_check_demo_mode_login_only != NULL) &&
+ (tpg->se_tpg_tfo->tpg_check_demo_mode_login_only(tpg) == 1))
+ do { ; } while (0);
+ else
+ core_tpg_add_node_to_devs(acl, tpg);
- core_tpg_add_node_to_devs(acl, tpg);
-
- spin_lock_bh(&tpg->acl_node_lock);
+ spin_lock_irq(&tpg->acl_node_lock);
list_add_tail(&acl->acl_list, &tpg->acl_node_list);
tpg->num_node_acls++;
- spin_unlock_bh(&tpg->acl_node_lock);
+ spin_unlock_irq(&tpg->acl_node_lock);
pr_debug("%s_TPG[%u] - Added DYNAMIC ACL with TCQ Depth: %d for %s"
" Initiator Node: %s\n", tpg->se_tpg_tfo->get_fabric_name(),
@@ -354,7 +362,7 @@
{
struct se_node_acl *acl = NULL;
- spin_lock_bh(&tpg->acl_node_lock);
+ spin_lock_irq(&tpg->acl_node_lock);
acl = __core_tpg_get_initiator_node_acl(tpg, initiatorname);
if (acl) {
if (acl->dynamic_node_acl) {
@@ -362,7 +370,7 @@
pr_debug("%s_TPG[%u] - Replacing dynamic ACL"
" for %s\n", tpg->se_tpg_tfo->get_fabric_name(),
tpg->se_tpg_tfo->tpg_get_tag(tpg), initiatorname);
- spin_unlock_bh(&tpg->acl_node_lock);
+ spin_unlock_irq(&tpg->acl_node_lock);
/*
* Release the locally allocated struct se_node_acl
* because * core_tpg_add_initiator_node_acl() returned
@@ -378,10 +386,10 @@
" Node %s already exists for TPG %u, ignoring"
" request.\n", tpg->se_tpg_tfo->get_fabric_name(),
initiatorname, tpg->se_tpg_tfo->tpg_get_tag(tpg));
- spin_unlock_bh(&tpg->acl_node_lock);
+ spin_unlock_irq(&tpg->acl_node_lock);
return ERR_PTR(-EEXIST);
}
- spin_unlock_bh(&tpg->acl_node_lock);
+ spin_unlock_irq(&tpg->acl_node_lock);
if (!se_nacl) {
pr_err("struct se_node_acl pointer is NULL\n");
@@ -418,10 +426,10 @@
return ERR_PTR(-EINVAL);
}
- spin_lock_bh(&tpg->acl_node_lock);
+ spin_lock_irq(&tpg->acl_node_lock);
list_add_tail(&acl->acl_list, &tpg->acl_node_list);
tpg->num_node_acls++;
- spin_unlock_bh(&tpg->acl_node_lock);
+ spin_unlock_irq(&tpg->acl_node_lock);
done:
pr_debug("%s_TPG[%hu] - Added ACL with TCQ Depth: %d for %s"
@@ -445,14 +453,14 @@
struct se_session *sess, *sess_tmp;
int dynamic_acl = 0;
- spin_lock_bh(&tpg->acl_node_lock);
+ spin_lock_irq(&tpg->acl_node_lock);
if (acl->dynamic_node_acl) {
acl->dynamic_node_acl = 0;
dynamic_acl = 1;
}
list_del(&acl->acl_list);
tpg->num_node_acls--;
- spin_unlock_bh(&tpg->acl_node_lock);
+ spin_unlock_irq(&tpg->acl_node_lock);
spin_lock_bh(&tpg->session_lock);
list_for_each_entry_safe(sess, sess_tmp,
@@ -503,21 +511,21 @@
struct se_node_acl *acl;
int dynamic_acl = 0;
- spin_lock_bh(&tpg->acl_node_lock);
+ spin_lock_irq(&tpg->acl_node_lock);
acl = __core_tpg_get_initiator_node_acl(tpg, initiatorname);
if (!acl) {
pr_err("Access Control List entry for %s Initiator"
" Node %s does not exists for TPG %hu, ignoring"
" request.\n", tpg->se_tpg_tfo->get_fabric_name(),
initiatorname, tpg->se_tpg_tfo->tpg_get_tag(tpg));
- spin_unlock_bh(&tpg->acl_node_lock);
+ spin_unlock_irq(&tpg->acl_node_lock);
return -ENODEV;
}
if (acl->dynamic_node_acl) {
acl->dynamic_node_acl = 0;
dynamic_acl = 1;
}
- spin_unlock_bh(&tpg->acl_node_lock);
+ spin_unlock_irq(&tpg->acl_node_lock);
spin_lock_bh(&tpg->session_lock);
list_for_each_entry(sess, &tpg->tpg_sess_list, sess_list) {
@@ -533,10 +541,10 @@
tpg->se_tpg_tfo->get_fabric_name(), initiatorname);
spin_unlock_bh(&tpg->session_lock);
- spin_lock_bh(&tpg->acl_node_lock);
+ spin_lock_irq(&tpg->acl_node_lock);
if (dynamic_acl)
acl->dynamic_node_acl = 1;
- spin_unlock_bh(&tpg->acl_node_lock);
+ spin_unlock_irq(&tpg->acl_node_lock);
return -EEXIST;
}
/*
@@ -571,10 +579,10 @@
if (init_sess)
tpg->se_tpg_tfo->close_session(init_sess);
- spin_lock_bh(&tpg->acl_node_lock);
+ spin_lock_irq(&tpg->acl_node_lock);
if (dynamic_acl)
acl->dynamic_node_acl = 1;
- spin_unlock_bh(&tpg->acl_node_lock);
+ spin_unlock_irq(&tpg->acl_node_lock);
return -EINVAL;
}
spin_unlock_bh(&tpg->session_lock);
@@ -590,10 +598,10 @@
initiatorname, tpg->se_tpg_tfo->get_fabric_name(),
tpg->se_tpg_tfo->tpg_get_tag(tpg));
- spin_lock_bh(&tpg->acl_node_lock);
+ spin_lock_irq(&tpg->acl_node_lock);
if (dynamic_acl)
acl->dynamic_node_acl = 1;
- spin_unlock_bh(&tpg->acl_node_lock);
+ spin_unlock_irq(&tpg->acl_node_lock);
return 0;
}
@@ -717,20 +725,20 @@
* not been released because of TFO->tpg_check_demo_mode_cache() == 1
* in transport_deregister_session().
*/
- spin_lock_bh(&se_tpg->acl_node_lock);
+ spin_lock_irq(&se_tpg->acl_node_lock);
list_for_each_entry_safe(nacl, nacl_tmp, &se_tpg->acl_node_list,
acl_list) {
list_del(&nacl->acl_list);
se_tpg->num_node_acls--;
- spin_unlock_bh(&se_tpg->acl_node_lock);
+ spin_unlock_irq(&se_tpg->acl_node_lock);
core_tpg_wait_for_nacl_pr_ref(nacl);
core_free_device_list_for_node(nacl, se_tpg);
se_tpg->se_tpg_tfo->tpg_release_fabric_acl(se_tpg, nacl);
- spin_lock_bh(&se_tpg->acl_node_lock);
+ spin_lock_irq(&se_tpg->acl_node_lock);
}
- spin_unlock_bh(&se_tpg->acl_node_lock);
+ spin_unlock_irq(&se_tpg->acl_node_lock);
if (se_tpg->se_tpg_type == TRANSPORT_TPG_TYPE_NORMAL)
core_tpg_release_virtual_lun0(se_tpg);
diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c
index 8976032..8d0c58e 100644
--- a/drivers/target/target_core_transport.c
+++ b/drivers/target/target_core_transport.c
@@ -389,17 +389,18 @@
{
struct se_portal_group *se_tpg = se_sess->se_tpg;
struct se_node_acl *se_nacl;
+ unsigned long flags;
if (!se_tpg) {
transport_free_session(se_sess);
return;
}
- spin_lock_bh(&se_tpg->session_lock);
+ spin_lock_irqsave(&se_tpg->session_lock, flags);
list_del(&se_sess->sess_list);
se_sess->se_tpg = NULL;
se_sess->fabric_sess_ptr = NULL;
- spin_unlock_bh(&se_tpg->session_lock);
+ spin_unlock_irqrestore(&se_tpg->session_lock, flags);
/*
* Determine if we need to do extra work for this initiator node's
@@ -407,22 +408,22 @@
*/
se_nacl = se_sess->se_node_acl;
if (se_nacl) {
- spin_lock_bh(&se_tpg->acl_node_lock);
+ spin_lock_irqsave(&se_tpg->acl_node_lock, flags);
if (se_nacl->dynamic_node_acl) {
if (!se_tpg->se_tpg_tfo->tpg_check_demo_mode_cache(
se_tpg)) {
list_del(&se_nacl->acl_list);
se_tpg->num_node_acls--;
- spin_unlock_bh(&se_tpg->acl_node_lock);
+ spin_unlock_irqrestore(&se_tpg->acl_node_lock, flags);
core_tpg_wait_for_nacl_pr_ref(se_nacl);
core_free_device_list_for_node(se_nacl, se_tpg);
se_tpg->se_tpg_tfo->tpg_release_fabric_acl(se_tpg,
se_nacl);
- spin_lock_bh(&se_tpg->acl_node_lock);
+ spin_lock_irqsave(&se_tpg->acl_node_lock, flags);
}
}
- spin_unlock_bh(&se_tpg->acl_node_lock);
+ spin_unlock_irqrestore(&se_tpg->acl_node_lock, flags);
}
transport_free_session(se_sess);
@@ -2053,8 +2054,14 @@
cmd->scsi_sense_reason = TCM_UNSUPPORTED_SCSI_OPCODE;
break;
}
-
- if (!sc)
+ /*
+ * If a fabric does not define a cmd->se_tfo->new_cmd_map caller,
+ * make the call to transport_send_check_condition_and_sense()
+ * directly. Otherwise expect the fabric to make the call to
+ * transport_send_check_condition_and_sense() after handling
+ * possible unsoliticied write data payloads.
+ */
+ if (!sc && !cmd->se_tfo->new_cmd_map)
transport_new_cmd_failure(cmd);
else {
ret = transport_send_check_condition_and_sense(cmd,
@@ -2847,12 +2854,42 @@
" transport_dev_end_lba(): %llu\n",
cmd->t_task_lba, sectors,
transport_dev_end_lba(dev));
- pr_err(" We should return CHECK_CONDITION"
- " but we don't yet\n");
- return 0;
+ return -EINVAL;
}
- return sectors;
+ return 0;
+}
+
+static int target_check_write_same_discard(unsigned char *flags, struct se_device *dev)
+{
+ /*
+ * Determine if the received WRITE_SAME is used to for direct
+ * passthrough into Linux/SCSI with struct request via TCM/pSCSI
+ * or we are signaling the use of internal WRITE_SAME + UNMAP=1
+ * emulation for -> Linux/BLOCK disbard with TCM/IBLOCK code.
+ */
+ int passthrough = (dev->transport->transport_type ==
+ TRANSPORT_PLUGIN_PHBA_PDEV);
+
+ if (!passthrough) {
+ if ((flags[0] & 0x04) || (flags[0] & 0x02)) {
+ pr_err("WRITE_SAME PBDATA and LBDATA"
+ " bits not supported for Block Discard"
+ " Emulation\n");
+ return -ENOSYS;
+ }
+ /*
+ * Currently for the emulated case we only accept
+ * tpws with the UNMAP=1 bit set.
+ */
+ if (!(flags[0] & 0x08)) {
+ pr_err("WRITE_SAME w/o UNMAP bit not"
+ " supported for Block Discard Emulation\n");
+ return -ENOSYS;
+ }
+ }
+
+ return 0;
}
/* transport_generic_cmd_sequencer():
@@ -3065,7 +3102,7 @@
goto out_unsupported_cdb;
if (sectors)
- size = transport_get_size(sectors, cdb, cmd);
+ size = transport_get_size(1, cdb, cmd);
else {
pr_err("WSNZ=1, WRITE_SAME w/sectors=0 not"
" supported\n");
@@ -3075,27 +3112,9 @@
cmd->t_task_lba = get_unaligned_be64(&cdb[12]);
cmd->se_cmd_flags |= SCF_SCSI_CONTROL_SG_IO_CDB;
- /*
- * Skip the remaining assignments for TCM/PSCSI passthrough
- */
- if (passthrough)
- break;
+ if (target_check_write_same_discard(&cdb[10], dev) < 0)
+ goto out_invalid_cdb_field;
- if ((cdb[10] & 0x04) || (cdb[10] & 0x02)) {
- pr_err("WRITE_SAME PBDATA and LBDATA"
- " bits not supported for Block Discard"
- " Emulation\n");
- goto out_invalid_cdb_field;
- }
- /*
- * Currently for the emulated case we only accept
- * tpws with the UNMAP=1 bit set.
- */
- if (!(cdb[10] & 0x08)) {
- pr_err("WRITE_SAME w/o UNMAP bit not"
- " supported for Block Discard Emulation\n");
- goto out_invalid_cdb_field;
- }
break;
default:
pr_err("VARIABLE_LENGTH_CMD service action"
@@ -3330,10 +3349,12 @@
cmd->se_cmd_flags |= SCF_EMULATE_CDB_ASYNC;
/*
* Check to ensure that LBA + Range does not exceed past end of
- * device.
+ * device for IBLOCK and FILEIO ->do_sync_cache() backend calls
*/
- if (!transport_cmd_get_valid_sectors(cmd))
- goto out_invalid_cdb_field;
+ if ((cmd->t_task_lba != 0) || (sectors != 0)) {
+ if (transport_cmd_get_valid_sectors(cmd) < 0)
+ goto out_invalid_cdb_field;
+ }
break;
case UNMAP:
size = get_unaligned_be16(&cdb[7]);
@@ -3345,40 +3366,38 @@
goto out_unsupported_cdb;
if (sectors)
- size = transport_get_size(sectors, cdb, cmd);
+ size = transport_get_size(1, cdb, cmd);
else {
pr_err("WSNZ=1, WRITE_SAME w/sectors=0 not supported\n");
goto out_invalid_cdb_field;
}
cmd->t_task_lba = get_unaligned_be64(&cdb[2]);
- passthrough = (dev->transport->transport_type ==
- TRANSPORT_PLUGIN_PHBA_PDEV);
- /*
- * Determine if the received WRITE_SAME_16 is used to for direct
- * passthrough into Linux/SCSI with struct request via TCM/pSCSI
- * or we are signaling the use of internal WRITE_SAME + UNMAP=1
- * emulation for -> Linux/BLOCK disbard with TCM/IBLOCK and
- * TCM/FILEIO subsystem plugin backstores.
- */
- if (!passthrough) {
- if ((cdb[1] & 0x04) || (cdb[1] & 0x02)) {
- pr_err("WRITE_SAME PBDATA and LBDATA"
- " bits not supported for Block Discard"
- " Emulation\n");
- goto out_invalid_cdb_field;
- }
- /*
- * Currently for the emulated case we only accept
- * tpws with the UNMAP=1 bit set.
- */
- if (!(cdb[1] & 0x08)) {
- pr_err("WRITE_SAME w/o UNMAP bit not "
- " supported for Block Discard Emulation\n");
- goto out_invalid_cdb_field;
- }
- }
cmd->se_cmd_flags |= SCF_SCSI_CONTROL_SG_IO_CDB;
+
+ if (target_check_write_same_discard(&cdb[1], dev) < 0)
+ goto out_invalid_cdb_field;
+ break;
+ case WRITE_SAME:
+ sectors = transport_get_sectors_10(cdb, cmd, §or_ret);
+ if (sector_ret)
+ goto out_unsupported_cdb;
+
+ if (sectors)
+ size = transport_get_size(1, cdb, cmd);
+ else {
+ pr_err("WSNZ=1, WRITE_SAME w/sectors=0 not supported\n");
+ goto out_invalid_cdb_field;
+ }
+
+ cmd->t_task_lba = get_unaligned_be32(&cdb[2]);
+ cmd->se_cmd_flags |= SCF_SCSI_CONTROL_SG_IO_CDB;
+ /*
+ * Follow sbcr26 with WRITE_SAME (10) and check for the existence
+ * of byte 1 bit 3 UNMAP instead of original reserved field
+ */
+ if (target_check_write_same_discard(&cdb[1], dev) < 0)
+ goto out_invalid_cdb_field;
break;
case ALLOW_MEDIUM_REMOVAL:
case GPCMD_CLOSE_TRACK:
@@ -3873,9 +3892,7 @@
static int transport_new_cmd_obj(struct se_cmd *cmd)
{
struct se_device *dev = cmd->se_dev;
- u32 task_cdbs;
- u32 rc;
- int set_counts = 1;
+ int set_counts = 1, rc, task_cdbs;
/*
* Setup any BIDI READ tasks and memory from
@@ -3893,7 +3910,7 @@
cmd->se_cmd_flags |= SCF_SCSI_CDB_EXCEPTION;
cmd->scsi_sense_reason =
TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;
- return PYX_TRANSPORT_LU_COMM_FAILURE;
+ return -EINVAL;
}
atomic_inc(&cmd->t_fe_count);
atomic_inc(&cmd->t_se_count);
@@ -3912,7 +3929,7 @@
cmd->se_cmd_flags |= SCF_SCSI_CDB_EXCEPTION;
cmd->scsi_sense_reason =
TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;
- return PYX_TRANSPORT_LU_COMM_FAILURE;
+ return -EINVAL;
}
if (set_counts) {
@@ -4028,8 +4045,6 @@
if (!task->task_sg)
continue;
- BUG_ON(!task->task_padded_sg);
-
if (!sg_first) {
sg_first = task->task_sg;
chained_nents = task->task_sg_nents;
@@ -4037,9 +4052,19 @@
sg_chain(sg_prev, sg_prev_nents, task->task_sg);
chained_nents += task->task_sg_nents;
}
+ /*
+ * For the padded tasks, use the extra SGL vector allocated
+ * in transport_allocate_data_tasks() for the sg_prev_nents
+ * offset into sg_chain() above.. The last task of a
+ * multi-task list, or a single task will not have
+ * task->task_sg_padded set..
+ */
+ if (task->task_padded_sg)
+ sg_prev_nents = (task->task_sg_nents + 1);
+ else
+ sg_prev_nents = task->task_sg_nents;
sg_prev = task->task_sg;
- sg_prev_nents = task->task_sg_nents;
}
/*
* Setup the starting pointer and total t_tasks_sg_linked_no including
@@ -4091,7 +4116,7 @@
cmd_sg = sgl;
for (i = 0; i < task_count; i++) {
- unsigned int task_size;
+ unsigned int task_size, task_sg_nents_padded;
int count;
task = transport_generic_get_task(cmd, data_direction);
@@ -4110,30 +4135,33 @@
/* Update new cdb with updated lba/sectors */
cmd->transport_split_cdb(task->task_lba, task->task_sectors, cdb);
-
+ /*
+ * This now assumes that passed sg_ents are in PAGE_SIZE chunks
+ * in order to calculate the number per task SGL entries
+ */
+ task->task_sg_nents = DIV_ROUND_UP(task->task_size, PAGE_SIZE);
/*
* Check if the fabric module driver is requesting that all
* struct se_task->task_sg[] be chained together.. If so,
* then allocate an extra padding SG entry for linking and
- * marking the end of the chained SGL.
- * Possibly over-allocate task sgl size by using cmd sgl size.
- * It's so much easier and only a waste when task_count > 1.
- * That is extremely rare.
+ * marking the end of the chained SGL for every task except
+ * the last one for (task_count > 1) operation, or skipping
+ * the extra padding for the (task_count == 1) case.
*/
- task->task_sg_nents = sgl_nents;
- if (cmd->se_tfo->task_sg_chaining) {
- task->task_sg_nents++;
+ if (cmd->se_tfo->task_sg_chaining && (i < (task_count - 1))) {
+ task_sg_nents_padded = (task->task_sg_nents + 1);
task->task_padded_sg = 1;
- }
+ } else
+ task_sg_nents_padded = task->task_sg_nents;
task->task_sg = kmalloc(sizeof(struct scatterlist) *
- task->task_sg_nents, GFP_KERNEL);
+ task_sg_nents_padded, GFP_KERNEL);
if (!task->task_sg) {
cmd->se_dev->transport->free_task(task);
return -ENOMEM;
}
- sg_init_table(task->task_sg, task->task_sg_nents);
+ sg_init_table(task->task_sg, task_sg_nents_padded);
task_size = task->task_size;
@@ -4230,10 +4258,13 @@
struct scatterlist *sgl,
unsigned int sgl_nents)
{
- if (cmd->se_cmd_flags & SCF_SCSI_DATA_SG_IO_CDB)
+ if (cmd->se_cmd_flags & SCF_SCSI_DATA_SG_IO_CDB) {
+ if (transport_cmd_get_valid_sectors(cmd) < 0)
+ return -EINVAL;
+
return transport_allocate_data_tasks(cmd, lba, data_direction,
sgl, sgl_nents);
- else
+ } else
return transport_allocate_control_task(cmd);
}
@@ -4726,6 +4757,13 @@
*/
switch (reason) {
case TCM_NON_EXISTENT_LUN:
+ /* CURRENT ERROR */
+ buffer[offset] = 0x70;
+ /* ILLEGAL REQUEST */
+ buffer[offset+SPC_SENSE_KEY_OFFSET] = ILLEGAL_REQUEST;
+ /* LOGICAL UNIT NOT SUPPORTED */
+ buffer[offset+SPC_ASC_KEY_OFFSET] = 0x25;
+ break;
case TCM_UNSUPPORTED_SCSI_OPCODE:
case TCM_SECTOR_COUNT_TOO_MANY:
/* CURRENT ERROR */
diff --git a/drivers/target/tcm_fc/tfc_conf.c b/drivers/target/tcm_fc/tfc_conf.c
index 8781d1e..b15879d 100644
--- a/drivers/target/tcm_fc/tfc_conf.c
+++ b/drivers/target/tcm_fc/tfc_conf.c
@@ -256,7 +256,7 @@
struct se_portal_group *se_tpg = &tpg->se_tpg;
struct se_node_acl *se_acl;
- spin_lock_bh(&se_tpg->acl_node_lock);
+ spin_lock_irq(&se_tpg->acl_node_lock);
list_for_each_entry(se_acl, &se_tpg->acl_node_list, acl_list) {
acl = container_of(se_acl, struct ft_node_acl, se_node_acl);
pr_debug("acl %p port_name %llx\n",
@@ -270,7 +270,7 @@
break;
}
}
- spin_unlock_bh(&se_tpg->acl_node_lock);
+ spin_unlock_irq(&se_tpg->acl_node_lock);
return found;
}
@@ -655,9 +655,7 @@
synchronize_rcu();
}
-#ifdef MODULE
MODULE_DESCRIPTION("FC TCM fabric driver " FT_VERSION);
MODULE_LICENSE("GPL");
module_init(ft_init);
module_exit(ft_exit);
-#endif /* MODULE */
diff --git a/drivers/tty/pty.c b/drivers/tty/pty.c
index 98b6e3b..e809e9d 100644
--- a/drivers/tty/pty.c
+++ b/drivers/tty/pty.c
@@ -446,8 +446,19 @@
int pty_limit = NR_UNIX98_PTY_DEFAULT;
static int pty_limit_min;
static int pty_limit_max = NR_UNIX98_PTY_MAX;
+static int tty_count;
static int pty_count;
+static inline void pty_inc_count(void)
+{
+ pty_count = (++tty_count) / 2;
+}
+
+static inline void pty_dec_count(void)
+{
+ pty_count = (--tty_count) / 2;
+}
+
static struct cdev ptmx_cdev;
static struct ctl_table pty_table[] = {
@@ -542,6 +553,7 @@
static void pty_unix98_shutdown(struct tty_struct *tty)
{
+ tty_driver_remove_tty(tty->driver, tty);
/* We have our own method as we don't use the tty index */
kfree(tty->termios);
}
@@ -588,7 +600,8 @@
*/
tty_driver_kref_get(driver);
tty->count++;
- pty_count++;
+ pty_inc_count(); /* tty */
+ pty_inc_count(); /* tty->link */
return 0;
err_free_mem:
deinitialize_tty_struct(o_tty);
@@ -602,7 +615,7 @@
static void pty_unix98_remove(struct tty_driver *driver, struct tty_struct *tty)
{
- pty_count--;
+ pty_dec_count();
}
static const struct tty_operations ptm_unix98_ops = {
diff --git a/drivers/tty/serial/8250.c b/drivers/tty/serial/8250.c
index f2dfec8..7f50999 100644
--- a/drivers/tty/serial/8250.c
+++ b/drivers/tty/serial/8250.c
@@ -1819,6 +1819,8 @@
unsigned int iir, ier = 0, lsr;
unsigned long flags;
+ spin_lock_irqsave(&up->port.lock, flags);
+
/*
* Must disable interrupts or else we risk racing with the interrupt
* based handler.
@@ -1836,10 +1838,8 @@
* the "Diva" UART used on the management processor on many HP
* ia64 and parisc boxes.
*/
- spin_lock_irqsave(&up->port.lock, flags);
lsr = serial_in(up, UART_LSR);
up->lsr_saved_flags |= lsr & LSR_SAVE_FLAGS;
- spin_unlock_irqrestore(&up->port.lock, flags);
if ((iir & UART_IIR_NO_INT) && (up->ier & UART_IER_THRI) &&
(!uart_circ_empty(&up->port.state->xmit) || up->port.x_char) &&
(lsr & UART_LSR_THRE)) {
@@ -1848,11 +1848,13 @@
}
if (!(iir & UART_IIR_NO_INT))
- serial8250_handle_port(up);
+ transmit_chars(up);
if (is_real_interrupt(up->port.irq))
serial_out(up, UART_IER, ier);
+ spin_unlock_irqrestore(&up->port.lock, flags);
+
/* Standard timer interval plus 0.2s to keep the port running */
mod_timer(&up->timer,
jiffies + uart_poll_timeout(&up->port) + HZ / 5);
diff --git a/drivers/tty/serial/8250_pci.c b/drivers/tty/serial/8250_pci.c
index 6b887d9..3abeca2 100644
--- a/drivers/tty/serial/8250_pci.c
+++ b/drivers/tty/serial/8250_pci.c
@@ -1599,11 +1599,6 @@
.device = 0x800D,
.init = pci_eg20t_init,
},
- {
- .vendor = 0x10DB,
- .device = 0x800D,
- .init = pci_eg20t_init,
- },
/*
* Cronyx Omega PCI (PLX-chip based)
*/
@@ -4021,7 +4016,7 @@
0, 0, pbn_NETMOS9900_2s_115200 },
/*
- * Best Connectivity PCI Multi I/O cards
+ * Best Connectivity and Rosewill PCI Multi I/O cards
*/
{ PCI_VENDOR_ID_NETMOS, PCI_DEVICE_ID_NETMOS_9865,
@@ -4029,6 +4024,10 @@
0, 0, pbn_b0_1_115200 },
{ PCI_VENDOR_ID_NETMOS, PCI_DEVICE_ID_NETMOS_9865,
+ 0xA000, 0x3002,
+ 0, 0, pbn_b0_bt_2_115200 },
+
+ { PCI_VENDOR_ID_NETMOS, PCI_DEVICE_ID_NETMOS_9865,
0xA000, 0x3004,
0, 0, pbn_b0_bt_4_115200 },
/* Intel CE4100 */
diff --git a/drivers/tty/serial/8250_pnp.c b/drivers/tty/serial/8250_pnp.c
index fc301f6..a2f2365 100644
--- a/drivers/tty/serial/8250_pnp.c
+++ b/drivers/tty/serial/8250_pnp.c
@@ -109,6 +109,9 @@
/* IBM */
/* IBM Thinkpad 701 Internal Modem Voice */
{ "IBM0033", 0 },
+ /* Intermec */
+ /* Intermec CV60 touchscreen port */
+ { "PNP4972", 0 },
/* Intertex */
/* Intertex 28k8 33k6 Voice EXT PnP */
{ "IXDC801", 0 },
diff --git a/drivers/tty/serial/atmel_serial.c b/drivers/tty/serial/atmel_serial.c
index af9b781..b922f5d 100644
--- a/drivers/tty/serial/atmel_serial.c
+++ b/drivers/tty/serial/atmel_serial.c
@@ -1609,9 +1609,11 @@
static int __init atmel_console_init(void)
{
if (atmel_default_console_device) {
- add_preferred_console(ATMEL_DEVICENAME,
- atmel_default_console_device->id, NULL);
- atmel_init_port(&atmel_ports[atmel_default_console_device->id],
+ struct atmel_uart_data *pdata =
+ atmel_default_console_device->dev.platform_data;
+
+ add_preferred_console(ATMEL_DEVICENAME, pdata->num, NULL);
+ atmel_init_port(&atmel_ports[pdata->num],
atmel_default_console_device);
register_console(&atmel_console);
}
diff --git a/drivers/tty/serial/max3107-aava.c b/drivers/tty/serial/max3107-aava.c
index a1fe304..d73aadd 100644
--- a/drivers/tty/serial/max3107-aava.c
+++ b/drivers/tty/serial/max3107-aava.c
@@ -340,5 +340,5 @@
MODULE_DESCRIPTION("MAX3107 driver");
MODULE_AUTHOR("Aavamobile");
-MODULE_ALIAS("aava-max3107-spi");
+MODULE_ALIAS("spi:aava-max3107");
MODULE_LICENSE("GPL v2");
diff --git a/drivers/tty/serial/max3107.c b/drivers/tty/serial/max3107.c
index 750b4f6..a816460 100644
--- a/drivers/tty/serial/max3107.c
+++ b/drivers/tty/serial/max3107.c
@@ -1209,5 +1209,5 @@
MODULE_DESCRIPTION("MAX3107 driver");
MODULE_AUTHOR("Aavamobile");
-MODULE_ALIAS("max3107-spi");
+MODULE_ALIAS("spi:max3107");
MODULE_LICENSE("GPL v2");
diff --git a/drivers/tty/serial/mrst_max3110.c b/drivers/tty/serial/mrst_max3110.c
index a764bf9..23bc743 100644
--- a/drivers/tty/serial/mrst_max3110.c
+++ b/drivers/tty/serial/mrst_max3110.c
@@ -917,4 +917,4 @@
module_exit(serial_m3110_exit);
MODULE_LICENSE("GPL v2");
-MODULE_ALIAS("max3110-uart");
+MODULE_ALIAS("spi:max3110-uart");
diff --git a/drivers/tty/serial/omap-serial.c b/drivers/tty/serial/omap-serial.c
index c37df8d..5e713d3 100644
--- a/drivers/tty/serial/omap-serial.c
+++ b/drivers/tty/serial/omap-serial.c
@@ -806,8 +806,7 @@
serial_omap_set_mctrl(&up->port, up->port.mctrl);
/* Software Flow Control Configuration */
- if (termios->c_iflag & (IXON | IXOFF))
- serial_omap_configure_xonxoff(up, termios);
+ serial_omap_configure_xonxoff(up, termios);
spin_unlock_irqrestore(&up->port.lock, flags);
dev_dbg(up->port.dev, "serial_omap_set_termios+%d\n", up->pdev->id);
diff --git a/drivers/tty/serial/pch_uart.c b/drivers/tty/serial/pch_uart.c
index 846dfcd..b46218d 100644
--- a/drivers/tty/serial/pch_uart.c
+++ b/drivers/tty/serial/pch_uart.c
@@ -598,7 +598,8 @@
dma_cap_zero(mask);
dma_cap_set(DMA_SLAVE, mask);
- dma_dev = pci_get_bus_and_slot(2, PCI_DEVFN(0xa, 0)); /* Get DMA's dev
+ dma_dev = pci_get_bus_and_slot(priv->pdev->bus->number,
+ PCI_DEVFN(0xa, 0)); /* Get DMA's dev
information */
/* Set Tx DMA */
param = &priv->param_tx;
diff --git a/drivers/tty/serial/samsung.c b/drivers/tty/serial/samsung.c
index afc6294..6edafb5 100644
--- a/drivers/tty/serial/samsung.c
+++ b/drivers/tty/serial/samsung.c
@@ -1225,15 +1225,19 @@
.suspend = s3c24xx_serial_suspend,
.resume = s3c24xx_serial_resume,
};
+#define SERIAL_SAMSUNG_PM_OPS (&s3c24xx_serial_pm_ops)
+
#else /* !CONFIG_PM_SLEEP */
-#define s3c24xx_serial_pm_ops NULL
+
+#define SERIAL_SAMSUNG_PM_OPS NULL
#endif /* CONFIG_PM_SLEEP */
int s3c24xx_serial_init(struct platform_driver *drv,
struct s3c24xx_uart_info *info)
{
dbg("s3c24xx_serial_init(%p,%p)\n", drv, info);
- drv->driver.pm = &s3c24xx_serial_pm_ops;
+
+ drv->driver.pm = SERIAL_SAMSUNG_PM_OPS;
return platform_driver_register(drv);
}
diff --git a/drivers/tty/serial/serial_core.c b/drivers/tty/serial/serial_core.c
index db7912c..a3efbea 100644
--- a/drivers/tty/serial/serial_core.c
+++ b/drivers/tty/serial/serial_core.c
@@ -200,6 +200,11 @@
clear_bit(TTY_IO_ERROR, &tty->flags);
}
+ /*
+ * This is to allow setserial on this port. People may want to set
+ * port/irq/type and then reconfigure the port properly if it failed
+ * now.
+ */
if (retval && capable(CAP_SYS_ADMIN))
retval = 0;
diff --git a/drivers/tty/serial/sh-sci.c b/drivers/tty/serial/sh-sci.c
index 2ec57b2..5ea6ec3 100644
--- a/drivers/tty/serial/sh-sci.c
+++ b/drivers/tty/serial/sh-sci.c
@@ -47,6 +47,7 @@
#include <linux/ctype.h>
#include <linux/err.h>
#include <linux/dmaengine.h>
+#include <linux/dma-mapping.h>
#include <linux/scatterlist.h>
#include <linux/slab.h>
@@ -95,6 +96,12 @@
#endif
struct notifier_block freq_transition;
+
+#ifdef CONFIG_SERIAL_SH_SCI_CONSOLE
+ unsigned short saved_smr;
+ unsigned short saved_fcr;
+ unsigned char saved_brr;
+#endif
};
/* Function prototypes */
@@ -1076,7 +1083,7 @@
/* This routine is used for getting signals of: DTR, DCD, DSR, RI,
and CTS/RTS */
- return TIOCM_DTR | TIOCM_RTS | TIOCM_DSR;
+ return TIOCM_DTR | TIOCM_RTS | TIOCM_CTS | TIOCM_DSR;
}
#ifdef CONFIG_SERIAL_SH_SCI_DMA
@@ -1633,11 +1640,25 @@
return ((freq + 16 * bps) / (32 * bps) - 1);
}
+static void sci_reset(struct uart_port *port)
+{
+ unsigned int status;
+
+ do {
+ status = sci_in(port, SCxSR);
+ } while (!(status & SCxSR_TEND(port)));
+
+ sci_out(port, SCSCR, 0x00); /* TE=0, RE=0, CKE1=0 */
+
+ if (port->type != PORT_SCI)
+ sci_out(port, SCFCR, SCFCR_RFRST | SCFCR_TFRST);
+}
+
static void sci_set_termios(struct uart_port *port, struct ktermios *termios,
struct ktermios *old)
{
struct sci_port *s = to_sci_port(port);
- unsigned int status, baud, smr_val, max_baud;
+ unsigned int baud, smr_val, max_baud;
int t = -1;
u16 scfcr = 0;
@@ -1657,14 +1678,7 @@
sci_port_enable(s);
- do {
- status = sci_in(port, SCxSR);
- } while (!(status & SCxSR_TEND(port)));
-
- sci_out(port, SCSCR, 0x00); /* TE=0, RE=0, CKE1=0 */
-
- if (port->type != PORT_SCI)
- sci_out(port, SCFCR, scfcr | SCFCR_RFRST | SCFCR_TFRST);
+ sci_reset(port);
smr_val = sci_in(port, SCSMR) & 3;
@@ -1913,6 +1927,7 @@
port->dev = &dev->dev;
+ pm_runtime_irq_safe(&dev->dev);
pm_runtime_enable(&dev->dev);
}
@@ -2036,7 +2051,8 @@
if (options)
uart_parse_options(options, &baud, &parity, &bits, &flow);
- /* TODO: disable clock */
+ sci_port_disable(sci_port);
+
return uart_set_options(port, co, baud, parity, bits, flow);
}
@@ -2079,6 +2095,36 @@
return 0;
}
+#define uart_console(port) ((port)->cons->index == (port)->line)
+
+static int sci_runtime_suspend(struct device *dev)
+{
+ struct sci_port *sci_port = dev_get_drvdata(dev);
+ struct uart_port *port = &sci_port->port;
+
+ if (uart_console(port)) {
+ sci_port->saved_smr = sci_in(port, SCSMR);
+ sci_port->saved_brr = sci_in(port, SCBRR);
+ sci_port->saved_fcr = sci_in(port, SCFCR);
+ }
+ return 0;
+}
+
+static int sci_runtime_resume(struct device *dev)
+{
+ struct sci_port *sci_port = dev_get_drvdata(dev);
+ struct uart_port *port = &sci_port->port;
+
+ if (uart_console(port)) {
+ sci_reset(port);
+ sci_out(port, SCSMR, sci_port->saved_smr);
+ sci_out(port, SCBRR, sci_port->saved_brr);
+ sci_out(port, SCFCR, sci_port->saved_fcr);
+ sci_out(port, SCSCR, sci_port->cfg->scscr);
+ }
+ return 0;
+}
+
#define SCI_CONSOLE (&serial_console)
#else
@@ -2088,6 +2134,8 @@
}
#define SCI_CONSOLE NULL
+#define sci_runtime_suspend NULL
+#define sci_runtime_resume NULL
#endif /* CONFIG_SERIAL_SH_SCI_CONSOLE */
@@ -2203,6 +2251,8 @@
}
static const struct dev_pm_ops sci_dev_pm_ops = {
+ .runtime_suspend = sci_runtime_suspend,
+ .runtime_resume = sci_runtime_resume,
.suspend = sci_suspend,
.resume = sci_resume,
};
diff --git a/drivers/tty/serial/ucc_uart.c b/drivers/tty/serial/ucc_uart.c
index c327218..9af9f08 100644
--- a/drivers/tty/serial/ucc_uart.c
+++ b/drivers/tty/serial/ucc_uart.c
@@ -235,7 +235,7 @@
return qe_port->bd_virt + (addr - qe_port->bd_dma_addr);
/* something nasty happened */
- printk(KERN_ERR "%s: addr=%x\n", __func__, addr);
+ printk(KERN_ERR "%s: addr=%llx\n", __func__, (u64)addr);
BUG();
return NULL;
}
diff --git a/drivers/tty/tty_io.c b/drivers/tty/tty_io.c
index 150e4f7..4f1fc81 100644
--- a/drivers/tty/tty_io.c
+++ b/drivers/tty/tty_io.c
@@ -1295,8 +1295,7 @@
*
* Locking: tty_mutex for now
*/
-static void tty_driver_remove_tty(struct tty_driver *driver,
- struct tty_struct *tty)
+void tty_driver_remove_tty(struct tty_driver *driver, struct tty_struct *tty)
{
if (driver->ops->remove)
driver->ops->remove(driver, tty);
diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c
index 8669ba3..73cbbd8 100644
--- a/drivers/usb/core/hcd.c
+++ b/drivers/usb/core/hcd.c
@@ -1775,6 +1775,8 @@
struct usb_interface *iface = usb_ifnum_to_if(udev,
cur_alt->desc.bInterfaceNumber);
+ if (!iface)
+ return -EINVAL;
if (iface->resetting_device) {
/*
* The USB core just reset the device, so the xHCI host
diff --git a/drivers/usb/gadget/f_phonet.c b/drivers/usb/gadget/f_phonet.c
index 8f8d3f6..8f3eab1 100644
--- a/drivers/usb/gadget/f_phonet.c
+++ b/drivers/usb/gadget/f_phonet.c
@@ -434,6 +434,7 @@
config_ep_by_speed(gadget, f, fp->out_ep)) {
fp->in_ep->desc = NULL;
fp->out_ep->desc = NULL;
+ spin_unlock(&port->lock);
return -EINVAL;
}
usb_ep_enable(fp->out_ep);
diff --git a/drivers/usb/host/ehci-hub.c b/drivers/usb/host/ehci-hub.c
index e051b30..4c32cb1 100644
--- a/drivers/usb/host/ehci-hub.c
+++ b/drivers/usb/host/ehci-hub.c
@@ -343,7 +343,7 @@
u32 temp;
u32 power_okay;
int i;
- u8 resume_needed = 0;
+ unsigned long resume_needed = 0;
if (time_before (jiffies, ehci->next_statechange))
msleep(5);
@@ -416,7 +416,7 @@
if (test_bit(i, &ehci->bus_suspended) &&
(temp & PORT_SUSPEND)) {
temp |= PORT_RESUME;
- resume_needed = 1;
+ set_bit(i, &resume_needed);
}
ehci_writel(ehci, temp, &ehci->regs->port_status [i]);
}
@@ -431,8 +431,7 @@
i = HCS_N_PORTS (ehci->hcs_params);
while (i--) {
temp = ehci_readl(ehci, &ehci->regs->port_status [i]);
- if (test_bit(i, &ehci->bus_suspended) &&
- (temp & PORT_SUSPEND)) {
+ if (test_bit(i, &resume_needed)) {
temp &= ~(PORT_RWC_BITS | PORT_RESUME);
ehci_writel(ehci, temp, &ehci->regs->port_status [i]);
ehci_vdbg (ehci, "resumed port %d\n", i + 1);
diff --git a/drivers/usb/host/ehci-s5p.c b/drivers/usb/host/ehci-s5p.c
index b3958b3..9e77f1c 100644
--- a/drivers/usb/host/ehci-s5p.c
+++ b/drivers/usb/host/ehci-s5p.c
@@ -86,6 +86,7 @@
goto fail_hcd;
}
+ s5p_ehci->hcd = hcd;
s5p_ehci->clk = clk_get(&pdev->dev, "usbhost");
if (IS_ERR(s5p_ehci->clk)) {
diff --git a/drivers/usb/host/xhci-hub.c b/drivers/usb/host/xhci-hub.c
index 0be788c..1e96d1f 100644
--- a/drivers/usb/host/xhci-hub.c
+++ b/drivers/usb/host/xhci-hub.c
@@ -463,11 +463,12 @@
&& (temp & PORT_POWER))
status |= USB_PORT_STAT_SUSPEND;
}
- if ((temp & PORT_PLS_MASK) == XDEV_RESUME) {
+ if ((temp & PORT_PLS_MASK) == XDEV_RESUME &&
+ !DEV_SUPERSPEED(temp)) {
if ((temp & PORT_RESET) || !(temp & PORT_PE))
goto error;
- if (!DEV_SUPERSPEED(temp) && time_after_eq(jiffies,
- bus_state->resume_done[wIndex])) {
+ if (time_after_eq(jiffies,
+ bus_state->resume_done[wIndex])) {
xhci_dbg(xhci, "Resume USB2 port %d\n",
wIndex + 1);
bus_state->resume_done[wIndex] = 0;
@@ -487,6 +488,14 @@
xhci_ring_device(xhci, slot_id);
bus_state->port_c_suspend |= 1 << wIndex;
bus_state->suspended_ports &= ~(1 << wIndex);
+ } else {
+ /*
+ * The resume has been signaling for less than
+ * 20ms. Report the port status as SUSPEND,
+ * let the usbcore check port status again
+ * and clear resume signaling later.
+ */
+ status |= USB_PORT_STAT_SUSPEND;
}
}
if ((temp & PORT_PLS_MASK) == XDEV_U0
@@ -664,7 +673,7 @@
xhci_dbg(xhci, "PORTSC %04x\n", temp);
if (temp & PORT_RESET)
goto error;
- if (temp & XDEV_U3) {
+ if ((temp & PORT_PLS_MASK) == XDEV_U3) {
if ((temp & PORT_PE) == 0)
goto error;
diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c
index 7113d16..54139a2 100644
--- a/drivers/usb/host/xhci-ring.c
+++ b/drivers/usb/host/xhci-ring.c
@@ -514,8 +514,12 @@
(unsigned long long) addr);
}
+/* flip_cycle means flip the cycle bit of all but the first and last TRB.
+ * (The last TRB actually points to the ring enqueue pointer, which is not part
+ * of this TD.) This is used to remove partially enqueued isoc TDs from a ring.
+ */
static void td_to_noop(struct xhci_hcd *xhci, struct xhci_ring *ep_ring,
- struct xhci_td *cur_td)
+ struct xhci_td *cur_td, bool flip_cycle)
{
struct xhci_segment *cur_seg;
union xhci_trb *cur_trb;
@@ -528,6 +532,12 @@
* leave the pointers intact.
*/
cur_trb->generic.field[3] &= cpu_to_le32(~TRB_CHAIN);
+ /* Flip the cycle bit (link TRBs can't be the first
+ * or last TRB).
+ */
+ if (flip_cycle)
+ cur_trb->generic.field[3] ^=
+ cpu_to_le32(TRB_CYCLE);
xhci_dbg(xhci, "Cancel (unchain) link TRB\n");
xhci_dbg(xhci, "Address = %p (0x%llx dma); "
"in seg %p (0x%llx dma)\n",
@@ -541,6 +551,11 @@
cur_trb->generic.field[2] = 0;
/* Preserve only the cycle bit of this TRB */
cur_trb->generic.field[3] &= cpu_to_le32(TRB_CYCLE);
+ /* Flip the cycle bit except on the first or last TRB */
+ if (flip_cycle && cur_trb != cur_td->first_trb &&
+ cur_trb != cur_td->last_trb)
+ cur_trb->generic.field[3] ^=
+ cpu_to_le32(TRB_CYCLE);
cur_trb->generic.field[3] |= cpu_to_le32(
TRB_TYPE(TRB_TR_NOOP));
xhci_dbg(xhci, "Cancel TRB %p (0x%llx dma) "
@@ -719,14 +734,14 @@
cur_td->urb->stream_id,
cur_td, &deq_state);
else
- td_to_noop(xhci, ep_ring, cur_td);
+ td_to_noop(xhci, ep_ring, cur_td, false);
remove_finished_td:
/*
* The event handler won't see a completion for this TD anymore,
* so remove it from the endpoint ring's TD list. Keep it in
* the cancelled TD list for URB completion later.
*/
- list_del(&cur_td->td_list);
+ list_del_init(&cur_td->td_list);
}
last_unlinked_td = cur_td;
xhci_stop_watchdog_timer_in_irq(xhci, ep);
@@ -754,7 +769,7 @@
do {
cur_td = list_entry(ep->cancelled_td_list.next,
struct xhci_td, cancelled_td_list);
- list_del(&cur_td->cancelled_td_list);
+ list_del_init(&cur_td->cancelled_td_list);
/* Clean up the cancelled URB */
/* Doesn't matter what we pass for status, since the core will
@@ -862,9 +877,9 @@
cur_td = list_first_entry(&ring->td_list,
struct xhci_td,
td_list);
- list_del(&cur_td->td_list);
+ list_del_init(&cur_td->td_list);
if (!list_empty(&cur_td->cancelled_td_list))
- list_del(&cur_td->cancelled_td_list);
+ list_del_init(&cur_td->cancelled_td_list);
xhci_giveback_urb_in_irq(xhci, cur_td,
-ESHUTDOWN, "killed");
}
@@ -873,7 +888,7 @@
&temp_ep->cancelled_td_list,
struct xhci_td,
cancelled_td_list);
- list_del(&cur_td->cancelled_td_list);
+ list_del_init(&cur_td->cancelled_td_list);
xhci_giveback_urb_in_irq(xhci, cur_td,
-ESHUTDOWN, "killed");
}
@@ -1565,10 +1580,10 @@
else
*status = 0;
}
- list_del(&td->td_list);
+ list_del_init(&td->td_list);
/* Was this TD slated to be cancelled but completed anyway? */
if (!list_empty(&td->cancelled_td_list))
- list_del(&td->cancelled_td_list);
+ list_del_init(&td->cancelled_td_list);
urb_priv->td_cnt++;
/* Giveback the urb when all the tds are completed */
@@ -2500,11 +2515,8 @@
if (td_index == 0) {
ret = usb_hcd_link_urb_to_ep(bus_to_hcd(urb->dev->bus), urb);
- if (unlikely(ret)) {
- xhci_urb_free_priv(xhci, urb_priv);
- urb->hcpriv = NULL;
+ if (unlikely(ret))
return ret;
- }
}
td->urb = urb;
@@ -2672,6 +2684,10 @@
{
int packets_transferred;
+ /* One TRB with a zero-length data packet. */
+ if (running_total == 0 && trb_buff_len == 0)
+ return 0;
+
/* All the TRB queueing functions don't count the current TRB in
* running_total.
*/
@@ -3113,21 +3129,16 @@
struct urb *urb, int i)
{
int num_trbs = 0;
- u64 addr, td_len, running_total;
+ u64 addr, td_len;
addr = (u64) (urb->transfer_dma + urb->iso_frame_desc[i].offset);
td_len = urb->iso_frame_desc[i].length;
- running_total = TRB_MAX_BUFF_SIZE - (addr & (TRB_MAX_BUFF_SIZE - 1));
- running_total &= TRB_MAX_BUFF_SIZE - 1;
- if (running_total != 0)
+ num_trbs = DIV_ROUND_UP(td_len + (addr & (TRB_MAX_BUFF_SIZE - 1)),
+ TRB_MAX_BUFF_SIZE);
+ if (num_trbs == 0)
num_trbs++;
- while (running_total < td_len) {
- num_trbs++;
- running_total += TRB_MAX_BUFF_SIZE;
- }
-
return num_trbs;
}
@@ -3226,6 +3237,7 @@
start_trb = &ep_ring->enqueue->generic;
start_cycle = ep_ring->cycle_state;
+ urb_priv = urb->hcpriv;
/* Queue the first TRB, even if it's zero-length */
for (i = 0; i < num_tds; i++) {
unsigned int total_packet_count;
@@ -3237,9 +3249,11 @@
addr = start_addr + urb->iso_frame_desc[i].offset;
td_len = urb->iso_frame_desc[i].length;
td_remain_len = td_len;
- /* FIXME: Ignoring zero-length packets, can those happen? */
total_packet_count = roundup(td_len,
le16_to_cpu(urb->ep->desc.wMaxPacketSize));
+ /* A zero-length transfer still involves at least one packet. */
+ if (total_packet_count == 0)
+ total_packet_count++;
burst_count = xhci_get_burst_count(xhci, urb->dev, urb,
total_packet_count);
residue = xhci_get_last_burst_packet_count(xhci,
@@ -3249,12 +3263,13 @@
ret = prepare_transfer(xhci, xhci->devs[slot_id], ep_index,
urb->stream_id, trbs_per_td, urb, i, mem_flags);
- if (ret < 0)
- return ret;
+ if (ret < 0) {
+ if (i == 0)
+ return ret;
+ goto cleanup;
+ }
- urb_priv = urb->hcpriv;
td = urb_priv->td[i];
-
for (j = 0; j < trbs_per_td; j++) {
u32 remainder = 0;
field = TRB_TBC(burst_count) | TRB_TLBPC(residue);
@@ -3344,6 +3359,27 @@
giveback_first_trb(xhci, slot_id, ep_index, urb->stream_id,
start_cycle, start_trb);
return 0;
+cleanup:
+ /* Clean up a partially enqueued isoc transfer. */
+
+ for (i--; i >= 0; i--)
+ list_del_init(&urb_priv->td[i]->td_list);
+
+ /* Use the first TD as a temporary variable to turn the TDs we've queued
+ * into No-ops with a software-owned cycle bit. That way the hardware
+ * won't accidentally start executing bogus TDs when we partially
+ * overwrite them. td->first_trb and td->start_seg are already set.
+ */
+ urb_priv->td[0]->last_trb = ep_ring->enqueue;
+ /* Every TRB except the first & last will have its cycle bit flipped. */
+ td_to_noop(xhci, ep_ring, urb_priv->td[0], true);
+
+ /* Reset the ring enqueue back to the first TRB and its cycle bit. */
+ ep_ring->enqueue = urb_priv->td[0]->first_trb;
+ ep_ring->enq_seg = urb_priv->td[0]->start_seg;
+ ep_ring->cycle_state = start_cycle;
+ usb_hcd_unlink_urb_from_ep(bus_to_hcd(urb->dev->bus), urb);
+ return ret;
}
/*
diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c
index 1c4432d..3a0f695 100644
--- a/drivers/usb/host/xhci.c
+++ b/drivers/usb/host/xhci.c
@@ -1085,8 +1085,11 @@
if (urb->dev->speed == USB_SPEED_FULL) {
ret = xhci_check_maxpacket(xhci, slot_id,
ep_index, urb);
- if (ret < 0)
+ if (ret < 0) {
+ xhci_urb_free_priv(xhci, urb_priv);
+ urb->hcpriv = NULL;
return ret;
+ }
}
/* We have a spinlock and interrupts disabled, so we must pass
@@ -1097,6 +1100,8 @@
goto dying;
ret = xhci_queue_ctrl_tx(xhci, GFP_ATOMIC, urb,
slot_id, ep_index);
+ if (ret)
+ goto free_priv;
spin_unlock_irqrestore(&xhci->lock, flags);
} else if (usb_endpoint_xfer_bulk(&urb->ep->desc)) {
spin_lock_irqsave(&xhci->lock, flags);
@@ -1117,6 +1122,8 @@
ret = xhci_queue_bulk_tx(xhci, GFP_ATOMIC, urb,
slot_id, ep_index);
}
+ if (ret)
+ goto free_priv;
spin_unlock_irqrestore(&xhci->lock, flags);
} else if (usb_endpoint_xfer_int(&urb->ep->desc)) {
spin_lock_irqsave(&xhci->lock, flags);
@@ -1124,6 +1131,8 @@
goto dying;
ret = xhci_queue_intr_tx(xhci, GFP_ATOMIC, urb,
slot_id, ep_index);
+ if (ret)
+ goto free_priv;
spin_unlock_irqrestore(&xhci->lock, flags);
} else {
spin_lock_irqsave(&xhci->lock, flags);
@@ -1131,18 +1140,22 @@
goto dying;
ret = xhci_queue_isoc_tx_prepare(xhci, GFP_ATOMIC, urb,
slot_id, ep_index);
+ if (ret)
+ goto free_priv;
spin_unlock_irqrestore(&xhci->lock, flags);
}
exit:
return ret;
dying:
- xhci_urb_free_priv(xhci, urb_priv);
- urb->hcpriv = NULL;
xhci_dbg(xhci, "Ep 0x%x: URB %p submitted for "
"non-responsive xHCI host.\n",
urb->ep->desc.bEndpointAddress, urb);
+ ret = -ESHUTDOWN;
+free_priv:
+ xhci_urb_free_priv(xhci, urb_priv);
+ urb->hcpriv = NULL;
spin_unlock_irqrestore(&xhci->lock, flags);
- return -ESHUTDOWN;
+ return ret;
}
/* Get the right ring for the given URB.
@@ -1239,6 +1252,13 @@
if (temp == 0xffffffff || (xhci->xhc_state & XHCI_STATE_HALTED)) {
xhci_dbg(xhci, "HW died, freeing TD.\n");
urb_priv = urb->hcpriv;
+ for (i = urb_priv->td_cnt; i < urb_priv->length; i++) {
+ td = urb_priv->td[i];
+ if (!list_empty(&td->td_list))
+ list_del_init(&td->td_list);
+ if (!list_empty(&td->cancelled_td_list))
+ list_del_init(&td->cancelled_td_list);
+ }
usb_hcd_unlink_urb_from_ep(hcd, urb);
spin_unlock_irqrestore(&xhci->lock, flags);
diff --git a/drivers/usb/musb/blackfin.c b/drivers/usb/musb/blackfin.c
index ae8c396..5e7cfba 100644
--- a/drivers/usb/musb/blackfin.c
+++ b/drivers/usb/musb/blackfin.c
@@ -17,6 +17,7 @@
#include <linux/io.h>
#include <linux/platform_device.h>
#include <linux/dma-mapping.h>
+#include <linux/prefetch.h>
#include <asm/cacheflush.h>
diff --git a/drivers/usb/musb/cppi_dma.c b/drivers/usb/musb/cppi_dma.c
index 149f3f3..318fb4e 100644
--- a/drivers/usb/musb/cppi_dma.c
+++ b/drivers/usb/musb/cppi_dma.c
@@ -226,8 +226,10 @@
struct cppi *controller;
void __iomem *tibase;
int i;
+ struct musb *musb;
controller = container_of(c, struct cppi, controller);
+ musb = controller->musb;
tibase = controller->tibase;
/* DISABLE INDIVIDUAL CHANNEL Interrupts */
@@ -289,9 +291,11 @@
u8 index;
struct cppi_channel *cppi_ch;
void __iomem *tibase;
+ struct musb *musb;
controller = container_of(c, struct cppi, controller);
tibase = controller->tibase;
+ musb = controller->musb;
/* ep0 doesn't use DMA; remember cppi indices are 0..N-1 */
index = ep->epnum - 1;
@@ -339,7 +343,8 @@
c = container_of(channel, struct cppi_channel, channel);
tibase = c->controller->tibase;
if (!c->hw_ep)
- dev_dbg(musb->controller, "releasing idle DMA channel %p\n", c);
+ dev_dbg(c->controller->musb->controller,
+ "releasing idle DMA channel %p\n", c);
else if (!c->transmit)
core_rxirq_enable(tibase, c->index + 1);
@@ -357,10 +362,11 @@
musb_ep_select(base, c->index + 1);
- DBG(level, "RX DMA%d%s: %d left, csr %04x, "
- "%08x H%08x S%08x C%08x, "
- "B%08x L%08x %08x .. %08x"
- "\n",
+ dev_dbg(c->controller->musb->controller,
+ "RX DMA%d%s: %d left, csr %04x, "
+ "%08x H%08x S%08x C%08x, "
+ "B%08x L%08x %08x .. %08x"
+ "\n",
c->index, tag,
musb_readl(c->controller->tibase,
DAVINCI_RXCPPI_BUFCNT0_REG + 4 * c->index),
@@ -387,10 +393,11 @@
musb_ep_select(base, c->index + 1);
- DBG(level, "TX DMA%d%s: csr %04x, "
- "H%08x S%08x C%08x %08x, "
- "F%08x L%08x .. %08x"
- "\n",
+ dev_dbg(c->controller->musb->controller,
+ "TX DMA%d%s: csr %04x, "
+ "H%08x S%08x C%08x %08x, "
+ "F%08x L%08x .. %08x"
+ "\n",
c->index, tag,
musb_readw(c->hw_ep->regs, MUSB_TXCSR),
@@ -1022,6 +1029,7 @@
int i;
dma_addr_t safe2ack;
void __iomem *regs = rx->hw_ep->regs;
+ struct musb *musb = cppi->musb;
cppi_dump_rx(6, rx, "/K");
diff --git a/drivers/usb/musb/musb_core.h b/drivers/usb/musb/musb_core.h
index 668eeef..b3c065a 100644
--- a/drivers/usb/musb/musb_core.h
+++ b/drivers/usb/musb/musb_core.h
@@ -172,7 +172,8 @@
#endif
/* TUSB mapping: "flat" plus ep0 special cases */
-#if defined(CONFIG_USB_MUSB_TUSB6010)
+#if defined(CONFIG_USB_MUSB_TUSB6010) || \
+ defined(CONFIG_USB_MUSB_TUSB6010_MODULE)
#define musb_ep_select(_mbase, _epnum) \
musb_writeb((_mbase), MUSB_INDEX, (_epnum))
#define MUSB_EP_OFFSET MUSB_TUSB_OFFSET
@@ -241,7 +242,8 @@
void __iomem *fifo;
void __iomem *regs;
-#ifdef CONFIG_USB_MUSB_TUSB6010
+#if defined(CONFIG_USB_MUSB_TUSB6010) || \
+ defined(CONFIG_USB_MUSB_TUSB6010_MODULE)
void __iomem *conf;
#endif
@@ -258,7 +260,8 @@
struct dma_channel *tx_channel;
struct dma_channel *rx_channel;
-#ifdef CONFIG_USB_MUSB_TUSB6010
+#if defined(CONFIG_USB_MUSB_TUSB6010) || \
+ defined(CONFIG_USB_MUSB_TUSB6010_MODULE)
/* TUSB has "asynchronous" and "synchronous" dma modes */
dma_addr_t fifo_async;
dma_addr_t fifo_sync;
@@ -356,7 +359,8 @@
void __iomem *ctrl_base;
void __iomem *mregs;
-#ifdef CONFIG_USB_MUSB_TUSB6010
+#if defined(CONFIG_USB_MUSB_TUSB6010) || \
+ defined(CONFIG_USB_MUSB_TUSB6010_MODULE)
dma_addr_t async;
dma_addr_t sync;
void __iomem *sync_va;
diff --git a/drivers/usb/musb/musb_gadget.c b/drivers/usb/musb/musb_gadget.c
index 8c41a2e..e818203 100644
--- a/drivers/usb/musb/musb_gadget.c
+++ b/drivers/usb/musb/musb_gadget.c
@@ -1856,6 +1856,7 @@
return 0;
err:
+ musb->g.dev.parent = NULL;
device_unregister(&musb->g.dev);
return status;
}
@@ -1863,7 +1864,8 @@
void musb_gadget_cleanup(struct musb *musb)
{
usb_del_gadget_udc(&musb->g);
- device_unregister(&musb->g.dev);
+ if (musb->g.dev.parent)
+ device_unregister(&musb->g.dev);
}
/*
diff --git a/drivers/usb/musb/musb_regs.h b/drivers/usb/musb/musb_regs.h
index 8241070..03f2655 100644
--- a/drivers/usb/musb/musb_regs.h
+++ b/drivers/usb/musb/musb_regs.h
@@ -234,7 +234,8 @@
#define MUSB_TESTMODE 0x0F /* 8 bit */
/* Get offset for a given FIFO from musb->mregs */
-#ifdef CONFIG_USB_MUSB_TUSB6010
+#if defined(CONFIG_USB_MUSB_TUSB6010) || \
+ defined(CONFIG_USB_MUSB_TUSB6010_MODULE)
#define MUSB_FIFO_OFFSET(epnum) (0x200 + ((epnum) * 0x20))
#else
#define MUSB_FIFO_OFFSET(epnum) (0x20 + ((epnum) * 4))
@@ -295,7 +296,8 @@
#define MUSB_FLAT_OFFSET(_epnum, _offset) \
(0x100 + (0x10*(_epnum)) + (_offset))
-#ifdef CONFIG_USB_MUSB_TUSB6010
+#if defined(CONFIG_USB_MUSB_TUSB6010) || \
+ defined(CONFIG_USB_MUSB_TUSB6010_MODULE)
/* TUSB6010 EP0 configuration register is special */
#define MUSB_TUSB_OFFSET(_epnum, _offset) \
(0x10 + _offset)
diff --git a/drivers/usb/musb/tusb6010.c b/drivers/usb/musb/tusb6010.c
index 9eec41f..ec14801 100644
--- a/drivers/usb/musb/tusb6010.c
+++ b/drivers/usb/musb/tusb6010.c
@@ -18,6 +18,7 @@
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/init.h>
+#include <linux/prefetch.h>
#include <linux/usb.h>
#include <linux/irq.h>
#include <linux/platform_device.h>
diff --git a/drivers/usb/musb/tusb6010_omap.c b/drivers/usb/musb/tusb6010_omap.c
index 07c8a73..b67b4bc 100644
--- a/drivers/usb/musb/tusb6010_omap.c
+++ b/drivers/usb/musb/tusb6010_omap.c
@@ -20,6 +20,7 @@
#include <plat/mux.h>
#include "musb_core.h"
+#include "tusb6010.h"
#define to_chdat(c) ((struct tusb_omap_dma_ch *)(c)->private_data)
diff --git a/drivers/usb/musb/ux500_dma.c b/drivers/usb/musb/ux500_dma.c
index cecace4..ef4333f 100644
--- a/drivers/usb/musb/ux500_dma.c
+++ b/drivers/usb/musb/ux500_dma.c
@@ -65,7 +65,8 @@
struct musb *musb = hw_ep->musb;
unsigned long flags;
- DBG(4, "DMA tx transfer done on hw_ep=%d\n", hw_ep->epnum);
+ dev_dbg(musb->controller, "DMA tx transfer done on hw_ep=%d\n",
+ hw_ep->epnum);
spin_lock_irqsave(&musb->lock, flags);
ux500_channel->channel.actual_len = ux500_channel->cur_len;
@@ -84,7 +85,8 @@
struct musb *musb = hw_ep->musb;
unsigned long flags;
- DBG(4, "DMA rx transfer done on hw_ep=%d\n", hw_ep->epnum);
+ dev_dbg(musb->controller, "DMA rx transfer done on hw_ep=%d\n",
+ hw_ep->epnum);
spin_lock_irqsave(&musb->lock, flags);
ux500_channel->channel.actual_len = ux500_channel->cur_len;
@@ -116,9 +118,11 @@
enum dma_slave_buswidth addr_width;
dma_addr_t usb_fifo_addr = (MUSB_FIFO_OFFSET(hw_ep->epnum) +
ux500_channel->controller->phy_base);
+ struct musb *musb = ux500_channel->controller->private_data;
- DBG(4, "packet_sz=%d, mode=%d, dma_addr=0x%x, len=%d is_tx=%d\n",
- packet_sz, mode, dma_addr, len, ux500_channel->is_tx);
+ dev_dbg(musb->controller,
+ "packet_sz=%d, mode=%d, dma_addr=0x%x, len=%d is_tx=%d\n",
+ packet_sz, mode, dma_addr, len, ux500_channel->is_tx);
ux500_channel->cur_len = len;
@@ -133,15 +137,13 @@
DMA_SLAVE_BUSWIDTH_4_BYTES;
slave_conf.direction = direction;
- if (direction == DMA_FROM_DEVICE) {
- slave_conf.src_addr = usb_fifo_addr;
- slave_conf.src_addr_width = addr_width;
- slave_conf.src_maxburst = 16;
- } else {
- slave_conf.dst_addr = usb_fifo_addr;
- slave_conf.dst_addr_width = addr_width;
- slave_conf.dst_maxburst = 16;
- }
+ slave_conf.src_addr = usb_fifo_addr;
+ slave_conf.src_addr_width = addr_width;
+ slave_conf.src_maxburst = 16;
+ slave_conf.dst_addr = usb_fifo_addr;
+ slave_conf.dst_addr_width = addr_width;
+ slave_conf.dst_maxburst = 16;
+
dma_chan->device->device_control(dma_chan, DMA_SLAVE_CONFIG,
(unsigned long) &slave_conf);
@@ -166,6 +168,7 @@
struct ux500_dma_controller *controller = container_of(c,
struct ux500_dma_controller, controller);
struct ux500_dma_channel *ux500_channel = NULL;
+ struct musb *musb = controller->private_data;
u8 ch_num = hw_ep->epnum - 1;
u32 max_ch;
@@ -192,7 +195,7 @@
ux500_channel->hw_ep = hw_ep;
ux500_channel->is_allocated = 1;
- DBG(7, "hw_ep=%d, is_tx=0x%x, channel=%d\n",
+ dev_dbg(musb->controller, "hw_ep=%d, is_tx=0x%x, channel=%d\n",
hw_ep->epnum, is_tx, ch_num);
return &(ux500_channel->channel);
@@ -201,8 +204,9 @@
static void ux500_dma_channel_release(struct dma_channel *channel)
{
struct ux500_dma_channel *ux500_channel = channel->private_data;
+ struct musb *musb = ux500_channel->controller->private_data;
- DBG(7, "channel=%d\n", ux500_channel->ch_num);
+ dev_dbg(musb->controller, "channel=%d\n", ux500_channel->ch_num);
if (ux500_channel->is_allocated) {
ux500_channel->is_allocated = 0;
@@ -252,8 +256,8 @@
void __iomem *epio = musb->endpoints[ux500_channel->hw_ep->epnum].regs;
u16 csr;
- DBG(4, "channel=%d, is_tx=%d\n", ux500_channel->ch_num,
- ux500_channel->is_tx);
+ dev_dbg(musb->controller, "channel=%d, is_tx=%d\n",
+ ux500_channel->ch_num, ux500_channel->is_tx);
if (channel->status == MUSB_DMA_STATUS_BUSY) {
if (ux500_channel->is_tx) {
diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c
index 78a2cf9..5fc13e7 100644
--- a/drivers/usb/serial/ftdi_sio.c
+++ b/drivers/usb/serial/ftdi_sio.c
@@ -101,6 +101,7 @@
static int ftdi_mtxorb_hack_setup(struct usb_serial *serial);
static int ftdi_NDI_device_setup(struct usb_serial *serial);
static int ftdi_stmclite_probe(struct usb_serial *serial);
+static int ftdi_8u2232c_probe(struct usb_serial *serial);
static void ftdi_USB_UIRT_setup(struct ftdi_private *priv);
static void ftdi_HE_TIRA1_setup(struct ftdi_private *priv);
@@ -128,6 +129,10 @@
.probe = ftdi_stmclite_probe,
};
+static struct ftdi_sio_quirk ftdi_8u2232c_quirk = {
+ .probe = ftdi_8u2232c_probe,
+};
+
/*
* The 8U232AM has the same API as the sio except for:
* - it can support MUCH higher baudrates; up to:
@@ -178,7 +183,8 @@
{ USB_DEVICE(FTDI_VID, FTDI_8U232AM_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_8U232AM_ALT_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_232RL_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_8U2232C_PID) },
+ { USB_DEVICE(FTDI_VID, FTDI_8U2232C_PID) ,
+ .driver_info = (kernel_ulong_t)&ftdi_8u2232c_quirk },
{ USB_DEVICE(FTDI_VID, FTDI_4232H_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_232H_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_MICRO_CHAMELEON_PID) },
@@ -1737,6 +1743,18 @@
return 0;
}
+static int ftdi_8u2232c_probe(struct usb_serial *serial)
+{
+ struct usb_device *udev = serial->dev;
+
+ dbg("%s", __func__);
+
+ if (strcmp(udev->manufacturer, "CALAO Systems") == 0)
+ return ftdi_jtag_probe(serial);
+
+ return 0;
+}
+
/*
* First and second port on STMCLiteadaptors is reserved for JTAG interface
* and the forth port for pio
diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c
index 8156561..fe22e90 100644
--- a/drivers/usb/serial/option.c
+++ b/drivers/usb/serial/option.c
@@ -148,6 +148,8 @@
#define HUAWEI_PRODUCT_K4505 0x1464
#define HUAWEI_PRODUCT_K3765 0x1465
#define HUAWEI_PRODUCT_E14AC 0x14AC
+#define HUAWEI_PRODUCT_K3806 0x14AE
+#define HUAWEI_PRODUCT_K4605 0x14C6
#define HUAWEI_PRODUCT_K3770 0x14C9
#define HUAWEI_PRODUCT_K3771 0x14CA
#define HUAWEI_PRODUCT_K4510 0x14CB
@@ -416,6 +418,56 @@
#define SAMSUNG_VENDOR_ID 0x04e8
#define SAMSUNG_PRODUCT_GT_B3730 0x6889
+/* YUGA products www.yuga-info.com*/
+#define YUGA_VENDOR_ID 0x257A
+#define YUGA_PRODUCT_CEM600 0x1601
+#define YUGA_PRODUCT_CEM610 0x1602
+#define YUGA_PRODUCT_CEM500 0x1603
+#define YUGA_PRODUCT_CEM510 0x1604
+#define YUGA_PRODUCT_CEM800 0x1605
+#define YUGA_PRODUCT_CEM900 0x1606
+
+#define YUGA_PRODUCT_CEU818 0x1607
+#define YUGA_PRODUCT_CEU816 0x1608
+#define YUGA_PRODUCT_CEU828 0x1609
+#define YUGA_PRODUCT_CEU826 0x160A
+#define YUGA_PRODUCT_CEU518 0x160B
+#define YUGA_PRODUCT_CEU516 0x160C
+#define YUGA_PRODUCT_CEU528 0x160D
+#define YUGA_PRODUCT_CEU526 0x160F
+
+#define YUGA_PRODUCT_CWM600 0x2601
+#define YUGA_PRODUCT_CWM610 0x2602
+#define YUGA_PRODUCT_CWM500 0x2603
+#define YUGA_PRODUCT_CWM510 0x2604
+#define YUGA_PRODUCT_CWM800 0x2605
+#define YUGA_PRODUCT_CWM900 0x2606
+
+#define YUGA_PRODUCT_CWU718 0x2607
+#define YUGA_PRODUCT_CWU716 0x2608
+#define YUGA_PRODUCT_CWU728 0x2609
+#define YUGA_PRODUCT_CWU726 0x260A
+#define YUGA_PRODUCT_CWU518 0x260B
+#define YUGA_PRODUCT_CWU516 0x260C
+#define YUGA_PRODUCT_CWU528 0x260D
+#define YUGA_PRODUCT_CWU526 0x260F
+
+#define YUGA_PRODUCT_CLM600 0x2601
+#define YUGA_PRODUCT_CLM610 0x2602
+#define YUGA_PRODUCT_CLM500 0x2603
+#define YUGA_PRODUCT_CLM510 0x2604
+#define YUGA_PRODUCT_CLM800 0x2605
+#define YUGA_PRODUCT_CLM900 0x2606
+
+#define YUGA_PRODUCT_CLU718 0x2607
+#define YUGA_PRODUCT_CLU716 0x2608
+#define YUGA_PRODUCT_CLU728 0x2609
+#define YUGA_PRODUCT_CLU726 0x260A
+#define YUGA_PRODUCT_CLU518 0x260B
+#define YUGA_PRODUCT_CLU516 0x260C
+#define YUGA_PRODUCT_CLU528 0x260D
+#define YUGA_PRODUCT_CLU526 0x260F
+
/* some devices interfaces need special handling due to a number of reasons */
enum option_blacklist_reason {
OPTION_BLACKLIST_NONE = 0,
@@ -551,6 +603,8 @@
{ USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_K3765, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_ETS1220, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E14AC, 0xff, 0xff, 0xff) },
+ { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_K3806, 0xff, 0xff, 0xff) },
+ { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_K4605, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_K3770, 0xff, 0x02, 0x31) },
{ USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_K3770, 0xff, 0x02, 0x32) },
{ USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_K3771, 0xff, 0x02, 0x31) },
@@ -1005,6 +1059,48 @@
{ USB_DEVICE(CELOT_VENDOR_ID, CELOT_PRODUCT_CT680M) }, /* CT-650 CDMA 450 1xEVDO modem */
{ USB_DEVICE(ONDA_VENDOR_ID, ONDA_MT825UP) }, /* ONDA MT825UP modem */
{ USB_DEVICE_AND_INTERFACE_INFO(SAMSUNG_VENDOR_ID, SAMSUNG_PRODUCT_GT_B3730, USB_CLASS_CDC_DATA, 0x00, 0x00) }, /* Samsung GT-B3730 LTE USB modem.*/
+ { USB_DEVICE(YUGA_VENDOR_ID, YUGA_PRODUCT_CEM600) },
+ { USB_DEVICE(YUGA_VENDOR_ID, YUGA_PRODUCT_CEM610) },
+ { USB_DEVICE(YUGA_VENDOR_ID, YUGA_PRODUCT_CEM500) },
+ { USB_DEVICE(YUGA_VENDOR_ID, YUGA_PRODUCT_CEM510) },
+ { USB_DEVICE(YUGA_VENDOR_ID, YUGA_PRODUCT_CEM800) },
+ { USB_DEVICE(YUGA_VENDOR_ID, YUGA_PRODUCT_CEM900) },
+ { USB_DEVICE(YUGA_VENDOR_ID, YUGA_PRODUCT_CEU818) },
+ { USB_DEVICE(YUGA_VENDOR_ID, YUGA_PRODUCT_CEU816) },
+ { USB_DEVICE(YUGA_VENDOR_ID, YUGA_PRODUCT_CEU828) },
+ { USB_DEVICE(YUGA_VENDOR_ID, YUGA_PRODUCT_CEU826) },
+ { USB_DEVICE(YUGA_VENDOR_ID, YUGA_PRODUCT_CEU518) },
+ { USB_DEVICE(YUGA_VENDOR_ID, YUGA_PRODUCT_CEU516) },
+ { USB_DEVICE(YUGA_VENDOR_ID, YUGA_PRODUCT_CEU528) },
+ { USB_DEVICE(YUGA_VENDOR_ID, YUGA_PRODUCT_CEU526) },
+ { USB_DEVICE(YUGA_VENDOR_ID, YUGA_PRODUCT_CWM600) },
+ { USB_DEVICE(YUGA_VENDOR_ID, YUGA_PRODUCT_CWM610) },
+ { USB_DEVICE(YUGA_VENDOR_ID, YUGA_PRODUCT_CWM500) },
+ { USB_DEVICE(YUGA_VENDOR_ID, YUGA_PRODUCT_CWM510) },
+ { USB_DEVICE(YUGA_VENDOR_ID, YUGA_PRODUCT_CWM800) },
+ { USB_DEVICE(YUGA_VENDOR_ID, YUGA_PRODUCT_CWM900) },
+ { USB_DEVICE(YUGA_VENDOR_ID, YUGA_PRODUCT_CWU718) },
+ { USB_DEVICE(YUGA_VENDOR_ID, YUGA_PRODUCT_CWU716) },
+ { USB_DEVICE(YUGA_VENDOR_ID, YUGA_PRODUCT_CWU728) },
+ { USB_DEVICE(YUGA_VENDOR_ID, YUGA_PRODUCT_CWU726) },
+ { USB_DEVICE(YUGA_VENDOR_ID, YUGA_PRODUCT_CWU518) },
+ { USB_DEVICE(YUGA_VENDOR_ID, YUGA_PRODUCT_CWU516) },
+ { USB_DEVICE(YUGA_VENDOR_ID, YUGA_PRODUCT_CWU528) },
+ { USB_DEVICE(YUGA_VENDOR_ID, YUGA_PRODUCT_CWU526) },
+ { USB_DEVICE(YUGA_VENDOR_ID, YUGA_PRODUCT_CLM600) },
+ { USB_DEVICE(YUGA_VENDOR_ID, YUGA_PRODUCT_CLM610) },
+ { USB_DEVICE(YUGA_VENDOR_ID, YUGA_PRODUCT_CLM500) },
+ { USB_DEVICE(YUGA_VENDOR_ID, YUGA_PRODUCT_CLM510) },
+ { USB_DEVICE(YUGA_VENDOR_ID, YUGA_PRODUCT_CLM800) },
+ { USB_DEVICE(YUGA_VENDOR_ID, YUGA_PRODUCT_CLM900) },
+ { USB_DEVICE(YUGA_VENDOR_ID, YUGA_PRODUCT_CLU718) },
+ { USB_DEVICE(YUGA_VENDOR_ID, YUGA_PRODUCT_CLU716) },
+ { USB_DEVICE(YUGA_VENDOR_ID, YUGA_PRODUCT_CLU728) },
+ { USB_DEVICE(YUGA_VENDOR_ID, YUGA_PRODUCT_CLU726) },
+ { USB_DEVICE(YUGA_VENDOR_ID, YUGA_PRODUCT_CLU518) },
+ { USB_DEVICE(YUGA_VENDOR_ID, YUGA_PRODUCT_CLU516) },
+ { USB_DEVICE(YUGA_VENDOR_ID, YUGA_PRODUCT_CLU528) },
+ { USB_DEVICE(YUGA_VENDOR_ID, YUGA_PRODUCT_CLU526) },
{ } /* Terminating entry */
};
MODULE_DEVICE_TABLE(usb, option_ids);
@@ -1134,11 +1230,13 @@
serial->interface->cur_altsetting->desc.bInterfaceClass != 0xff)
return -ENODEV;
- /* Don't bind network interfaces on Huawei K3765 & K4505 */
+ /* Don't bind network interfaces on Huawei K3765, K4505 & K4605 */
if (serial->dev->descriptor.idVendor == HUAWEI_VENDOR_ID &&
(serial->dev->descriptor.idProduct == HUAWEI_PRODUCT_K3765 ||
- serial->dev->descriptor.idProduct == HUAWEI_PRODUCT_K4505) &&
- serial->interface->cur_altsetting->desc.bInterfaceNumber == 1)
+ serial->dev->descriptor.idProduct == HUAWEI_PRODUCT_K4505 ||
+ serial->dev->descriptor.idProduct == HUAWEI_PRODUCT_K4605) &&
+ (serial->interface->cur_altsetting->desc.bInterfaceNumber == 1 ||
+ serial->interface->cur_altsetting->desc.bInterfaceNumber == 2))
return -ENODEV;
/* Don't bind network interface on Samsung GT-B3730, it is handled by a separate module */
diff --git a/drivers/video/backlight/adp8870_bl.c b/drivers/video/backlight/adp8870_bl.c
index 05a8832..d06886a 100644
--- a/drivers/video/backlight/adp8870_bl.c
+++ b/drivers/video/backlight/adp8870_bl.c
@@ -1009,4 +1009,4 @@
MODULE_LICENSE("GPL v2");
MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>");
MODULE_DESCRIPTION("ADP8870 Backlight driver");
-MODULE_ALIAS("platform:adp8870-backlight");
+MODULE_ALIAS("i2c:adp8870-backlight");
diff --git a/drivers/video/backlight/backlight.c b/drivers/video/backlight/backlight.c
index 80d292f..7363c1b 100644
--- a/drivers/video/backlight/backlight.c
+++ b/drivers/video/backlight/backlight.c
@@ -19,7 +19,7 @@
#include <asm/backlight.h>
#endif
-static const char const *backlight_types[] = {
+static const char *const backlight_types[] = {
[BACKLIGHT_RAW] = "raw",
[BACKLIGHT_PLATFORM] = "platform",
[BACKLIGHT_FIRMWARE] = "firmware",
diff --git a/drivers/video/backlight/ep93xx_bl.c b/drivers/video/backlight/ep93xx_bl.c
index 9f1e389..b058291 100644
--- a/drivers/video/backlight/ep93xx_bl.c
+++ b/drivers/video/backlight/ep93xx_bl.c
@@ -11,7 +11,7 @@
* BRIGHT, on the Cirrus EP9307, EP9312, and EP9315 processors.
*/
-
+#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/io.h>
#include <linux/fb.h>
diff --git a/drivers/video/backlight/pwm_bl.c b/drivers/video/backlight/pwm_bl.c
index b8f38ec..8b5b2a4 100644
--- a/drivers/video/backlight/pwm_bl.c
+++ b/drivers/video/backlight/pwm_bl.c
@@ -28,6 +28,8 @@
unsigned int lth_brightness;
int (*notify)(struct device *,
int brightness);
+ void (*notify_after)(struct device *,
+ int brightness);
int (*check_fb)(struct device *, struct fb_info *);
};
@@ -55,6 +57,10 @@
pwm_config(pb->pwm, brightness, pb->period);
pwm_enable(pb->pwm);
}
+
+ if (pb->notify_after)
+ pb->notify_after(pb->dev, brightness);
+
return 0;
}
@@ -105,6 +111,7 @@
pb->period = data->pwm_period_ns;
pb->notify = data->notify;
+ pb->notify_after = data->notify_after;
pb->check_fb = data->check_fb;
pb->lth_brightness = data->lth_brightness *
(data->pwm_period_ns / data->max_brightness);
@@ -172,6 +179,8 @@
pb->notify(pb->dev, 0);
pwm_config(pb->pwm, 0, pb->period);
pwm_disable(pb->pwm);
+ if (pb->notify_after)
+ pb->notify_after(pb->dev, 0);
return 0;
}
diff --git a/drivers/w1/masters/ds2490.c b/drivers/w1/masters/ds2490.c
index 02bf7bf..b5abaae 100644
--- a/drivers/w1/masters/ds2490.c
+++ b/drivers/w1/masters/ds2490.c
@@ -1,7 +1,7 @@
/*
* dscore.c
*
- * Copyright (c) 2004 Evgeniy Polyakov <johnpol@2ka.mipt.ru>
+ * Copyright (c) 2004 Evgeniy Polyakov <zbr@ioremap.net>
*
*
* This program is free software; you can redistribute it and/or modify
@@ -1024,5 +1024,5 @@
module_exit(ds_fini);
MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Evgeniy Polyakov <johnpol@2ka.mipt.ru>");
+MODULE_AUTHOR("Evgeniy Polyakov <zbr@ioremap.net>");
MODULE_DESCRIPTION("DS2490 USB <-> W1 bus master driver (DS9490*)");
diff --git a/drivers/w1/masters/matrox_w1.c b/drivers/w1/masters/matrox_w1.c
index 334d1cc..f667c26 100644
--- a/drivers/w1/masters/matrox_w1.c
+++ b/drivers/w1/masters/matrox_w1.c
@@ -1,7 +1,7 @@
/*
* matrox_w1.c
*
- * Copyright (c) 2004 Evgeniy Polyakov <johnpol@2ka.mipt.ru>
+ * Copyright (c) 2004 Evgeniy Polyakov <zbr@ioremap.net>
*
*
* This program is free software; you can redistribute it and/or modify
@@ -39,7 +39,7 @@
#include "../w1_log.h"
MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Evgeniy Polyakov <johnpol@2ka.mipt.ru>");
+MODULE_AUTHOR("Evgeniy Polyakov <zbr@ioremap.net>");
MODULE_DESCRIPTION("Driver for transport(Dallas 1-wire prtocol) over VGA DDC(matrox gpio).");
static struct pci_device_id matrox_w1_tbl[] = {
diff --git a/drivers/w1/slaves/w1_ds2408.c b/drivers/w1/slaves/w1_ds2408.c
index c377818..7c8cdb8 100644
--- a/drivers/w1/slaves/w1_ds2408.c
+++ b/drivers/w1/slaves/w1_ds2408.c
@@ -373,7 +373,7 @@
static void w1_f29_remove_slave(struct w1_slave *sl)
{
int i;
- for (i = NB_SYSFS_BIN_FILES; i <= 0; --i)
+ for (i = NB_SYSFS_BIN_FILES - 1; i >= 0; --i)
sysfs_remove_bin_file(&sl->dev.kobj,
&(w1_f29_sysfs_bin_files[i]));
}
diff --git a/drivers/w1/slaves/w1_smem.c b/drivers/w1/slaves/w1_smem.c
index cc8c02e..8465562 100644
--- a/drivers/w1/slaves/w1_smem.c
+++ b/drivers/w1/slaves/w1_smem.c
@@ -1,7 +1,7 @@
/*
* w1_smem.c
*
- * Copyright (c) 2004 Evgeniy Polyakov <johnpol@2ka.mipt.ru>
+ * Copyright (c) 2004 Evgeniy Polyakov <zbr@ioremap.net>
*
*
* This program is free software; you can redistribute it and/or modify
@@ -32,7 +32,7 @@
#include "../w1_family.h"
MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Evgeniy Polyakov <johnpol@2ka.mipt.ru>");
+MODULE_AUTHOR("Evgeniy Polyakov <zbr@ioremap.net>");
MODULE_DESCRIPTION("Driver for 1-wire Dallas network protocol, 64bit memory family.");
static struct w1_family w1_smem_family_01 = {
diff --git a/drivers/w1/slaves/w1_therm.c b/drivers/w1/slaves/w1_therm.c
index 402928b..a1ef9b5 100644
--- a/drivers/w1/slaves/w1_therm.c
+++ b/drivers/w1/slaves/w1_therm.c
@@ -1,7 +1,7 @@
/*
* w1_therm.c
*
- * Copyright (c) 2004 Evgeniy Polyakov <johnpol@2ka.mipt.ru>
+ * Copyright (c) 2004 Evgeniy Polyakov <zbr@ioremap.net>
*
*
* This program is free software; you can redistribute it and/or modify
@@ -34,7 +34,7 @@
#include "../w1_family.h"
MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Evgeniy Polyakov <johnpol@2ka.mipt.ru>");
+MODULE_AUTHOR("Evgeniy Polyakov <zbr@ioremap.net>");
MODULE_DESCRIPTION("Driver for 1-wire Dallas network protocol, temperature family.");
/* Allow the strong pullup to be disabled, but default to enabled.
diff --git a/drivers/w1/w1.c b/drivers/w1/w1.c
index 6c136c1..c374978 100644
--- a/drivers/w1/w1.c
+++ b/drivers/w1/w1.c
@@ -1,7 +1,7 @@
/*
* w1.c
*
- * Copyright (c) 2004 Evgeniy Polyakov <johnpol@2ka.mipt.ru>
+ * Copyright (c) 2004 Evgeniy Polyakov <zbr@ioremap.net>
*
*
* This program is free software; you can redistribute it and/or modify
@@ -42,7 +42,7 @@
#include "w1_netlink.h"
MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Evgeniy Polyakov <johnpol@2ka.mipt.ru>");
+MODULE_AUTHOR("Evgeniy Polyakov <zbr@ioremap.net>");
MODULE_DESCRIPTION("Driver for 1-wire Dallas network protocol.");
static int w1_timeout = 10;
diff --git a/drivers/w1/w1.h b/drivers/w1/w1.h
index 1ce23fc..4d012ca 100644
--- a/drivers/w1/w1.h
+++ b/drivers/w1/w1.h
@@ -1,7 +1,7 @@
/*
* w1.h
*
- * Copyright (c) 2004 Evgeniy Polyakov <johnpol@2ka.mipt.ru>
+ * Copyright (c) 2004 Evgeniy Polyakov <zbr@ioremap.net>
*
*
* This program is free software; you can redistribute it and/or modify
diff --git a/drivers/w1/w1_family.c b/drivers/w1/w1_family.c
index 4a09904..6335979 100644
--- a/drivers/w1/w1_family.c
+++ b/drivers/w1/w1_family.c
@@ -1,7 +1,7 @@
/*
* w1_family.c
*
- * Copyright (c) 2004 Evgeniy Polyakov <johnpol@2ka.mipt.ru>
+ * Copyright (c) 2004 Evgeniy Polyakov <zbr@ioremap.net>
*
*
* This program is free software; you can redistribute it and/or modify
diff --git a/drivers/w1/w1_family.h b/drivers/w1/w1_family.h
index 98a1ac0..490cda2 100644
--- a/drivers/w1/w1_family.h
+++ b/drivers/w1/w1_family.h
@@ -1,7 +1,7 @@
/*
* w1_family.h
*
- * Copyright (c) 2004 Evgeniy Polyakov <johnpol@2ka.mipt.ru>
+ * Copyright (c) 2004 Evgeniy Polyakov <zbr@ioremap.net>
*
*
* This program is free software; you can redistribute it and/or modify
diff --git a/drivers/w1/w1_int.c b/drivers/w1/w1_int.c
index b50be3f..d220bce 100644
--- a/drivers/w1/w1_int.c
+++ b/drivers/w1/w1_int.c
@@ -1,7 +1,7 @@
/*
* w1_int.c
*
- * Copyright (c) 2004 Evgeniy Polyakov <johnpol@2ka.mipt.ru>
+ * Copyright (c) 2004 Evgeniy Polyakov <zbr@ioremap.net>
*
*
* This program is free software; you can redistribute it and/or modify
diff --git a/drivers/w1/w1_int.h b/drivers/w1/w1_int.h
index 4274082..2ad7d44 100644
--- a/drivers/w1/w1_int.h
+++ b/drivers/w1/w1_int.h
@@ -1,7 +1,7 @@
/*
* w1_int.h
*
- * Copyright (c) 2004 Evgeniy Polyakov <johnpol@2ka.mipt.ru>
+ * Copyright (c) 2004 Evgeniy Polyakov <zbr@ioremap.net>
*
*
* This program is free software; you can redistribute it and/or modify
diff --git a/drivers/w1/w1_io.c b/drivers/w1/w1_io.c
index 8e8b64c..765b37b 100644
--- a/drivers/w1/w1_io.c
+++ b/drivers/w1/w1_io.c
@@ -1,7 +1,7 @@
/*
* w1_io.c
*
- * Copyright (c) 2004 Evgeniy Polyakov <johnpol@2ka.mipt.ru>
+ * Copyright (c) 2004 Evgeniy Polyakov <zbr@ioremap.net>
*
*
* This program is free software; you can redistribute it and/or modify
diff --git a/drivers/w1/w1_log.h b/drivers/w1/w1_log.h
index e6ab7cf..9c7bd62 100644
--- a/drivers/w1/w1_log.h
+++ b/drivers/w1/w1_log.h
@@ -1,7 +1,7 @@
/*
* w1_log.h
*
- * Copyright (c) 2004 Evgeniy Polyakov <johnpol@2ka.mipt.ru>
+ * Copyright (c) 2004 Evgeniy Polyakov <zbr@ioremap.net>
*
*
* This program is free software; you can redistribute it and/or modify
diff --git a/drivers/w1/w1_netlink.c b/drivers/w1/w1_netlink.c
index 55aabd9..40788c9 100644
--- a/drivers/w1/w1_netlink.c
+++ b/drivers/w1/w1_netlink.c
@@ -1,7 +1,7 @@
/*
* w1_netlink.c
*
- * Copyright (c) 2003 Evgeniy Polyakov <johnpol@2ka.mipt.ru>
+ * Copyright (c) 2003 Evgeniy Polyakov <zbr@ioremap.net>
*
*
* This program is free software; you can redistribute it and/or modify
diff --git a/drivers/w1/w1_netlink.h b/drivers/w1/w1_netlink.h
index 27e950f..b0922dc 100644
--- a/drivers/w1/w1_netlink.h
+++ b/drivers/w1/w1_netlink.h
@@ -1,7 +1,7 @@
/*
* w1_netlink.h
*
- * Copyright (c) 2003 Evgeniy Polyakov <johnpol@2ka.mipt.ru>
+ * Copyright (c) 2003 Evgeniy Polyakov <zbr@ioremap.net>
*
*
* This program is free software; you can redistribute it and/or modify
diff --git a/fs/9p/v9fs_vfs.h b/fs/9p/v9fs_vfs.h
index 46ce357..410ffd6 100644
--- a/fs/9p/v9fs_vfs.h
+++ b/fs/9p/v9fs_vfs.h
@@ -54,9 +54,9 @@
struct inode *v9fs_alloc_inode(struct super_block *sb);
void v9fs_destroy_inode(struct inode *inode);
-struct inode *v9fs_get_inode(struct super_block *sb, int mode);
+struct inode *v9fs_get_inode(struct super_block *sb, int mode, dev_t);
int v9fs_init_inode(struct v9fs_session_info *v9ses,
- struct inode *inode, int mode);
+ struct inode *inode, int mode, dev_t);
void v9fs_evict_inode(struct inode *inode);
ino_t v9fs_qid2ino(struct p9_qid *qid);
void v9fs_stat2inode(struct p9_wstat *, struct inode *, struct super_block *);
@@ -83,4 +83,6 @@
v9inode->cache_validity |= V9FS_INO_INVALID_ATTR;
return;
}
+
+int v9fs_open_to_dotl_flags(int flags);
#endif
diff --git a/fs/9p/vfs_file.c b/fs/9p/vfs_file.c
index 3c173fc..62857a8 100644
--- a/fs/9p/vfs_file.c
+++ b/fs/9p/vfs_file.c
@@ -65,7 +65,7 @@
v9inode = V9FS_I(inode);
v9ses = v9fs_inode2v9ses(inode);
if (v9fs_proto_dotl(v9ses))
- omode = file->f_flags;
+ omode = v9fs_open_to_dotl_flags(file->f_flags);
else
omode = v9fs_uflags2omode(file->f_flags,
v9fs_proto_dotu(v9ses));
@@ -169,7 +169,18 @@
/* convert posix lock to p9 tlock args */
memset(&flock, 0, sizeof(flock));
- flock.type = fl->fl_type;
+ /* map the lock type */
+ switch (fl->fl_type) {
+ case F_RDLCK:
+ flock.type = P9_LOCK_TYPE_RDLCK;
+ break;
+ case F_WRLCK:
+ flock.type = P9_LOCK_TYPE_WRLCK;
+ break;
+ case F_UNLCK:
+ flock.type = P9_LOCK_TYPE_UNLCK;
+ break;
+ }
flock.start = fl->fl_start;
if (fl->fl_end == OFFSET_MAX)
flock.length = 0;
@@ -245,7 +256,7 @@
/* convert posix lock to p9 tgetlock args */
memset(&glock, 0, sizeof(glock));
- glock.type = fl->fl_type;
+ glock.type = P9_LOCK_TYPE_UNLCK;
glock.start = fl->fl_start;
if (fl->fl_end == OFFSET_MAX)
glock.length = 0;
@@ -257,17 +268,26 @@
res = p9_client_getlock_dotl(fid, &glock);
if (res < 0)
return res;
- if (glock.type != F_UNLCK) {
- fl->fl_type = glock.type;
+ /* map 9p lock type to os lock type */
+ switch (glock.type) {
+ case P9_LOCK_TYPE_RDLCK:
+ fl->fl_type = F_RDLCK;
+ break;
+ case P9_LOCK_TYPE_WRLCK:
+ fl->fl_type = F_WRLCK;
+ break;
+ case P9_LOCK_TYPE_UNLCK:
+ fl->fl_type = F_UNLCK;
+ break;
+ }
+ if (glock.type != P9_LOCK_TYPE_UNLCK) {
fl->fl_start = glock.start;
if (glock.length == 0)
fl->fl_end = OFFSET_MAX;
else
fl->fl_end = glock.start + glock.length - 1;
fl->fl_pid = glock.proc_id;
- } else
- fl->fl_type = F_UNLCK;
-
+ }
return res;
}
diff --git a/fs/9p/vfs_inode.c b/fs/9p/vfs_inode.c
index 8bb5507..e3c03db 100644
--- a/fs/9p/vfs_inode.c
+++ b/fs/9p/vfs_inode.c
@@ -95,15 +95,18 @@
/**
* p9mode2unixmode- convert plan9 mode bits to unix mode bits
* @v9ses: v9fs session information
- * @mode: mode to convert
+ * @stat: p9_wstat from which mode need to be derived
+ * @rdev: major number, minor number in case of device files.
*
*/
-
-static int p9mode2unixmode(struct v9fs_session_info *v9ses, int mode)
+static int p9mode2unixmode(struct v9fs_session_info *v9ses,
+ struct p9_wstat *stat, dev_t *rdev)
{
int res;
+ int mode = stat->mode;
- res = mode & 0777;
+ res = mode & S_IALLUGO;
+ *rdev = 0;
if ((mode & P9_DMDIR) == P9_DMDIR)
res |= S_IFDIR;
@@ -116,9 +119,26 @@
&& (v9ses->nodev == 0))
res |= S_IFIFO;
else if ((mode & P9_DMDEVICE) && (v9fs_proto_dotu(v9ses))
- && (v9ses->nodev == 0))
- res |= S_IFBLK;
- else
+ && (v9ses->nodev == 0)) {
+ char type = 0, ext[32];
+ int major = -1, minor = -1;
+
+ strncpy(ext, stat->extension, sizeof(ext));
+ sscanf(ext, "%c %u %u", &type, &major, &minor);
+ switch (type) {
+ case 'c':
+ res |= S_IFCHR;
+ break;
+ case 'b':
+ res |= S_IFBLK;
+ break;
+ default:
+ P9_DPRINTK(P9_DEBUG_ERROR,
+ "Unknown special type %c %s\n", type,
+ stat->extension);
+ };
+ *rdev = MKDEV(major, minor);
+ } else
res |= S_IFREG;
if (v9fs_proto_dotu(v9ses)) {
@@ -131,7 +151,6 @@
if ((mode & P9_DMSETVTX) == P9_DMSETVTX)
res |= S_ISVTX;
}
-
return res;
}
@@ -242,13 +261,13 @@
}
int v9fs_init_inode(struct v9fs_session_info *v9ses,
- struct inode *inode, int mode)
+ struct inode *inode, int mode, dev_t rdev)
{
int err = 0;
inode_init_owner(inode, NULL, mode);
inode->i_blocks = 0;
- inode->i_rdev = 0;
+ inode->i_rdev = rdev;
inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
inode->i_mapping->a_ops = &v9fs_addr_operations;
@@ -335,7 +354,7 @@
*
*/
-struct inode *v9fs_get_inode(struct super_block *sb, int mode)
+struct inode *v9fs_get_inode(struct super_block *sb, int mode, dev_t rdev)
{
int err;
struct inode *inode;
@@ -348,7 +367,7 @@
P9_EPRINTK(KERN_WARNING, "Problem allocating inode\n");
return ERR_PTR(-ENOMEM);
}
- err = v9fs_init_inode(v9ses, inode, mode);
+ err = v9fs_init_inode(v9ses, inode, mode, rdev);
if (err) {
iput(inode);
return ERR_PTR(err);
@@ -435,11 +454,12 @@
static int v9fs_test_inode(struct inode *inode, void *data)
{
int umode;
+ dev_t rdev;
struct v9fs_inode *v9inode = V9FS_I(inode);
struct p9_wstat *st = (struct p9_wstat *)data;
struct v9fs_session_info *v9ses = v9fs_inode2v9ses(inode);
- umode = p9mode2unixmode(v9ses, st->mode);
+ umode = p9mode2unixmode(v9ses, st, &rdev);
/* don't match inode of different type */
if ((inode->i_mode & S_IFMT) != (umode & S_IFMT))
return 0;
@@ -473,6 +493,7 @@
struct p9_wstat *st,
int new)
{
+ dev_t rdev;
int retval, umode;
unsigned long i_ino;
struct inode *inode;
@@ -496,8 +517,8 @@
* later.
*/
inode->i_ino = i_ino;
- umode = p9mode2unixmode(v9ses, st->mode);
- retval = v9fs_init_inode(v9ses, inode, umode);
+ umode = p9mode2unixmode(v9ses, st, &rdev);
+ retval = v9fs_init_inode(v9ses, inode, umode, rdev);
if (retval)
goto error;
@@ -532,6 +553,19 @@
}
/**
+ * v9fs_at_to_dotl_flags- convert Linux specific AT flags to
+ * plan 9 AT flag.
+ * @flags: flags to convert
+ */
+static int v9fs_at_to_dotl_flags(int flags)
+{
+ int rflags = 0;
+ if (flags & AT_REMOVEDIR)
+ rflags |= P9_DOTL_AT_REMOVEDIR;
+ return rflags;
+}
+
+/**
* v9fs_remove - helper function to remove files and directories
* @dir: directory inode that is being deleted
* @dentry: dentry that is being deleted
@@ -558,7 +592,8 @@
return retval;
}
if (v9fs_proto_dotl(v9ses))
- retval = p9_client_unlinkat(dfid, dentry->d_name.name, flags);
+ retval = p9_client_unlinkat(dfid, dentry->d_name.name,
+ v9fs_at_to_dotl_flags(flags));
if (retval == -EOPNOTSUPP) {
/* Try the one based on path */
v9fid = v9fs_fid_clone(dentry);
@@ -645,13 +680,11 @@
P9_DPRINTK(P9_DEBUG_VFS, "inode creation failed %d\n", err);
goto error;
}
- d_instantiate(dentry, inode);
err = v9fs_fid_add(dentry, fid);
if (err < 0)
goto error;
-
+ d_instantiate(dentry, inode);
return ofid;
-
error:
if (ofid)
p9_client_clunk(ofid);
@@ -792,6 +825,7 @@
struct dentry *v9fs_vfs_lookup(struct inode *dir, struct dentry *dentry,
struct nameidata *nameidata)
{
+ struct dentry *res;
struct super_block *sb;
struct v9fs_session_info *v9ses;
struct p9_fid *dfid, *fid;
@@ -823,22 +857,35 @@
return ERR_PTR(result);
}
-
- inode = v9fs_get_inode_from_fid(v9ses, fid, dir->i_sb);
+ /*
+ * Make sure we don't use a wrong inode due to parallel
+ * unlink. For cached mode create calls request for new
+ * inode. But with cache disabled, lookup should do this.
+ */
+ if (v9ses->cache)
+ inode = v9fs_get_inode_from_fid(v9ses, fid, dir->i_sb);
+ else
+ inode = v9fs_get_new_inode_from_fid(v9ses, fid, dir->i_sb);
if (IS_ERR(inode)) {
result = PTR_ERR(inode);
inode = NULL;
goto error;
}
-
result = v9fs_fid_add(dentry, fid);
if (result < 0)
goto error_iput;
-
inst_out:
- d_add(dentry, inode);
- return NULL;
-
+ /*
+ * If we had a rename on the server and a parallel lookup
+ * for the new name, then make sure we instantiate with
+ * the new name. ie look up for a/b, while on server somebody
+ * moved b under k and client parallely did a lookup for
+ * k/b.
+ */
+ res = d_materialise_unique(dentry, inode);
+ if (!IS_ERR(res))
+ return res;
+ result = PTR_ERR(res);
error_iput:
iput(inode);
error:
@@ -1002,7 +1049,7 @@
return PTR_ERR(st);
v9fs_stat2inode(st, dentry->d_inode, dentry->d_inode->i_sb);
- generic_fillattr(dentry->d_inode, stat);
+ generic_fillattr(dentry->d_inode, stat);
p9stat_free(st);
kfree(st);
@@ -1086,6 +1133,7 @@
v9fs_stat2inode(struct p9_wstat *stat, struct inode *inode,
struct super_block *sb)
{
+ mode_t mode;
char ext[32];
char tag_name[14];
unsigned int i_nlink;
@@ -1121,31 +1169,9 @@
inode->i_nlink = i_nlink;
}
}
- inode->i_mode = p9mode2unixmode(v9ses, stat->mode);
- if ((S_ISBLK(inode->i_mode)) || (S_ISCHR(inode->i_mode))) {
- char type = 0;
- int major = -1;
- int minor = -1;
-
- strncpy(ext, stat->extension, sizeof(ext));
- sscanf(ext, "%c %u %u", &type, &major, &minor);
- switch (type) {
- case 'c':
- inode->i_mode &= ~S_IFBLK;
- inode->i_mode |= S_IFCHR;
- break;
- case 'b':
- break;
- default:
- P9_DPRINTK(P9_DEBUG_ERROR,
- "Unknown special type %c %s\n", type,
- stat->extension);
- };
- inode->i_rdev = MKDEV(major, minor);
- init_special_inode(inode, inode->i_mode, inode->i_rdev);
- } else
- inode->i_rdev = 0;
-
+ mode = stat->mode & S_IALLUGO;
+ mode |= inode->i_mode & ~S_IALLUGO;
+ inode->i_mode = mode;
i_size_write(inode, stat->length);
/* not real number of blocks, but 512 byte ones ... */
@@ -1411,6 +1437,8 @@
int v9fs_refresh_inode(struct p9_fid *fid, struct inode *inode)
{
+ int umode;
+ dev_t rdev;
loff_t i_size;
struct p9_wstat *st;
struct v9fs_session_info *v9ses;
@@ -1419,6 +1447,12 @@
st = p9_client_stat(fid);
if (IS_ERR(st))
return PTR_ERR(st);
+ /*
+ * Don't update inode if the file type is different
+ */
+ umode = p9mode2unixmode(v9ses, st, &rdev);
+ if ((inode->i_mode & S_IFMT) != (umode & S_IFMT))
+ goto out;
spin_lock(&inode->i_lock);
/*
@@ -1430,6 +1464,7 @@
if (v9ses->cache)
inode->i_size = i_size;
spin_unlock(&inode->i_lock);
+out:
p9stat_free(st);
kfree(st);
return 0;
diff --git a/fs/9p/vfs_inode_dotl.c b/fs/9p/vfs_inode_dotl.c
index b6c8ed2..aded79f 100644
--- a/fs/9p/vfs_inode_dotl.c
+++ b/fs/9p/vfs_inode_dotl.c
@@ -153,7 +153,8 @@
* later.
*/
inode->i_ino = i_ino;
- retval = v9fs_init_inode(v9ses, inode, st->st_mode);
+ retval = v9fs_init_inode(v9ses, inode,
+ st->st_mode, new_decode_dev(st->st_rdev));
if (retval)
goto error;
@@ -190,6 +191,58 @@
return inode;
}
+struct dotl_openflag_map {
+ int open_flag;
+ int dotl_flag;
+};
+
+static int v9fs_mapped_dotl_flags(int flags)
+{
+ int i;
+ int rflags = 0;
+ struct dotl_openflag_map dotl_oflag_map[] = {
+ { O_CREAT, P9_DOTL_CREATE },
+ { O_EXCL, P9_DOTL_EXCL },
+ { O_NOCTTY, P9_DOTL_NOCTTY },
+ { O_TRUNC, P9_DOTL_TRUNC },
+ { O_APPEND, P9_DOTL_APPEND },
+ { O_NONBLOCK, P9_DOTL_NONBLOCK },
+ { O_DSYNC, P9_DOTL_DSYNC },
+ { FASYNC, P9_DOTL_FASYNC },
+ { O_DIRECT, P9_DOTL_DIRECT },
+ { O_LARGEFILE, P9_DOTL_LARGEFILE },
+ { O_DIRECTORY, P9_DOTL_DIRECTORY },
+ { O_NOFOLLOW, P9_DOTL_NOFOLLOW },
+ { O_NOATIME, P9_DOTL_NOATIME },
+ { O_CLOEXEC, P9_DOTL_CLOEXEC },
+ { O_SYNC, P9_DOTL_SYNC},
+ };
+ for (i = 0; i < ARRAY_SIZE(dotl_oflag_map); i++) {
+ if (flags & dotl_oflag_map[i].open_flag)
+ rflags |= dotl_oflag_map[i].dotl_flag;
+ }
+ return rflags;
+}
+
+/**
+ * v9fs_open_to_dotl_flags- convert Linux specific open flags to
+ * plan 9 open flag.
+ * @flags: flags to convert
+ */
+int v9fs_open_to_dotl_flags(int flags)
+{
+ int rflags = 0;
+
+ /*
+ * We have same bits for P9_DOTL_READONLY, P9_DOTL_WRONLY
+ * and P9_DOTL_NOACCESS
+ */
+ rflags |= flags & O_ACCMODE;
+ rflags |= v9fs_mapped_dotl_flags(flags);
+
+ return rflags;
+}
+
/**
* v9fs_vfs_create_dotl - VFS hook to create files for 9P2000.L protocol.
* @dir: directory inode that is being created
@@ -258,7 +311,8 @@
"Failed to get acl values in creat %d\n", err);
goto error;
}
- err = p9_client_create_dotl(ofid, name, flags, mode, gid, &qid);
+ err = p9_client_create_dotl(ofid, name, v9fs_open_to_dotl_flags(flags),
+ mode, gid, &qid);
if (err < 0) {
P9_DPRINTK(P9_DEBUG_VFS,
"p9_client_open_dotl failed in creat %d\n",
@@ -281,10 +335,10 @@
P9_DPRINTK(P9_DEBUG_VFS, "inode creation failed %d\n", err);
goto error;
}
- d_instantiate(dentry, inode);
err = v9fs_fid_add(dentry, fid);
if (err < 0)
goto error;
+ d_instantiate(dentry, inode);
/* Now set the ACL based on the default value */
v9fs_set_create_acl(dentry, &dacl, &pacl);
@@ -403,10 +457,10 @@
err);
goto error;
}
- d_instantiate(dentry, inode);
err = v9fs_fid_add(dentry, fid);
if (err < 0)
goto error;
+ d_instantiate(dentry, inode);
fid = NULL;
} else {
/*
@@ -414,7 +468,7 @@
* inode with stat. We need to get an inode
* so that we can set the acl with dentry
*/
- inode = v9fs_get_inode(dir->i_sb, mode);
+ inode = v9fs_get_inode(dir->i_sb, mode, 0);
if (IS_ERR(inode)) {
err = PTR_ERR(inode);
goto error;
@@ -540,6 +594,7 @@
void
v9fs_stat2inode_dotl(struct p9_stat_dotl *stat, struct inode *inode)
{
+ mode_t mode;
struct v9fs_inode *v9inode = V9FS_I(inode);
if ((stat->st_result_mask & P9_STATS_BASIC) == P9_STATS_BASIC) {
@@ -552,11 +607,10 @@
inode->i_uid = stat->st_uid;
inode->i_gid = stat->st_gid;
inode->i_nlink = stat->st_nlink;
- inode->i_mode = stat->st_mode;
- inode->i_rdev = new_decode_dev(stat->st_rdev);
- if ((S_ISBLK(inode->i_mode)) || (S_ISCHR(inode->i_mode)))
- init_special_inode(inode, inode->i_mode, inode->i_rdev);
+ mode = stat->st_mode & S_IALLUGO;
+ mode |= inode->i_mode & ~S_IALLUGO;
+ inode->i_mode = mode;
i_size_write(inode, stat->st_size);
inode->i_blocks = stat->st_blocks;
@@ -657,14 +711,14 @@
err);
goto error;
}
- d_instantiate(dentry, inode);
err = v9fs_fid_add(dentry, fid);
if (err < 0)
goto error;
+ d_instantiate(dentry, inode);
fid = NULL;
} else {
/* Not in cached mode. No need to populate inode with stat */
- inode = v9fs_get_inode(dir->i_sb, S_IFLNK);
+ inode = v9fs_get_inode(dir->i_sb, S_IFLNK, 0);
if (IS_ERR(inode)) {
err = PTR_ERR(inode);
goto error;
@@ -810,17 +864,17 @@
err);
goto error;
}
- d_instantiate(dentry, inode);
err = v9fs_fid_add(dentry, fid);
if (err < 0)
goto error;
+ d_instantiate(dentry, inode);
fid = NULL;
} else {
/*
* Not in cached mode. No need to populate inode with stat.
* socket syscall returns a fd, so we need instantiate
*/
- inode = v9fs_get_inode(dir->i_sb, mode);
+ inode = v9fs_get_inode(dir->i_sb, mode, rdev);
if (IS_ERR(inode)) {
err = PTR_ERR(inode);
goto error;
@@ -886,6 +940,11 @@
st = p9_client_getattr_dotl(fid, P9_STATS_ALL);
if (IS_ERR(st))
return PTR_ERR(st);
+ /*
+ * Don't update inode if the file type is different
+ */
+ if ((inode->i_mode & S_IFMT) != (st->st_mode & S_IFMT))
+ goto out;
spin_lock(&inode->i_lock);
/*
@@ -897,6 +956,7 @@
if (v9ses->cache)
inode->i_size = i_size;
spin_unlock(&inode->i_lock);
+out:
kfree(st);
return 0;
}
diff --git a/fs/9p/vfs_super.c b/fs/9p/vfs_super.c
index feef6cd..c70251d 100644
--- a/fs/9p/vfs_super.c
+++ b/fs/9p/vfs_super.c
@@ -149,7 +149,7 @@
else
sb->s_d_op = &v9fs_dentry_operations;
- inode = v9fs_get_inode(sb, S_IFDIR | mode);
+ inode = v9fs_get_inode(sb, S_IFDIR | mode, 0);
if (IS_ERR(inode)) {
retval = PTR_ERR(inode);
goto release_sb;
diff --git a/fs/block_dev.c b/fs/block_dev.c
index ff77262..95f786e 100644
--- a/fs/block_dev.c
+++ b/fs/block_dev.c
@@ -1429,6 +1429,11 @@
WARN_ON_ONCE(bdev->bd_holders);
sync_blockdev(bdev);
kill_bdev(bdev);
+ /* ->release can cause the old bdi to disappear,
+ * so must switch it out first
+ */
+ bdev_inode_switch_bdi(bdev->bd_inode,
+ &default_backing_dev_info);
}
if (bdev->bd_contains == bdev) {
if (disk->fops->release)
@@ -1442,8 +1447,6 @@
disk_put_part(bdev->bd_part);
bdev->bd_part = NULL;
bdev->bd_disk = NULL;
- bdev_inode_switch_bdi(bdev->bd_inode,
- &default_backing_dev_info);
if (bdev != bdev->bd_contains)
victim = bdev->bd_contains;
bdev->bd_contains = NULL;
diff --git a/fs/btrfs/btrfs_inode.h b/fs/btrfs/btrfs_inode.h
index 502b9e9..d9f99a1 100644
--- a/fs/btrfs/btrfs_inode.h
+++ b/fs/btrfs/btrfs_inode.h
@@ -176,7 +176,11 @@
{
u64 ino = BTRFS_I(inode)->location.objectid;
- if (ino <= BTRFS_FIRST_FREE_OBJECTID)
+ /*
+ * !ino: btree_inode
+ * type == BTRFS_ROOT_ITEM_KEY: subvol dir
+ */
+ if (!ino || BTRFS_I(inode)->location.type == BTRFS_ROOT_ITEM_KEY)
ino = inode->i_ino;
return ino;
}
diff --git a/fs/btrfs/file-item.c b/fs/btrfs/file-item.c
index b910694..a1cb782 100644
--- a/fs/btrfs/file-item.c
+++ b/fs/btrfs/file-item.c
@@ -183,8 +183,10 @@
* read from the commit root and sidestep a nasty deadlock
* between reading the free space cache and updating the csum tree.
*/
- if (btrfs_is_free_space_inode(root, inode))
+ if (btrfs_is_free_space_inode(root, inode)) {
path->search_commit_root = 1;
+ path->skip_locking = 1;
+ }
disk_bytenr = (u64)bio->bi_sector << 9;
if (dio)
diff --git a/fs/btrfs/file.c b/fs/btrfs/file.c
index e7872e4..3c3abff 100644
--- a/fs/btrfs/file.c
+++ b/fs/btrfs/file.c
@@ -1075,12 +1075,6 @@
start_pos = pos & ~((u64)root->sectorsize - 1);
last_pos = ((u64)index + num_pages) << PAGE_CACHE_SHIFT;
- if (start_pos > inode->i_size) {
- err = btrfs_cont_expand(inode, i_size_read(inode), start_pos);
- if (err)
- return err;
- }
-
again:
for (i = 0; i < num_pages; i++) {
pages[i] = find_or_create_page(inode->i_mapping, index + i,
@@ -1338,6 +1332,7 @@
struct inode *inode = fdentry(file)->d_inode;
struct btrfs_root *root = BTRFS_I(inode)->root;
loff_t *ppos = &iocb->ki_pos;
+ u64 start_pos;
ssize_t num_written = 0;
ssize_t err = 0;
size_t count, ocount;
@@ -1386,6 +1381,15 @@
file_update_time(file);
BTRFS_I(inode)->sequence++;
+ start_pos = round_down(pos, root->sectorsize);
+ if (start_pos > i_size_read(inode)) {
+ err = btrfs_cont_expand(inode, i_size_read(inode), start_pos);
+ if (err) {
+ mutex_unlock(&inode->i_mutex);
+ goto out;
+ }
+ }
+
if (unlikely(file->f_flags & O_DIRECT)) {
num_written = __btrfs_direct_write(iocb, iov, nr_segs,
pos, ppos, count, ocount);
diff --git a/fs/btrfs/free-space-cache.c b/fs/btrfs/free-space-cache.c
index 6a265b9..41ac927 100644
--- a/fs/btrfs/free-space-cache.c
+++ b/fs/btrfs/free-space-cache.c
@@ -190,9 +190,11 @@
struct btrfs_path *path,
struct inode *inode)
{
+ struct btrfs_block_rsv *rsv;
loff_t oldsize;
int ret = 0;
+ rsv = trans->block_rsv;
trans->block_rsv = root->orphan_block_rsv;
ret = btrfs_block_rsv_check(trans, root,
root->orphan_block_rsv,
@@ -210,6 +212,8 @@
*/
ret = btrfs_truncate_inode_items(trans, root, inode,
0, BTRFS_EXTENT_DATA_KEY);
+
+ trans->block_rsv = rsv;
if (ret) {
WARN_ON(1);
return ret;
diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c
index 0ccc743..4d14de6 100644
--- a/fs/btrfs/inode.c
+++ b/fs/btrfs/inode.c
@@ -1786,7 +1786,7 @@
&ordered_extent->list);
ret = btrfs_ordered_update_i_size(inode, 0, ordered_extent);
- if (!ret) {
+ if (!ret || !test_bit(BTRFS_ORDERED_PREALLOC, &ordered_extent->flags)) {
ret = btrfs_update_inode(trans, root, inode);
BUG_ON(ret);
}
@@ -3510,15 +3510,19 @@
err = btrfs_drop_extents(trans, inode, cur_offset,
cur_offset + hole_size,
&hint_byte, 1);
- if (err)
+ if (err) {
+ btrfs_end_transaction(trans, root);
break;
+ }
err = btrfs_insert_file_extent(trans, root,
btrfs_ino(inode), cur_offset, 0,
0, hole_size, 0, hole_size,
0, 0, 0);
- if (err)
+ if (err) {
+ btrfs_end_transaction(trans, root);
break;
+ }
btrfs_drop_extent_cache(inode, hole_start,
last_byte - 1, 0);
@@ -3952,7 +3956,6 @@
struct btrfs_root *root, int *new)
{
struct inode *inode;
- int bad_inode = 0;
inode = btrfs_iget_locked(s, location->objectid, root);
if (!inode)
@@ -3968,15 +3971,12 @@
if (new)
*new = 1;
} else {
- bad_inode = 1;
+ unlock_new_inode(inode);
+ iput(inode);
+ inode = ERR_PTR(-ESTALE);
}
}
- if (bad_inode) {
- iput(inode);
- inode = ERR_PTR(-ESTALE);
- }
-
return inode;
}
@@ -5823,7 +5823,7 @@
add_pending_csums(trans, inode, ordered->file_offset, &ordered->list);
ret = btrfs_ordered_update_i_size(inode, 0, ordered);
- if (!ret)
+ if (!ret || !test_bit(BTRFS_ORDERED_PREALLOC, &ordered->flags))
btrfs_update_inode(trans, root, inode);
ret = 0;
out_unlock:
diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c
index 970977a..3351b1b 100644
--- a/fs/btrfs/ioctl.c
+++ b/fs/btrfs/ioctl.c
@@ -2220,6 +2220,12 @@
!IS_ALIGNED(destoff, bs))
goto out_unlock;
+ if (destoff > inode->i_size) {
+ ret = btrfs_cont_expand(inode, inode->i_size, destoff);
+ if (ret)
+ goto out_unlock;
+ }
+
/* do any pending delalloc/csum calc on src, one way or
another, and lock file content */
while (1) {
@@ -2325,14 +2331,21 @@
if (type == BTRFS_FILE_EXTENT_REG ||
type == BTRFS_FILE_EXTENT_PREALLOC) {
+ /*
+ * a | --- range to clone ---| b
+ * | ------------- extent ------------- |
+ */
+
+ /* substract range b */
+ if (key.offset + datal > off + len)
+ datal = off + len - key.offset;
+
+ /* substract range a */
if (off > key.offset) {
datao += off - key.offset;
datal -= off - key.offset;
}
- if (key.offset + datal > off + len)
- datal = off + len - key.offset;
-
ret = btrfs_drop_extents(trans, inode,
new_key.offset,
new_key.offset + datal,
diff --git a/fs/btrfs/transaction.c b/fs/btrfs/transaction.c
index 7dc36fa..e24b796 100644
--- a/fs/btrfs/transaction.c
+++ b/fs/btrfs/transaction.c
@@ -884,6 +884,7 @@
struct btrfs_root *tree_root = fs_info->tree_root;
struct btrfs_root *root = pending->root;
struct btrfs_root *parent_root;
+ struct btrfs_block_rsv *rsv;
struct inode *parent_inode;
struct dentry *parent;
struct dentry *dentry;
@@ -895,6 +896,8 @@
u64 objectid;
u64 root_flags;
+ rsv = trans->block_rsv;
+
new_root_item = kmalloc(sizeof(*new_root_item), GFP_NOFS);
if (!new_root_item) {
pending->error = -ENOMEM;
@@ -1002,6 +1005,7 @@
btrfs_orphan_post_snapshot(trans, pending);
fail:
kfree(new_root_item);
+ trans->block_rsv = rsv;
btrfs_block_rsv_release(root, &pending->block_rsv, (u64)-1);
return 0;
}
diff --git a/fs/btrfs/xattr.c b/fs/btrfs/xattr.c
index d733b9c..69565e5 100644
--- a/fs/btrfs/xattr.c
+++ b/fs/btrfs/xattr.c
@@ -116,6 +116,12 @@
if (ret)
goto out;
btrfs_release_path(path);
+
+ /*
+ * remove the attribute
+ */
+ if (!value)
+ goto out;
}
again:
@@ -158,6 +164,9 @@
return ret;
}
+/*
+ * @value: "" makes the attribute to empty, NULL removes it
+ */
int __btrfs_setxattr(struct btrfs_trans_handle *trans,
struct inode *inode, const char *name,
const void *value, size_t size, int flags)
diff --git a/fs/ceph/mds_client.c b/fs/ceph/mds_client.c
index fee028b..86c59e1 100644
--- a/fs/ceph/mds_client.c
+++ b/fs/ceph/mds_client.c
@@ -1595,7 +1595,7 @@
r = build_dentry_path(rdentry, ppath, pathlen, ino, freepath);
dout(" dentry %p %llx/%.*s\n", rdentry, *ino, *pathlen,
*ppath);
- } else if (rpath) {
+ } else if (rpath || rino) {
*ino = rino;
*ppath = rpath;
*pathlen = strlen(rpath);
diff --git a/fs/ceph/super.c b/fs/ceph/super.c
index d47c5ec..88bacaf 100644
--- a/fs/ceph/super.c
+++ b/fs/ceph/super.c
@@ -813,8 +813,8 @@
fsc = create_fs_client(fsopt, opt);
if (IS_ERR(fsc)) {
res = ERR_CAST(fsc);
- kfree(fsopt);
- kfree(opt);
+ destroy_mount_options(fsopt);
+ ceph_destroy_options(opt);
goto out_final;
}
diff --git a/fs/compat.c b/fs/compat.c
index 0b48d01..58b1da4 100644
--- a/fs/compat.c
+++ b/fs/compat.c
@@ -1675,11 +1675,6 @@
}
#endif /* HAVE_SET_RESTORE_SIGMASK */
-long asmlinkage compat_sys_nfsservctl(int cmd, void *notused, void *notused2)
-{
- return sys_ni_syscall();
-}
-
#ifdef CONFIG_EPOLL
#ifdef HAVE_SET_RESTORE_SIGMASK
diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h
index e717dfd..b7d7bd0 100644
--- a/fs/ext4/ext4.h
+++ b/fs/ext4/ext4.h
@@ -175,6 +175,7 @@
*/
#define EXT4_IO_END_UNWRITTEN 0x0001
#define EXT4_IO_END_ERROR 0x0002
+#define EXT4_IO_END_QUEUED 0x0004
struct ext4_io_page {
struct page *p_page;
diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c
index c4da98a..18d2558 100644
--- a/fs/ext4/inode.c
+++ b/fs/ext4/inode.c
@@ -121,9 +121,6 @@
trace_ext4_evict_inode(inode);
- mutex_lock(&inode->i_mutex);
- ext4_flush_completed_IO(inode);
- mutex_unlock(&inode->i_mutex);
ext4_ioend_wait(inode);
if (inode->i_nlink) {
diff --git a/fs/ext4/page-io.c b/fs/ext4/page-io.c
index 78839af..92f38ee 100644
--- a/fs/ext4/page-io.c
+++ b/fs/ext4/page-io.c
@@ -142,7 +142,23 @@
unsigned long flags;
int ret;
- mutex_lock(&inode->i_mutex);
+ if (!mutex_trylock(&inode->i_mutex)) {
+ /*
+ * Requeue the work instead of waiting so that the work
+ * items queued after this can be processed.
+ */
+ queue_work(EXT4_SB(inode->i_sb)->dio_unwritten_wq, &io->work);
+ /*
+ * To prevent the ext4-dio-unwritten thread from keeping
+ * requeueing end_io requests and occupying cpu for too long,
+ * yield the cpu if it sees an end_io request that has already
+ * been requeued.
+ */
+ if (io->flag & EXT4_IO_END_QUEUED)
+ yield();
+ io->flag |= EXT4_IO_END_QUEUED;
+ return;
+ }
ret = ext4_end_io_nolock(io);
if (ret < 0) {
mutex_unlock(&inode->i_mutex);
diff --git a/fs/fuse/dev.c b/fs/fuse/dev.c
index 640fc22..5cb8614 100644
--- a/fs/fuse/dev.c
+++ b/fs/fuse/dev.c
@@ -258,10 +258,14 @@
forget->forget_one.nlookup = nlookup;
spin_lock(&fc->lock);
- fc->forget_list_tail->next = forget;
- fc->forget_list_tail = forget;
- wake_up(&fc->waitq);
- kill_fasync(&fc->fasync, SIGIO, POLL_IN);
+ if (fc->connected) {
+ fc->forget_list_tail->next = forget;
+ fc->forget_list_tail = forget;
+ wake_up(&fc->waitq);
+ kill_fasync(&fc->fasync, SIGIO, POLL_IN);
+ } else {
+ kfree(forget);
+ }
spin_unlock(&fc->lock);
}
@@ -1358,6 +1362,10 @@
if (outarg.namelen > FUSE_NAME_MAX)
goto err;
+ err = -EINVAL;
+ if (size != sizeof(outarg) + outarg.namelen + 1)
+ goto err;
+
name.name = buf;
name.len = outarg.namelen;
err = fuse_copy_one(cs, buf, outarg.namelen + 1);
diff --git a/fs/fuse/file.c b/fs/fuse/file.c
index d480d9a..594f07a 100644
--- a/fs/fuse/file.c
+++ b/fs/fuse/file.c
@@ -14,6 +14,7 @@
#include <linux/sched.h>
#include <linux/module.h>
#include <linux/compat.h>
+#include <linux/swap.h>
static const struct file_operations fuse_direct_io_file_operations;
@@ -245,6 +246,12 @@
req = ff->reserved_req;
fuse_prepare_release(ff, file->f_flags, opcode);
+ if (ff->flock) {
+ struct fuse_release_in *inarg = &req->misc.release.in;
+ inarg->release_flags |= FUSE_RELEASE_FLOCK_UNLOCK;
+ inarg->lock_owner = fuse_lock_owner_id(ff->fc,
+ (fl_owner_t) file);
+ }
/* Hold vfsmount and dentry until release is finished */
path_get(&file->f_path);
req->misc.release.path = file->f_path;
@@ -755,18 +762,6 @@
return req->misc.write.out.size;
}
-static int fuse_write_begin(struct file *file, struct address_space *mapping,
- loff_t pos, unsigned len, unsigned flags,
- struct page **pagep, void **fsdata)
-{
- pgoff_t index = pos >> PAGE_CACHE_SHIFT;
-
- *pagep = grab_cache_page_write_begin(mapping, index, flags);
- if (!*pagep)
- return -ENOMEM;
- return 0;
-}
-
void fuse_write_update_size(struct inode *inode, loff_t pos)
{
struct fuse_conn *fc = get_fuse_conn(inode);
@@ -779,62 +774,6 @@
spin_unlock(&fc->lock);
}
-static int fuse_buffered_write(struct file *file, struct inode *inode,
- loff_t pos, unsigned count, struct page *page)
-{
- int err;
- size_t nres;
- struct fuse_conn *fc = get_fuse_conn(inode);
- unsigned offset = pos & (PAGE_CACHE_SIZE - 1);
- struct fuse_req *req;
-
- if (is_bad_inode(inode))
- return -EIO;
-
- /*
- * Make sure writepages on the same page are not mixed up with
- * plain writes.
- */
- fuse_wait_on_page_writeback(inode, page->index);
-
- req = fuse_get_req(fc);
- if (IS_ERR(req))
- return PTR_ERR(req);
-
- req->in.argpages = 1;
- req->num_pages = 1;
- req->pages[0] = page;
- req->page_offset = offset;
- nres = fuse_send_write(req, file, pos, count, NULL);
- err = req->out.h.error;
- fuse_put_request(fc, req);
- if (!err && !nres)
- err = -EIO;
- if (!err) {
- pos += nres;
- fuse_write_update_size(inode, pos);
- if (count == PAGE_CACHE_SIZE)
- SetPageUptodate(page);
- }
- fuse_invalidate_attr(inode);
- return err ? err : nres;
-}
-
-static int fuse_write_end(struct file *file, struct address_space *mapping,
- loff_t pos, unsigned len, unsigned copied,
- struct page *page, void *fsdata)
-{
- struct inode *inode = mapping->host;
- int res = 0;
-
- if (copied)
- res = fuse_buffered_write(file, inode, pos, copied, page);
-
- unlock_page(page);
- page_cache_release(page);
- return res;
-}
-
static size_t fuse_send_write_pages(struct fuse_req *req, struct file *file,
struct inode *inode, loff_t pos,
size_t count)
@@ -908,6 +847,8 @@
pagefault_enable();
flush_dcache_page(page);
+ mark_page_accessed(page);
+
if (!tmp) {
unlock_page(page);
page_cache_release(page);
@@ -1559,11 +1500,14 @@
struct fuse_conn *fc = get_fuse_conn(inode);
int err;
- if (fc->no_lock) {
+ if (fc->no_flock) {
err = flock_lock_file_wait(file, fl);
} else {
+ struct fuse_file *ff = file->private_data;
+
/* emulate flock with POSIX locks */
fl->fl_owner = (fl_owner_t) file;
+ ff->flock = true;
err = fuse_setlk(file, fl, 1);
}
@@ -2201,8 +2145,6 @@
.readpage = fuse_readpage,
.writepage = fuse_writepage,
.launder_page = fuse_launder_page,
- .write_begin = fuse_write_begin,
- .write_end = fuse_write_end,
.readpages = fuse_readpages,
.set_page_dirty = __set_page_dirty_nobuffers,
.bmap = fuse_bmap,
diff --git a/fs/fuse/fuse_i.h b/fs/fuse/fuse_i.h
index c6aa2d4..cf6db0a 100644
--- a/fs/fuse/fuse_i.h
+++ b/fs/fuse/fuse_i.h
@@ -135,6 +135,9 @@
/** Wait queue head for poll */
wait_queue_head_t poll_wait;
+
+ /** Has flock been performed on this file? */
+ bool flock:1;
};
/** One input argument of a request */
@@ -448,7 +451,7 @@
/** Is removexattr not implemented by fs? */
unsigned no_removexattr:1;
- /** Are file locking primitives not implemented by fs? */
+ /** Are posix file locking primitives not implemented by fs? */
unsigned no_lock:1;
/** Is access not implemented by fs? */
@@ -472,6 +475,9 @@
/** Don't apply umask to creation modes */
unsigned dont_mask:1;
+ /** Are BSD file locking primitives not implemented by fs? */
+ unsigned no_flock:1;
+
/** The number of requests waiting for completion */
atomic_t num_waiting;
diff --git a/fs/fuse/inode.c b/fs/fuse/inode.c
index 38f84cd..add96f6 100644
--- a/fs/fuse/inode.c
+++ b/fs/fuse/inode.c
@@ -71,7 +71,7 @@
unsigned blksize;
};
-struct fuse_forget_link *fuse_alloc_forget()
+struct fuse_forget_link *fuse_alloc_forget(void)
{
return kzalloc(sizeof(struct fuse_forget_link), GFP_KERNEL);
}
@@ -809,6 +809,13 @@
fc->async_read = 1;
if (!(arg->flags & FUSE_POSIX_LOCKS))
fc->no_lock = 1;
+ if (arg->minor >= 17) {
+ if (!(arg->flags & FUSE_FLOCK_LOCKS))
+ fc->no_flock = 1;
+ } else {
+ if (!(arg->flags & FUSE_POSIX_LOCKS))
+ fc->no_flock = 1;
+ }
if (arg->flags & FUSE_ATOMIC_O_TRUNC)
fc->atomic_o_trunc = 1;
if (arg->minor >= 9) {
@@ -823,6 +830,7 @@
} else {
ra_pages = fc->max_read / PAGE_CACHE_SIZE;
fc->no_lock = 1;
+ fc->no_flock = 1;
}
fc->bdi.ra_pages = min(fc->bdi.ra_pages, ra_pages);
@@ -843,7 +851,8 @@
arg->minor = FUSE_KERNEL_MINOR_VERSION;
arg->max_readahead = fc->bdi.ra_pages * PAGE_CACHE_SIZE;
arg->flags |= FUSE_ASYNC_READ | FUSE_POSIX_LOCKS | FUSE_ATOMIC_O_TRUNC |
- FUSE_EXPORT_SUPPORT | FUSE_BIG_WRITES | FUSE_DONT_MASK;
+ FUSE_EXPORT_SUPPORT | FUSE_BIG_WRITES | FUSE_DONT_MASK |
+ FUSE_FLOCK_LOCKS;
req->in.h.opcode = FUSE_INIT;
req->in.numargs = 1;
req->in.args[0].size = sizeof(*arg);
diff --git a/fs/hugetlbfs/inode.c b/fs/hugetlbfs/inode.c
index 87b6e04..ec88953 100644
--- a/fs/hugetlbfs/inode.c
+++ b/fs/hugetlbfs/inode.c
@@ -491,6 +491,7 @@
inode->i_op = &page_symlink_inode_operations;
break;
}
+ lockdep_annotate_inode_mutex_key(inode);
}
return inode;
}
diff --git a/fs/inode.c b/fs/inode.c
index 73920d5..ec79246 100644
--- a/fs/inode.c
+++ b/fs/inode.c
@@ -848,16 +848,9 @@
}
EXPORT_SYMBOL(new_inode);
-/**
- * unlock_new_inode - clear the I_NEW state and wake up any waiters
- * @inode: new inode to unlock
- *
- * Called when the inode is fully initialised to clear the new state of the
- * inode and wake up anyone waiting for the inode to finish initialisation.
- */
-void unlock_new_inode(struct inode *inode)
-{
#ifdef CONFIG_DEBUG_LOCK_ALLOC
+void lockdep_annotate_inode_mutex_key(struct inode *inode)
+{
if (S_ISDIR(inode->i_mode)) {
struct file_system_type *type = inode->i_sb->s_type;
@@ -873,7 +866,20 @@
&type->i_mutex_dir_key);
}
}
+}
+EXPORT_SYMBOL(lockdep_annotate_inode_mutex_key);
#endif
+
+/**
+ * unlock_new_inode - clear the I_NEW state and wake up any waiters
+ * @inode: new inode to unlock
+ *
+ * Called when the inode is fully initialised to clear the new state of the
+ * inode and wake up anyone waiting for the inode to finish initialisation.
+ */
+void unlock_new_inode(struct inode *inode)
+{
+ lockdep_annotate_inode_mutex_key(inode);
spin_lock(&inode->i_lock);
WARN_ON(!(inode->i_state & I_NEW));
inode->i_state &= ~I_NEW;
diff --git a/fs/namei.c b/fs/namei.c
index 2826db3..b52bc68 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -727,25 +727,22 @@
if ((flags & LOOKUP_NO_AUTOMOUNT) && !(flags & LOOKUP_PARENT))
return -EISDIR; /* we actually want to stop here */
- /*
- * We don't want to mount if someone's just doing a stat and they've
- * set AT_SYMLINK_NOFOLLOW - unless they're stat'ing a directory and
- * appended a '/' to the name.
+ /* We don't want to mount if someone's just doing a stat -
+ * unless they're stat'ing a directory and appended a '/' to
+ * the name.
+ *
+ * We do, however, want to mount if someone wants to open or
+ * create a file of any type under the mountpoint, wants to
+ * traverse through the mountpoint or wants to open the
+ * mounted directory. Also, autofs may mark negative dentries
+ * as being automount points. These will need the attentions
+ * of the daemon to instantiate them before they can be used.
*/
- if (!(flags & LOOKUP_FOLLOW)) {
- /* We do, however, want to mount if someone wants to open or
- * create a file of any type under the mountpoint, wants to
- * traverse through the mountpoint or wants to open the mounted
- * directory.
- * Also, autofs may mark negative dentries as being automount
- * points. These will need the attentions of the daemon to
- * instantiate them before they can be used.
- */
- if (!(flags & (LOOKUP_PARENT | LOOKUP_DIRECTORY |
- LOOKUP_OPEN | LOOKUP_CREATE)) &&
- path->dentry->d_inode)
- return -EISDIR;
- }
+ if (!(flags & (LOOKUP_PARENT | LOOKUP_DIRECTORY |
+ LOOKUP_OPEN | LOOKUP_CREATE)) &&
+ path->dentry->d_inode)
+ return -EISDIR;
+
current->total_link_count++;
if (current->total_link_count >= 40)
return -ELOOP;
diff --git a/fs/ubifs/debug.h b/fs/ubifs/debug.h
index 45174b5..feb361e 100644
--- a/fs/ubifs/debug.h
+++ b/fs/ubifs/debug.h
@@ -335,9 +335,9 @@
#define DBGKEY(key) ((char *)(key))
#define DBGKEY1(key) ((char *)(key))
-#define ubifs_dbg_msg(fmt, ...) do { \
- if (0) \
- pr_debug(fmt "\n", ##__VA_ARGS__); \
+#define ubifs_dbg_msg(fmt, ...) do { \
+ if (0) \
+ printk(KERN_DEBUG fmt "\n", ##__VA_ARGS__); \
} while (0)
#define dbg_dump_stack()
diff --git a/fs/xfs/Makefile b/fs/xfs/Makefile
index 75bb316..427a4e8 100644
--- a/fs/xfs/Makefile
+++ b/fs/xfs/Makefile
@@ -16,44 +16,53 @@
# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#
-ccflags-y := -I$(src) -I$(src)/linux-2.6
-ccflags-$(CONFIG_XFS_DEBUG) += -g
+ccflags-y += -I$(src) # needed for trace events
-XFS_LINUX := linux-2.6
+ccflags-$(CONFIG_XFS_DEBUG) += -g
obj-$(CONFIG_XFS_FS) += xfs.o
-xfs-y += linux-2.6/xfs_trace.o
+# this one should be compiled first, as the tracing macros can easily blow up
+xfs-y += xfs_trace.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)
-xfs-$(CONFIG_XFS_QUOTA) += linux-2.6/xfs_quotaops.o
+# highlevel code
+xfs-y += xfs_aops.o \
+ xfs_bit.o \
+ xfs_buf.o \
+ xfs_dfrag.o \
+ xfs_discard.o \
+ xfs_error.o \
+ xfs_export.o \
+ xfs_file.o \
+ xfs_filestream.o \
+ xfs_fsops.o \
+ xfs_fs_subr.o \
+ xfs_globals.o \
+ xfs_iget.o \
+ xfs_ioctl.o \
+ xfs_iomap.o \
+ xfs_iops.o \
+ xfs_itable.o \
+ xfs_message.o \
+ xfs_mru_cache.o \
+ xfs_super.o \
+ xfs_sync.o \
+ xfs_xattr.o \
+ xfs_rename.o \
+ xfs_rw.o \
+ xfs_utils.o \
+ xfs_vnodeops.o \
+ kmem.o \
+ uuid.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_LINUX)/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
-
-
+# code shared with libxfs
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 \
@@ -61,49 +70,37 @@
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_cil.o \
xfs_log_recover.o \
xfs_mount.o \
- xfs_mru_cache.o \
- xfs_rename.o \
- xfs_trans.o \
+ xfs_trans.o
+
+# low-level transaction/log code
+xfs-y += xfs_log.o \
+ xfs_log_cil.o \
+ xfs_buf_item.o \
+ xfs_extfree_item.o \
+ xfs_inode_item.o \
xfs_trans_ail.o \
xfs_trans_buf.o \
xfs_trans_extfree.o \
xfs_trans_inode.o \
- xfs_utils.o \
- xfs_vnodeops.o \
- xfs_rw.o
-# Objects in linux/
-xfs-y += $(addprefix $(XFS_LINUX)/, \
- kmem.o \
- xfs_aops.o \
- xfs_buf.o \
- xfs_discard.o \
- xfs_export.o \
- xfs_file.o \
- xfs_fs_subr.o \
- xfs_globals.o \
- xfs_ioctl.o \
- xfs_iops.o \
- xfs_message.o \
- xfs_super.o \
- xfs_sync.o \
- xfs_xattr.o)
-
-# Objects in support/
-xfs-y += support/uuid.o
+# optional features
+xfs-$(CONFIG_XFS_QUOTA) += xfs_dquot.o \
+ xfs_dquot_item.o \
+ xfs_trans_dquot.o \
+ xfs_qm_syscalls.o \
+ xfs_qm_bhv.o \
+ xfs_qm.o \
+ xfs_quotaops.o
+ifeq ($(CONFIG_XFS_QUOTA),y)
+xfs-$(CONFIG_PROC_FS) += 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_stats.o
+xfs-$(CONFIG_SYSCTL) += xfs_sysctl.o
+xfs-$(CONFIG_COMPAT) += xfs_ioctl32.o
diff --git a/fs/xfs/linux-2.6/kmem.c b/fs/xfs/kmem.c
similarity index 100%
rename from fs/xfs/linux-2.6/kmem.c
rename to fs/xfs/kmem.c
diff --git a/fs/xfs/linux-2.6/kmem.h b/fs/xfs/kmem.h
similarity index 100%
rename from fs/xfs/linux-2.6/kmem.h
rename to fs/xfs/kmem.h
diff --git a/fs/xfs/linux-2.6/mrlock.h b/fs/xfs/mrlock.h
similarity index 100%
rename from fs/xfs/linux-2.6/mrlock.h
rename to fs/xfs/mrlock.h
diff --git a/fs/xfs/linux-2.6/time.h b/fs/xfs/time.h
similarity index 100%
rename from fs/xfs/linux-2.6/time.h
rename to fs/xfs/time.h
diff --git a/fs/xfs/support/uuid.c b/fs/xfs/uuid.c
similarity index 100%
rename from fs/xfs/support/uuid.c
rename to fs/xfs/uuid.c
diff --git a/fs/xfs/support/uuid.h b/fs/xfs/uuid.h
similarity index 100%
rename from fs/xfs/support/uuid.h
rename to fs/xfs/uuid.h
diff --git a/fs/xfs/xfs.h b/fs/xfs/xfs.h
index 53ec3ea..d8b11b7 100644
--- a/fs/xfs/xfs.h
+++ b/fs/xfs/xfs.h
@@ -24,5 +24,6 @@
#define XFS_BUF_LOCK_TRACKING 1
#endif
-#include <linux-2.6/xfs_linux.h>
+#include "xfs_linux.h"
+
#endif /* __XFS_H__ */
diff --git a/fs/xfs/linux-2.6/xfs_acl.c b/fs/xfs/xfs_acl.c
similarity index 100%
rename from fs/xfs/linux-2.6/xfs_acl.c
rename to fs/xfs/xfs_acl.c
diff --git a/fs/xfs/linux-2.6/xfs_aops.c b/fs/xfs/xfs_aops.c
similarity index 100%
rename from fs/xfs/linux-2.6/xfs_aops.c
rename to fs/xfs/xfs_aops.c
diff --git a/fs/xfs/linux-2.6/xfs_aops.h b/fs/xfs/xfs_aops.h
similarity index 100%
rename from fs/xfs/linux-2.6/xfs_aops.h
rename to fs/xfs/xfs_aops.h
diff --git a/fs/xfs/linux-2.6/xfs_buf.c b/fs/xfs/xfs_buf.c
similarity index 100%
rename from fs/xfs/linux-2.6/xfs_buf.c
rename to fs/xfs/xfs_buf.c
diff --git a/fs/xfs/linux-2.6/xfs_buf.h b/fs/xfs/xfs_buf.h
similarity index 100%
rename from fs/xfs/linux-2.6/xfs_buf.h
rename to fs/xfs/xfs_buf.h
diff --git a/fs/xfs/linux-2.6/xfs_discard.c b/fs/xfs/xfs_discard.c
similarity index 100%
rename from fs/xfs/linux-2.6/xfs_discard.c
rename to fs/xfs/xfs_discard.c
diff --git a/fs/xfs/linux-2.6/xfs_discard.h b/fs/xfs/xfs_discard.h
similarity index 100%
rename from fs/xfs/linux-2.6/xfs_discard.h
rename to fs/xfs/xfs_discard.h
diff --git a/fs/xfs/quota/xfs_dquot.c b/fs/xfs/xfs_dquot.c
similarity index 100%
rename from fs/xfs/quota/xfs_dquot.c
rename to fs/xfs/xfs_dquot.c
diff --git a/fs/xfs/quota/xfs_dquot.h b/fs/xfs/xfs_dquot.h
similarity index 100%
rename from fs/xfs/quota/xfs_dquot.h
rename to fs/xfs/xfs_dquot.h
diff --git a/fs/xfs/quota/xfs_dquot_item.c b/fs/xfs/xfs_dquot_item.c
similarity index 100%
rename from fs/xfs/quota/xfs_dquot_item.c
rename to fs/xfs/xfs_dquot_item.c
diff --git a/fs/xfs/quota/xfs_dquot_item.h b/fs/xfs/xfs_dquot_item.h
similarity index 100%
rename from fs/xfs/quota/xfs_dquot_item.h
rename to fs/xfs/xfs_dquot_item.h
diff --git a/fs/xfs/linux-2.6/xfs_export.c b/fs/xfs/xfs_export.c
similarity index 100%
rename from fs/xfs/linux-2.6/xfs_export.c
rename to fs/xfs/xfs_export.c
diff --git a/fs/xfs/linux-2.6/xfs_export.h b/fs/xfs/xfs_export.h
similarity index 100%
rename from fs/xfs/linux-2.6/xfs_export.h
rename to fs/xfs/xfs_export.h
diff --git a/fs/xfs/linux-2.6/xfs_file.c b/fs/xfs/xfs_file.c
similarity index 100%
rename from fs/xfs/linux-2.6/xfs_file.c
rename to fs/xfs/xfs_file.c
diff --git a/fs/xfs/linux-2.6/xfs_fs_subr.c b/fs/xfs/xfs_fs_subr.c
similarity index 100%
rename from fs/xfs/linux-2.6/xfs_fs_subr.c
rename to fs/xfs/xfs_fs_subr.c
diff --git a/fs/xfs/linux-2.6/xfs_globals.c b/fs/xfs/xfs_globals.c
similarity index 100%
rename from fs/xfs/linux-2.6/xfs_globals.c
rename to fs/xfs/xfs_globals.c
diff --git a/fs/xfs/linux-2.6/xfs_ioctl.c b/fs/xfs/xfs_ioctl.c
similarity index 100%
rename from fs/xfs/linux-2.6/xfs_ioctl.c
rename to fs/xfs/xfs_ioctl.c
diff --git a/fs/xfs/linux-2.6/xfs_ioctl.h b/fs/xfs/xfs_ioctl.h
similarity index 100%
rename from fs/xfs/linux-2.6/xfs_ioctl.h
rename to fs/xfs/xfs_ioctl.h
diff --git a/fs/xfs/linux-2.6/xfs_ioctl32.c b/fs/xfs/xfs_ioctl32.c
similarity index 100%
rename from fs/xfs/linux-2.6/xfs_ioctl32.c
rename to fs/xfs/xfs_ioctl32.c
diff --git a/fs/xfs/linux-2.6/xfs_ioctl32.h b/fs/xfs/xfs_ioctl32.h
similarity index 100%
rename from fs/xfs/linux-2.6/xfs_ioctl32.h
rename to fs/xfs/xfs_ioctl32.h
diff --git a/fs/xfs/linux-2.6/xfs_iops.c b/fs/xfs/xfs_iops.c
similarity index 98%
rename from fs/xfs/linux-2.6/xfs_iops.c
rename to fs/xfs/xfs_iops.c
index b9c172b..673704f 100644
--- a/fs/xfs/linux-2.6/xfs_iops.c
+++ b/fs/xfs/xfs_iops.c
@@ -70,9 +70,8 @@
}
/*
- * If the linux inode is valid, mark it dirty.
- * Used when committing a dirty inode into a transaction so that
- * the inode will get written back by the linux code
+ * If the linux inode is valid, mark it dirty, else mark the dirty state
+ * in the XFS inode to make sure we pick it up when reclaiming the inode.
*/
void
xfs_mark_inode_dirty_sync(
@@ -82,6 +81,10 @@
if (!(inode->i_state & (I_WILL_FREE|I_FREEING)))
mark_inode_dirty_sync(inode);
+ else {
+ barrier();
+ ip->i_update_core = 1;
+ }
}
void
@@ -92,6 +95,11 @@
if (!(inode->i_state & (I_WILL_FREE|I_FREEING)))
mark_inode_dirty(inode);
+ else {
+ barrier();
+ ip->i_update_core = 1;
+ }
+
}
/*
diff --git a/fs/xfs/linux-2.6/xfs_iops.h b/fs/xfs/xfs_iops.h
similarity index 100%
rename from fs/xfs/linux-2.6/xfs_iops.h
rename to fs/xfs/xfs_iops.h
diff --git a/fs/xfs/linux-2.6/xfs_linux.h b/fs/xfs/xfs_linux.h
similarity index 95%
rename from fs/xfs/linux-2.6/xfs_linux.h
rename to fs/xfs/xfs_linux.h
index d42f814..1e8a45e 100644
--- a/fs/xfs/linux-2.6/xfs_linux.h
+++ b/fs/xfs/xfs_linux.h
@@ -32,13 +32,12 @@
# define XFS_BIG_INUMS 0
#endif
-#include <xfs_types.h>
+#include "xfs_types.h"
-#include <kmem.h>
-#include <mrlock.h>
-#include <time.h>
-
-#include <support/uuid.h>
+#include "kmem.h"
+#include "mrlock.h"
+#include "time.h"
+#include "uuid.h"
#include <linux/semaphore.h>
#include <linux/mm.h>
@@ -78,14 +77,14 @@
#include <asm/byteorder.h>
#include <asm/unaligned.h>
-#include <xfs_vnode.h>
-#include <xfs_stats.h>
-#include <xfs_sysctl.h>
-#include <xfs_iops.h>
-#include <xfs_aops.h>
-#include <xfs_super.h>
-#include <xfs_buf.h>
-#include <xfs_message.h>
+#include "xfs_vnode.h"
+#include "xfs_stats.h"
+#include "xfs_sysctl.h"
+#include "xfs_iops.h"
+#include "xfs_aops.h"
+#include "xfs_super.h"
+#include "xfs_buf.h"
+#include "xfs_message.h"
#ifdef __BIG_ENDIAN
#define XFS_NATIVE_HOST 1
diff --git a/fs/xfs/linux-2.6/xfs_message.c b/fs/xfs/xfs_message.c
similarity index 100%
rename from fs/xfs/linux-2.6/xfs_message.c
rename to fs/xfs/xfs_message.c
diff --git a/fs/xfs/linux-2.6/xfs_message.h b/fs/xfs/xfs_message.h
similarity index 100%
rename from fs/xfs/linux-2.6/xfs_message.h
rename to fs/xfs/xfs_message.h
diff --git a/fs/xfs/quota/xfs_qm.c b/fs/xfs/xfs_qm.c
similarity index 100%
rename from fs/xfs/quota/xfs_qm.c
rename to fs/xfs/xfs_qm.c
diff --git a/fs/xfs/quota/xfs_qm.h b/fs/xfs/xfs_qm.h
similarity index 100%
rename from fs/xfs/quota/xfs_qm.h
rename to fs/xfs/xfs_qm.h
diff --git a/fs/xfs/quota/xfs_qm_bhv.c b/fs/xfs/xfs_qm_bhv.c
similarity index 100%
rename from fs/xfs/quota/xfs_qm_bhv.c
rename to fs/xfs/xfs_qm_bhv.c
diff --git a/fs/xfs/quota/xfs_qm_stats.c b/fs/xfs/xfs_qm_stats.c
similarity index 100%
rename from fs/xfs/quota/xfs_qm_stats.c
rename to fs/xfs/xfs_qm_stats.c
diff --git a/fs/xfs/quota/xfs_qm_stats.h b/fs/xfs/xfs_qm_stats.h
similarity index 100%
rename from fs/xfs/quota/xfs_qm_stats.h
rename to fs/xfs/xfs_qm_stats.h
diff --git a/fs/xfs/quota/xfs_qm_syscalls.c b/fs/xfs/xfs_qm_syscalls.c
similarity index 100%
rename from fs/xfs/quota/xfs_qm_syscalls.c
rename to fs/xfs/xfs_qm_syscalls.c
diff --git a/fs/xfs/quota/xfs_quota_priv.h b/fs/xfs/xfs_quota_priv.h
similarity index 100%
rename from fs/xfs/quota/xfs_quota_priv.h
rename to fs/xfs/xfs_quota_priv.h
diff --git a/fs/xfs/linux-2.6/xfs_quotaops.c b/fs/xfs/xfs_quotaops.c
similarity index 98%
rename from fs/xfs/linux-2.6/xfs_quotaops.c
rename to fs/xfs/xfs_quotaops.c
index 29b9d64..7e76f53 100644
--- a/fs/xfs/linux-2.6/xfs_quotaops.c
+++ b/fs/xfs/xfs_quotaops.c
@@ -25,7 +25,7 @@
#include "xfs_trans.h"
#include "xfs_bmap_btree.h"
#include "xfs_inode.h"
-#include "quota/xfs_qm.h"
+#include "xfs_qm.h"
#include <linux/quota.h>
diff --git a/fs/xfs/linux-2.6/xfs_stats.c b/fs/xfs/xfs_stats.c
similarity index 100%
rename from fs/xfs/linux-2.6/xfs_stats.c
rename to fs/xfs/xfs_stats.c
diff --git a/fs/xfs/linux-2.6/xfs_stats.h b/fs/xfs/xfs_stats.h
similarity index 100%
rename from fs/xfs/linux-2.6/xfs_stats.h
rename to fs/xfs/xfs_stats.h
diff --git a/fs/xfs/linux-2.6/xfs_super.c b/fs/xfs/xfs_super.c
similarity index 97%
rename from fs/xfs/linux-2.6/xfs_super.c
rename to fs/xfs/xfs_super.c
index 9a72dda..2366c54 100644
--- a/fs/xfs/linux-2.6/xfs_super.c
+++ b/fs/xfs/xfs_super.c
@@ -356,6 +356,8 @@
mp->m_flags |= XFS_MOUNT_DELAYLOG;
} else if (!strcmp(this_char, MNTOPT_NODELAYLOG)) {
mp->m_flags &= ~XFS_MOUNT_DELAYLOG;
+ xfs_warn(mp,
+ "nodelaylog is deprecated and will be removed in Linux 3.3");
} else if (!strcmp(this_char, MNTOPT_DISCARD)) {
mp->m_flags |= XFS_MOUNT_DISCARD;
} else if (!strcmp(this_char, MNTOPT_NODISCARD)) {
@@ -877,33 +879,17 @@
struct xfs_trans *tp;
int error;
- xfs_iunlock(ip, XFS_ILOCK_SHARED);
tp = xfs_trans_alloc(mp, XFS_TRANS_FSYNC_TS);
error = xfs_trans_reserve(tp, 0, XFS_FSYNC_TS_LOG_RES(mp), 0, 0, 0);
-
if (error) {
xfs_trans_cancel(tp, 0);
- /* we need to return with the lock hold shared */
- xfs_ilock(ip, XFS_ILOCK_SHARED);
return error;
}
xfs_ilock(ip, XFS_ILOCK_EXCL);
-
- /*
- * Note - it's possible that we might have pushed ourselves out of the
- * way during trans_reserve which would flush the inode. But there's
- * no guarantee that the inode buffer has actually gone out yet (it's
- * delwri). Plus the buffer could be pinned anyway if it's part of
- * an inode in another recent transaction. So we play it safe and
- * fire off the transaction anyway.
- */
- xfs_trans_ijoin(tp, ip);
+ xfs_trans_ijoin_ref(tp, ip, XFS_ILOCK_EXCL);
xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE);
- error = xfs_trans_commit(tp, 0);
- xfs_ilock_demote(ip, XFS_ILOCK_EXCL);
-
- return error;
+ return xfs_trans_commit(tp, 0);
}
STATIC int
@@ -918,7 +904,9 @@
trace_xfs_write_inode(ip);
if (XFS_FORCED_SHUTDOWN(mp))
- return XFS_ERROR(EIO);
+ return -XFS_ERROR(EIO);
+ if (!ip->i_update_core)
+ return 0;
if (wbc->sync_mode == WB_SYNC_ALL) {
/*
@@ -929,12 +917,10 @@
* of synchronous log foces dramatically.
*/
xfs_ioend_wait(ip);
- xfs_ilock(ip, XFS_ILOCK_SHARED);
- if (ip->i_update_core) {
- error = xfs_log_inode(ip);
- if (error)
- goto out_unlock;
- }
+ error = xfs_log_inode(ip);
+ if (error)
+ goto out;
+ return 0;
} else {
/*
* We make this non-blocking if the inode is contended, return
diff --git a/fs/xfs/linux-2.6/xfs_super.h b/fs/xfs/xfs_super.h
similarity index 100%
rename from fs/xfs/linux-2.6/xfs_super.h
rename to fs/xfs/xfs_super.h
diff --git a/fs/xfs/linux-2.6/xfs_sync.c b/fs/xfs/xfs_sync.c
similarity index 100%
rename from fs/xfs/linux-2.6/xfs_sync.c
rename to fs/xfs/xfs_sync.c
diff --git a/fs/xfs/linux-2.6/xfs_sync.h b/fs/xfs/xfs_sync.h
similarity index 100%
rename from fs/xfs/linux-2.6/xfs_sync.h
rename to fs/xfs/xfs_sync.h
diff --git a/fs/xfs/linux-2.6/xfs_sysctl.c b/fs/xfs/xfs_sysctl.c
similarity index 100%
rename from fs/xfs/linux-2.6/xfs_sysctl.c
rename to fs/xfs/xfs_sysctl.c
diff --git a/fs/xfs/linux-2.6/xfs_sysctl.h b/fs/xfs/xfs_sysctl.h
similarity index 100%
rename from fs/xfs/linux-2.6/xfs_sysctl.h
rename to fs/xfs/xfs_sysctl.h
diff --git a/fs/xfs/linux-2.6/xfs_trace.c b/fs/xfs/xfs_trace.c
similarity index 95%
rename from fs/xfs/linux-2.6/xfs_trace.c
rename to fs/xfs/xfs_trace.c
index 88d25d4..9010ce8 100644
--- a/fs/xfs/linux-2.6/xfs_trace.c
+++ b/fs/xfs/xfs_trace.c
@@ -43,8 +43,8 @@
#include "xfs_quota.h"
#include "xfs_iomap.h"
#include "xfs_aops.h"
-#include "quota/xfs_dquot_item.h"
-#include "quota/xfs_dquot.h"
+#include "xfs_dquot_item.h"
+#include "xfs_dquot.h"
#include "xfs_log_recover.h"
#include "xfs_inode_item.h"
diff --git a/fs/xfs/linux-2.6/xfs_trace.h b/fs/xfs/xfs_trace.h
similarity index 100%
rename from fs/xfs/linux-2.6/xfs_trace.h
rename to fs/xfs/xfs_trace.h
diff --git a/fs/xfs/quota/xfs_trans_dquot.c b/fs/xfs/xfs_trans_dquot.c
similarity index 100%
rename from fs/xfs/quota/xfs_trans_dquot.c
rename to fs/xfs/xfs_trans_dquot.c
diff --git a/fs/xfs/linux-2.6/xfs_vnode.h b/fs/xfs/xfs_vnode.h
similarity index 100%
rename from fs/xfs/linux-2.6/xfs_vnode.h
rename to fs/xfs/xfs_vnode.h
diff --git a/fs/xfs/linux-2.6/xfs_xattr.c b/fs/xfs/xfs_xattr.c
similarity index 100%
rename from fs/xfs/linux-2.6/xfs_xattr.c
rename to fs/xfs/xfs_xattr.c
diff --git a/include/asm-generic/unistd.h b/include/asm-generic/unistd.h
index 4f769593..f4c38d8c 100644
--- a/include/asm-generic/unistd.h
+++ b/include/asm-generic/unistd.h
@@ -143,7 +143,7 @@
/* fs/nfsctl.c */
#define __NR_nfsservctl 42
-__SC_COMP(__NR_nfsservctl, sys_nfsservctl, compat_sys_nfsservctl)
+__SYSCALL(__NR_nfsservctl, sys_ni_syscall)
/* fs/open.c */
#define __NR3264_statfs 43
diff --git a/include/linux/compat.h b/include/linux/compat.h
index 8779405..c6e7523 100644
--- a/include/linux/compat.h
+++ b/include/linux/compat.h
@@ -438,7 +438,6 @@
struct compat_timespec __user *tsp,
const compat_sigset_t __user *sigmask,
compat_size_t sigsetsize);
-asmlinkage long compat_sys_nfsservctl(int cmd, void *notused, void *notused2);
asmlinkage long compat_sys_signalfd4(int ufd,
const compat_sigset_t __user *sigmask,
compat_size_t sigsetsize, int flags);
diff --git a/include/linux/connector.h b/include/linux/connector.h
index 0c69ad8..3c9c54f 100644
--- a/include/linux/connector.h
+++ b/include/linux/connector.h
@@ -1,7 +1,7 @@
/*
* connector.h
*
- * 2004-2005 Copyright (c) Evgeniy Polyakov <johnpol@2ka.mipt.ru>
+ * 2004-2005 Copyright (c) Evgeniy Polyakov <zbr@ioremap.net>
* All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
diff --git a/include/linux/cpu_pm.h b/include/linux/cpu_pm.h
new file mode 100644
index 0000000..455b233
--- /dev/null
+++ b/include/linux/cpu_pm.h
@@ -0,0 +1,109 @@
+/*
+ * Copyright (C) 2011 Google, Inc.
+ *
+ * Author:
+ * Colin Cross <ccross@android.com>
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * 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.
+ *
+ */
+
+#ifndef _LINUX_CPU_PM_H
+#define _LINUX_CPU_PM_H
+
+#include <linux/kernel.h>
+#include <linux/notifier.h>
+
+/*
+ * When a CPU goes to a low power state that turns off power to the CPU's
+ * power domain, the contents of some blocks (floating point coprocessors,
+ * interrupt controllers, caches, timers) in the same power domain can
+ * be lost. The cpm_pm notifiers provide a method for platform idle, suspend,
+ * and hotplug implementations to notify the drivers for these blocks that
+ * they may be reset.
+ *
+ * All cpu_pm notifications must be called with interrupts disabled.
+ *
+ * The notifications are split into two classes: CPU notifications and CPU
+ * cluster notifications.
+ *
+ * CPU notifications apply to a single CPU and must be called on the affected
+ * CPU. They are used to save per-cpu context for affected blocks.
+ *
+ * CPU cluster notifications apply to all CPUs in a single power domain. They
+ * are used to save any global context for affected blocks, and must be called
+ * after all the CPUs in the power domain have been notified of the low power
+ * state.
+ */
+
+/*
+ * Event codes passed as unsigned long val to notifier calls
+ */
+enum cpu_pm_event {
+ /* A single cpu is entering a low power state */
+ CPU_PM_ENTER,
+
+ /* A single cpu failed to enter a low power state */
+ CPU_PM_ENTER_FAILED,
+
+ /* A single cpu is exiting a low power state */
+ CPU_PM_EXIT,
+
+ /* A cpu power domain is entering a low power state */
+ CPU_CLUSTER_PM_ENTER,
+
+ /* A cpu power domain failed to enter a low power state */
+ CPU_CLUSTER_PM_ENTER_FAILED,
+
+ /* A cpu power domain is exiting a low power state */
+ CPU_CLUSTER_PM_EXIT,
+};
+
+#ifdef CONFIG_CPU_PM
+int cpu_pm_register_notifier(struct notifier_block *nb);
+int cpu_pm_unregister_notifier(struct notifier_block *nb);
+int cpu_pm_enter(void);
+int cpu_pm_exit(void);
+int cpu_cluster_pm_enter(void);
+int cpu_cluster_pm_exit(void);
+
+#else
+
+static inline int cpu_pm_register_notifier(struct notifier_block *nb)
+{
+ return 0;
+}
+
+static inline int cpu_pm_unregister_notifier(struct notifier_block *nb)
+{
+ return 0;
+}
+
+static inline int cpu_pm_enter(void)
+{
+ return 0;
+}
+
+static inline int cpu_pm_exit(void)
+{
+ return 0;
+}
+
+static inline int cpu_cluster_pm_enter(void)
+{
+ return 0;
+}
+
+static inline int cpu_cluster_pm_exit(void)
+{
+ return 0;
+}
+#endif
+#endif
diff --git a/include/linux/fs.h b/include/linux/fs.h
index 178cdb4..c2bd68f 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -2318,6 +2318,11 @@
extern struct inode * iget_locked(struct super_block *, unsigned long);
extern int insert_inode_locked4(struct inode *, unsigned long, int (*test)(struct inode *, void *), void *);
extern int insert_inode_locked(struct inode *);
+#ifdef CONFIG_DEBUG_LOCK_ALLOC
+extern void lockdep_annotate_inode_mutex_key(struct inode *inode);
+#else
+static inline void lockdep_annotate_inode_mutex_key(struct inode *inode) { };
+#endif
extern void unlock_new_inode(struct inode *);
extern unsigned int get_next_ino(void);
diff --git a/include/linux/fuse.h b/include/linux/fuse.h
index d464de5..464cff5 100644
--- a/include/linux/fuse.h
+++ b/include/linux/fuse.h
@@ -47,6 +47,9 @@
* - FUSE_IOCTL_UNRESTRICTED shall now return with array of 'struct
* fuse_ioctl_iovec' instead of ambiguous 'struct iovec'
* - add FUSE_IOCTL_32BIT flag
+ *
+ * 7.17
+ * - add FUSE_FLOCK_LOCKS and FUSE_RELEASE_FLOCK_UNLOCK
*/
#ifndef _LINUX_FUSE_H
@@ -78,7 +81,7 @@
#define FUSE_KERNEL_VERSION 7
/** Minor version number of this interface */
-#define FUSE_KERNEL_MINOR_VERSION 16
+#define FUSE_KERNEL_MINOR_VERSION 17
/** The node ID of the root inode */
#define FUSE_ROOT_ID 1
@@ -153,8 +156,10 @@
/**
* INIT request/reply flags
*
+ * FUSE_POSIX_LOCKS: remote locking for POSIX file locks
* FUSE_EXPORT_SUPPORT: filesystem handles lookups of "." and ".."
* FUSE_DONT_MASK: don't apply umask to file mode on create operations
+ * FUSE_FLOCK_LOCKS: remote locking for BSD style file locks
*/
#define FUSE_ASYNC_READ (1 << 0)
#define FUSE_POSIX_LOCKS (1 << 1)
@@ -163,6 +168,7 @@
#define FUSE_EXPORT_SUPPORT (1 << 4)
#define FUSE_BIG_WRITES (1 << 5)
#define FUSE_DONT_MASK (1 << 6)
+#define FUSE_FLOCK_LOCKS (1 << 10)
/**
* CUSE INIT request/reply flags
@@ -175,6 +181,7 @@
* Release flags
*/
#define FUSE_RELEASE_FLUSH (1 << 0)
+#define FUSE_RELEASE_FLOCK_UNLOCK (1 << 1)
/**
* Getattr flags
diff --git a/include/linux/perf_event.h b/include/linux/perf_event.h
index 245bafd..c816075 100644
--- a/include/linux/perf_event.h
+++ b/include/linux/perf_event.h
@@ -944,8 +944,10 @@
extern int perf_num_counters(void);
extern const char *perf_pmu_name(void);
-extern void __perf_event_task_sched_in(struct task_struct *task);
-extern void __perf_event_task_sched_out(struct task_struct *task, struct task_struct *next);
+extern void __perf_event_task_sched_in(struct task_struct *prev,
+ struct task_struct *task);
+extern void __perf_event_task_sched_out(struct task_struct *prev,
+ struct task_struct *next);
extern int perf_event_init_task(struct task_struct *child);
extern void perf_event_exit_task(struct task_struct *child);
extern void perf_event_free_task(struct task_struct *task);
@@ -1059,17 +1061,20 @@
extern struct jump_label_key perf_sched_events;
-static inline void perf_event_task_sched_in(struct task_struct *task)
+static inline void perf_event_task_sched_in(struct task_struct *prev,
+ struct task_struct *task)
{
if (static_branch(&perf_sched_events))
- __perf_event_task_sched_in(task);
+ __perf_event_task_sched_in(prev, task);
}
-static inline void perf_event_task_sched_out(struct task_struct *task, struct task_struct *next)
+static inline void perf_event_task_sched_out(struct task_struct *prev,
+ struct task_struct *next)
{
perf_sw_event(PERF_COUNT_SW_CONTEXT_SWITCHES, 1, NULL, 0);
- __perf_event_task_sched_out(task, next);
+ if (static_branch(&perf_sched_events))
+ __perf_event_task_sched_out(prev, next);
}
extern void perf_event_mmap(struct vm_area_struct *vma);
@@ -1139,10 +1144,11 @@
extern void perf_event_task_tick(void);
#else
static inline void
-perf_event_task_sched_in(struct task_struct *task) { }
+perf_event_task_sched_in(struct task_struct *prev,
+ struct task_struct *task) { }
static inline void
-perf_event_task_sched_out(struct task_struct *task,
- struct task_struct *next) { }
+perf_event_task_sched_out(struct task_struct *prev,
+ struct task_struct *next) { }
static inline int perf_event_init_task(struct task_struct *child) { return 0; }
static inline void perf_event_exit_task(struct task_struct *child) { }
static inline void perf_event_free_task(struct task_struct *task) { }
diff --git a/include/linux/personality.h b/include/linux/personality.h
index eec3bae..8fc7dd1a 100644
--- a/include/linux/personality.h
+++ b/include/linux/personality.h
@@ -22,6 +22,7 @@
* These occupy the top three bytes.
*/
enum {
+ UNAME26 = 0x0020000,
ADDR_NO_RANDOMIZE = 0x0040000, /* disable randomization of VA space */
FDPIC_FUNCPTRS = 0x0080000, /* userspace function ptrs point to descriptors
* (signal handling)
diff --git a/include/linux/pwm_backlight.h b/include/linux/pwm_backlight.h
index 5e3e25a..63d2df4 100644
--- a/include/linux/pwm_backlight.h
+++ b/include/linux/pwm_backlight.h
@@ -14,6 +14,7 @@
unsigned int pwm_period_ns;
int (*init)(struct device *dev);
int (*notify)(struct device *dev, int brightness);
+ void (*notify_after)(struct device *dev, int brightness);
void (*exit)(struct device *dev);
int (*check_fb)(struct device *dev, struct fb_info *info);
};
diff --git a/include/linux/regulator/consumer.h b/include/linux/regulator/consumer.h
index 26f6ea4..b47771a 100644
--- a/include/linux/regulator/consumer.h
+++ b/include/linux/regulator/consumer.h
@@ -123,7 +123,7 @@
const char *supply;
struct regulator *consumer;
- /* Internal use */
+ /* private: Internal use */
int ret;
};
diff --git a/include/linux/rio_regs.h b/include/linux/rio_regs.h
index 9026b30..218168a 100644
--- a/include/linux/rio_regs.h
+++ b/include/linux/rio_regs.h
@@ -36,12 +36,12 @@
#define RIO_PEF_PROCESSOR 0x20000000 /* [I] Processor */
#define RIO_PEF_SWITCH 0x10000000 /* [I] Switch */
#define RIO_PEF_MULTIPORT 0x08000000 /* [VI, 2.1] Multiport */
-#define RIO_PEF_INB_MBOX 0x00f00000 /* [II] Mailboxes */
-#define RIO_PEF_INB_MBOX0 0x00800000 /* [II] Mailbox 0 */
-#define RIO_PEF_INB_MBOX1 0x00400000 /* [II] Mailbox 1 */
-#define RIO_PEF_INB_MBOX2 0x00200000 /* [II] Mailbox 2 */
-#define RIO_PEF_INB_MBOX3 0x00100000 /* [II] Mailbox 3 */
-#define RIO_PEF_INB_DOORBELL 0x00080000 /* [II] Doorbells */
+#define RIO_PEF_INB_MBOX 0x00f00000 /* [II, <= 1.2] Mailboxes */
+#define RIO_PEF_INB_MBOX0 0x00800000 /* [II, <= 1.2] Mailbox 0 */
+#define RIO_PEF_INB_MBOX1 0x00400000 /* [II, <= 1.2] Mailbox 1 */
+#define RIO_PEF_INB_MBOX2 0x00200000 /* [II, <= 1.2] Mailbox 2 */
+#define RIO_PEF_INB_MBOX3 0x00100000 /* [II, <= 1.2] Mailbox 3 */
+#define RIO_PEF_INB_DOORBELL 0x00080000 /* [II, <= 1.2] Doorbells */
#define RIO_PEF_EXT_RT 0x00000200 /* [III, 1.3] Extended route table support */
#define RIO_PEF_STD_RT 0x00000100 /* [III, 1.3] Standard route table support */
#define RIO_PEF_CTLS 0x00000010 /* [III] CTLS */
@@ -102,7 +102,7 @@
#define RIO_SWITCH_RT_LIMIT 0x34 /* [III, 1.3] Switch Route Table Destination ID Limit CAR */
#define RIO_RT_MAX_DESTID 0x0000ffff
-#define RIO_MBOX_CSR 0x40 /* [II] Mailbox CSR */
+#define RIO_MBOX_CSR 0x40 /* [II, <= 1.2] Mailbox CSR */
#define RIO_MBOX0_AVAIL 0x80000000 /* [II] Mbox 0 avail */
#define RIO_MBOX0_FULL 0x40000000 /* [II] Mbox 0 full */
#define RIO_MBOX0_EMPTY 0x20000000 /* [II] Mbox 0 empty */
@@ -128,8 +128,8 @@
#define RIO_MBOX3_FAIL 0x00000008 /* [II] Mbox 3 fail */
#define RIO_MBOX3_ERROR 0x00000004 /* [II] Mbox 3 error */
-#define RIO_WRITE_PORT_CSR 0x44 /* [I] Write Port CSR */
-#define RIO_DOORBELL_CSR 0x44 /* [II] Doorbell CSR */
+#define RIO_WRITE_PORT_CSR 0x44 /* [I, <= 1.2] Write Port CSR */
+#define RIO_DOORBELL_CSR 0x44 /* [II, <= 1.2] Doorbell CSR */
#define RIO_DOORBELL_AVAIL 0x80000000 /* [II] Doorbell avail */
#define RIO_DOORBELL_FULL 0x40000000 /* [II] Doorbell full */
#define RIO_DOORBELL_EMPTY 0x20000000 /* [II] Doorbell empty */
diff --git a/include/linux/syscalls.h b/include/linux/syscalls.h
index 8c03b98..1ff0ec2 100644
--- a/include/linux/syscalls.h
+++ b/include/linux/syscalls.h
@@ -702,9 +702,6 @@
asmlinkage long sys_sysinfo(struct sysinfo __user *info);
asmlinkage long sys_sysfs(int option,
unsigned long arg1, unsigned long arg2);
-asmlinkage long sys_nfsservctl(int cmd,
- struct nfsctl_arg __user *arg,
- void __user *res);
asmlinkage long sys_syslog(int type, char __user *buf, int len);
asmlinkage long sys_uselib(const char __user *library);
asmlinkage long sys_ni_syscall(void);
diff --git a/include/linux/ti_wilink_st.h b/include/linux/ti_wilink_st.h
index b004e55..2ef4385 100644
--- a/include/linux/ti_wilink_st.h
+++ b/include/linux/ti_wilink_st.h
@@ -410,7 +410,28 @@
u16 plen;
} __attribute__ ((packed));
-/* platform data */
+/**
+ * struct ti_st_plat_data - platform data shared between ST driver and
+ * platform specific board file which adds the ST device.
+ * @nshutdown_gpio: Host's GPIO line to which chip's BT_EN is connected.
+ * @dev_name: The UART/TTY name to which chip is interfaced. (eg: /dev/ttyS1)
+ * @flow_cntrl: Should always be 1, since UART's CTS/RTS is used for PM
+ * purposes.
+ * @baud_rate: The baud rate supported by the Host UART controller, this will
+ * be shared across with the chip via a HCI VS command from User-Space Init
+ * Mgr application.
+ * @suspend:
+ * @resume: legacy PM routines hooked to platform specific board file, so as
+ * to take chip-host interface specific action.
+ * @chip_enable:
+ * @chip_disable: Platform/Interface specific mux mode setting, GPIO
+ * configuring, Host side PM disabling etc.. can be done here.
+ * @chip_asleep:
+ * @chip_awake: Chip specific deep sleep states is communicated to Host
+ * specific board-xx.c to take actions such as cut UART clocks when chip
+ * asleep or run host faster when chip awake etc..
+ *
+ */
struct ti_st_plat_data {
long nshutdown_gpio;
unsigned char dev_name[UART_DEV_NAME_LEN]; /* uart name */
@@ -418,6 +439,10 @@
unsigned long baud_rate;
int (*suspend)(struct platform_device *, pm_message_t);
int (*resume)(struct platform_device *);
+ int (*chip_enable) (struct kim_data_s *);
+ int (*chip_disable) (struct kim_data_s *);
+ int (*chip_asleep) (struct kim_data_s *);
+ int (*chip_awake) (struct kim_data_s *);
};
#endif /* TI_WILINK_ST_H */
diff --git a/include/linux/tty.h b/include/linux/tty.h
index 44bc0c5..5f2ede8 100644
--- a/include/linux/tty.h
+++ b/include/linux/tty.h
@@ -421,6 +421,8 @@
extern void tty_throttle(struct tty_struct *tty);
extern void tty_unthrottle(struct tty_struct *tty);
extern int tty_do_resize(struct tty_struct *tty, struct winsize *ws);
+extern void tty_driver_remove_tty(struct tty_driver *driver,
+ struct tty_struct *tty);
extern void tty_shutdown(struct tty_struct *tty);
extern void tty_free_termios(struct tty_struct *tty);
extern int is_current_pgrp_orphaned(void);
diff --git a/include/linux/tty_driver.h b/include/linux/tty_driver.h
index 9deeac8..ecdaeb9 100644
--- a/include/linux/tty_driver.h
+++ b/include/linux/tty_driver.h
@@ -47,6 +47,9 @@
*
* This routine is called synchronously when a particular tty device
* is closed for the last time freeing up the resources.
+ * Note that tty_shutdown() is not called if ops->shutdown is defined.
+ * This means one is responsible to take care of calling ops->remove (e.g.
+ * via tty_driver_remove_tty) and releasing tty->termios.
*
*
* void (*cleanup)(struct tty_struct * tty);
diff --git a/include/linux/writeback.h b/include/linux/writeback.h
index f1bfa12e..2b8963f 100644
--- a/include/linux/writeback.h
+++ b/include/linux/writeback.h
@@ -12,15 +12,6 @@
*
* (thresh - thresh/DIRTY_FULL_SCOPE, thresh)
*
- * The 1/16 region above the global dirty limit will be put to maximum pauses:
- *
- * (limit, limit + limit/DIRTY_MAXPAUSE_AREA)
- *
- * The 1/16 region above the max-pause region, dirty exceeded bdi's will be put
- * to loops:
- *
- * (limit + limit/DIRTY_MAXPAUSE_AREA, limit + limit/DIRTY_PASSGOOD_AREA)
- *
* Further beyond, all dirtier tasks will enter a loop waiting (possibly long
* time) for the dirty pages to drop, unless written enough pages.
*
@@ -31,8 +22,6 @@
*/
#define DIRTY_SCOPE 8
#define DIRTY_FULL_SCOPE (DIRTY_SCOPE / 2)
-#define DIRTY_MAXPAUSE_AREA 16
-#define DIRTY_PASSGOOD_AREA 8
/*
* 4MB minimal write chunk size
diff --git a/include/net/9p/9p.h b/include/net/9p/9p.h
index 342dcf1..a6326ef 100644
--- a/include/net/9p/9p.h
+++ b/include/net/9p/9p.h
@@ -288,6 +288,35 @@
P9_DMSETVTX = 0x00010000,
};
+/* 9p2000.L open flags */
+#define P9_DOTL_RDONLY 00000000
+#define P9_DOTL_WRONLY 00000001
+#define P9_DOTL_RDWR 00000002
+#define P9_DOTL_NOACCESS 00000003
+#define P9_DOTL_CREATE 00000100
+#define P9_DOTL_EXCL 00000200
+#define P9_DOTL_NOCTTY 00000400
+#define P9_DOTL_TRUNC 00001000
+#define P9_DOTL_APPEND 00002000
+#define P9_DOTL_NONBLOCK 00004000
+#define P9_DOTL_DSYNC 00010000
+#define P9_DOTL_FASYNC 00020000
+#define P9_DOTL_DIRECT 00040000
+#define P9_DOTL_LARGEFILE 00100000
+#define P9_DOTL_DIRECTORY 00200000
+#define P9_DOTL_NOFOLLOW 00400000
+#define P9_DOTL_NOATIME 01000000
+#define P9_DOTL_CLOEXEC 02000000
+#define P9_DOTL_SYNC 04000000
+
+/* 9p2000.L at flags */
+#define P9_DOTL_AT_REMOVEDIR 0x200
+
+/* 9p2000.L lock type */
+#define P9_LOCK_TYPE_RDLCK 0
+#define P9_LOCK_TYPE_WRLCK 1
+#define P9_LOCK_TYPE_UNLCK 2
+
/**
* enum p9_qid_t - QID types
* @P9_QTDIR: directory
diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index d17f47f..401d73b 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -1744,6 +1744,8 @@
* by default for perm_addr. In this case, the mask should be set to
* all-zeroes. In this case it is assumed that the device can handle
* the same number of arbitrary MAC addresses.
+ * @registered: protects ->resume and ->suspend sysfs callbacks against
+ * unregister hardware
* @debugfsdir: debugfs directory used for this wiphy, will be renamed
* automatically on wiphy renames
* @dev: (virtual) struct device for this wiphy
@@ -1865,6 +1867,9 @@
* you need use set_wiphy_dev() (see below) */
struct device dev;
+ /* protects ->resume, ->suspend sysfs callbacks against unregister hw */
+ bool registered;
+
/* dir in debugfs: ieee80211/<wiphyname> */
struct dentry *debugfsdir;
diff --git a/include/target/target_core_fabric_ops.h b/include/target/target_core_fabric_ops.h
index 2de8fe9..126c675 100644
--- a/include/target/target_core_fabric_ops.h
+++ b/include/target/target_core_fabric_ops.h
@@ -27,6 +27,12 @@
int (*tpg_check_demo_mode_cache)(struct se_portal_group *);
int (*tpg_check_demo_mode_write_protect)(struct se_portal_group *);
int (*tpg_check_prod_mode_write_protect)(struct se_portal_group *);
+ /*
+ * Optionally used by fabrics to allow demo-mode login, but not
+ * expose any TPG LUNs, and return 'not connected' in standard
+ * inquiry response
+ */
+ int (*tpg_check_demo_mode_login_only)(struct se_portal_group *);
struct se_node_acl *(*tpg_alloc_fabric_acl)(
struct se_portal_group *);
void (*tpg_release_fabric_acl)(struct se_portal_group *,
diff --git a/kernel/Makefile b/kernel/Makefile
index eca595e..988cb3d 100644
--- a/kernel/Makefile
+++ b/kernel/Makefile
@@ -101,6 +101,7 @@
obj-$(CONFIG_TRACEPOINTS) += trace/
obj-$(CONFIG_SMP) += sched_cpupri.o
obj-$(CONFIG_IRQ_WORK) += irq_work.o
+obj-$(CONFIG_CPU_PM) += cpu_pm.o
obj-$(CONFIG_PERF_EVENTS) += events/
diff --git a/kernel/cpu_pm.c b/kernel/cpu_pm.c
new file mode 100644
index 0000000..249152e
--- /dev/null
+++ b/kernel/cpu_pm.c
@@ -0,0 +1,233 @@
+/*
+ * Copyright (C) 2011 Google, Inc.
+ *
+ * Author:
+ * Colin Cross <ccross@android.com>
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * 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.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/cpu_pm.h>
+#include <linux/module.h>
+#include <linux/notifier.h>
+#include <linux/spinlock.h>
+#include <linux/syscore_ops.h>
+
+static DEFINE_RWLOCK(cpu_pm_notifier_lock);
+static RAW_NOTIFIER_HEAD(cpu_pm_notifier_chain);
+
+static int cpu_pm_notify(enum cpu_pm_event event, int nr_to_call, int *nr_calls)
+{
+ int ret;
+
+ ret = __raw_notifier_call_chain(&cpu_pm_notifier_chain, event, NULL,
+ nr_to_call, nr_calls);
+
+ return notifier_to_errno(ret);
+}
+
+/**
+ * cpu_pm_register_notifier - register a driver with cpu_pm
+ * @nb: notifier block to register
+ *
+ * Add a driver to a list of drivers that are notified about
+ * CPU and CPU cluster low power entry and exit.
+ *
+ * This function may sleep, and has the same return conditions as
+ * raw_notifier_chain_register.
+ */
+int cpu_pm_register_notifier(struct notifier_block *nb)
+{
+ unsigned long flags;
+ int ret;
+
+ write_lock_irqsave(&cpu_pm_notifier_lock, flags);
+ ret = raw_notifier_chain_register(&cpu_pm_notifier_chain, nb);
+ write_unlock_irqrestore(&cpu_pm_notifier_lock, flags);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(cpu_pm_register_notifier);
+
+/**
+ * cpu_pm_unregister_notifier - unregister a driver with cpu_pm
+ * @nb: notifier block to be unregistered
+ *
+ * Remove a driver from the CPU PM notifier list.
+ *
+ * This function may sleep, and has the same return conditions as
+ * raw_notifier_chain_unregister.
+ */
+int cpu_pm_unregister_notifier(struct notifier_block *nb)
+{
+ unsigned long flags;
+ int ret;
+
+ write_lock_irqsave(&cpu_pm_notifier_lock, flags);
+ ret = raw_notifier_chain_unregister(&cpu_pm_notifier_chain, nb);
+ write_unlock_irqrestore(&cpu_pm_notifier_lock, flags);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(cpu_pm_unregister_notifier);
+
+/**
+ * cpm_pm_enter - CPU low power entry notifier
+ *
+ * Notifies listeners that a single CPU is entering a low power state that may
+ * cause some blocks in the same power domain as the cpu to reset.
+ *
+ * Must be called on the affected CPU with interrupts disabled. Platform is
+ * responsible for ensuring that cpu_pm_enter is not called twice on the same
+ * CPU before cpu_pm_exit is called. Notified drivers can include VFP
+ * co-processor, interrupt controller and it's PM extensions, local CPU
+ * timers context save/restore which shouldn't be interrupted. Hence it
+ * must be called with interrupts disabled.
+ *
+ * Return conditions are same as __raw_notifier_call_chain.
+ */
+int cpu_pm_enter(void)
+{
+ int nr_calls;
+ int ret = 0;
+
+ read_lock(&cpu_pm_notifier_lock);
+ ret = cpu_pm_notify(CPU_PM_ENTER, -1, &nr_calls);
+ if (ret)
+ /*
+ * Inform listeners (nr_calls - 1) about failure of CPU PM
+ * PM entry who are notified earlier to prepare for it.
+ */
+ cpu_pm_notify(CPU_PM_ENTER_FAILED, nr_calls - 1, NULL);
+ read_unlock(&cpu_pm_notifier_lock);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(cpu_pm_enter);
+
+/**
+ * cpm_pm_exit - CPU low power exit notifier
+ *
+ * Notifies listeners that a single CPU is exiting a low power state that may
+ * have caused some blocks in the same power domain as the cpu to reset.
+ *
+ * Notified drivers can include VFP co-processor, interrupt controller
+ * and it's PM extensions, local CPU timers context save/restore which
+ * shouldn't be interrupted. Hence it must be called with interrupts disabled.
+ *
+ * Return conditions are same as __raw_notifier_call_chain.
+ */
+int cpu_pm_exit(void)
+{
+ int ret;
+
+ read_lock(&cpu_pm_notifier_lock);
+ ret = cpu_pm_notify(CPU_PM_EXIT, -1, NULL);
+ read_unlock(&cpu_pm_notifier_lock);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(cpu_pm_exit);
+
+/**
+ * cpm_cluster_pm_enter - CPU cluster low power entry notifier
+ *
+ * Notifies listeners that all cpus in a power domain are entering a low power
+ * state that may cause some blocks in the same power domain to reset.
+ *
+ * Must be called after cpu_pm_enter has been called on all cpus in the power
+ * domain, and before cpu_pm_exit has been called on any cpu in the power
+ * domain. Notified drivers can include VFP co-processor, interrupt controller
+ * and it's PM extensions, local CPU timers context save/restore which
+ * shouldn't be interrupted. Hence it must be called with interrupts disabled.
+ *
+ * Must be called with interrupts disabled.
+ *
+ * Return conditions are same as __raw_notifier_call_chain.
+ */
+int cpu_cluster_pm_enter(void)
+{
+ int nr_calls;
+ int ret = 0;
+
+ read_lock(&cpu_pm_notifier_lock);
+ ret = cpu_pm_notify(CPU_CLUSTER_PM_ENTER, -1, &nr_calls);
+ if (ret)
+ /*
+ * Inform listeners (nr_calls - 1) about failure of CPU cluster
+ * PM entry who are notified earlier to prepare for it.
+ */
+ cpu_pm_notify(CPU_CLUSTER_PM_ENTER_FAILED, nr_calls - 1, NULL);
+ read_unlock(&cpu_pm_notifier_lock);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(cpu_cluster_pm_enter);
+
+/**
+ * cpm_cluster_pm_exit - CPU cluster low power exit notifier
+ *
+ * Notifies listeners that all cpus in a power domain are exiting form a
+ * low power state that may have caused some blocks in the same power domain
+ * to reset.
+ *
+ * Must be called after cpu_pm_exit has been called on all cpus in the power
+ * domain, and before cpu_pm_exit has been called on any cpu in the power
+ * domain. Notified drivers can include VFP co-processor, interrupt controller
+ * and it's PM extensions, local CPU timers context save/restore which
+ * shouldn't be interrupted. Hence it must be called with interrupts disabled.
+ *
+ * Return conditions are same as __raw_notifier_call_chain.
+ */
+int cpu_cluster_pm_exit(void)
+{
+ int ret;
+
+ read_lock(&cpu_pm_notifier_lock);
+ ret = cpu_pm_notify(CPU_CLUSTER_PM_EXIT, -1, NULL);
+ read_unlock(&cpu_pm_notifier_lock);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(cpu_cluster_pm_exit);
+
+#ifdef CONFIG_PM
+static int cpu_pm_suspend(void)
+{
+ int ret;
+
+ ret = cpu_pm_enter();
+ if (ret)
+ return ret;
+
+ ret = cpu_cluster_pm_enter();
+ return ret;
+}
+
+static void cpu_pm_resume(void)
+{
+ cpu_cluster_pm_exit();
+ cpu_pm_exit();
+}
+
+static struct syscore_ops cpu_pm_syscore_ops = {
+ .suspend = cpu_pm_suspend,
+ .resume = cpu_pm_resume,
+};
+
+static int cpu_pm_init(void)
+{
+ register_syscore_ops(&cpu_pm_syscore_ops);
+ return 0;
+}
+core_initcall(cpu_pm_init);
+#endif
diff --git a/kernel/events/core.c b/kernel/events/core.c
index b8785e2..fbe38f2 100644
--- a/kernel/events/core.c
+++ b/kernel/events/core.c
@@ -399,14 +399,54 @@
local_irq_restore(flags);
}
-static inline void perf_cgroup_sched_out(struct task_struct *task)
+static inline void perf_cgroup_sched_out(struct task_struct *task,
+ struct task_struct *next)
{
- perf_cgroup_switch(task, PERF_CGROUP_SWOUT);
+ struct perf_cgroup *cgrp1;
+ struct perf_cgroup *cgrp2 = NULL;
+
+ /*
+ * we come here when we know perf_cgroup_events > 0
+ */
+ cgrp1 = perf_cgroup_from_task(task);
+
+ /*
+ * next is NULL when called from perf_event_enable_on_exec()
+ * that will systematically cause a cgroup_switch()
+ */
+ if (next)
+ cgrp2 = perf_cgroup_from_task(next);
+
+ /*
+ * only schedule out current cgroup events if we know
+ * that we are switching to a different cgroup. Otherwise,
+ * do no touch the cgroup events.
+ */
+ if (cgrp1 != cgrp2)
+ perf_cgroup_switch(task, PERF_CGROUP_SWOUT);
}
-static inline void perf_cgroup_sched_in(struct task_struct *task)
+static inline void perf_cgroup_sched_in(struct task_struct *prev,
+ struct task_struct *task)
{
- perf_cgroup_switch(task, PERF_CGROUP_SWIN);
+ struct perf_cgroup *cgrp1;
+ struct perf_cgroup *cgrp2 = NULL;
+
+ /*
+ * we come here when we know perf_cgroup_events > 0
+ */
+ cgrp1 = perf_cgroup_from_task(task);
+
+ /* prev can never be NULL */
+ cgrp2 = perf_cgroup_from_task(prev);
+
+ /*
+ * only need to schedule in cgroup events if we are changing
+ * cgroup during ctxsw. Cgroup events were not scheduled
+ * out of ctxsw out if that was not the case.
+ */
+ if (cgrp1 != cgrp2)
+ perf_cgroup_switch(task, PERF_CGROUP_SWIN);
}
static inline int perf_cgroup_connect(int fd, struct perf_event *event,
@@ -518,11 +558,13 @@
{
}
-static inline void perf_cgroup_sched_out(struct task_struct *task)
+static inline void perf_cgroup_sched_out(struct task_struct *task,
+ struct task_struct *next)
{
}
-static inline void perf_cgroup_sched_in(struct task_struct *task)
+static inline void perf_cgroup_sched_in(struct task_struct *prev,
+ struct task_struct *task)
{
}
@@ -1988,7 +2030,7 @@
* cgroup event are system-wide mode only
*/
if (atomic_read(&__get_cpu_var(perf_cgroup_events)))
- perf_cgroup_sched_out(task);
+ perf_cgroup_sched_out(task, next);
}
static void task_ctx_sched_out(struct perf_event_context *ctx)
@@ -2153,7 +2195,8 @@
* accessing the event control register. If a NMI hits, then it will
* keep the event running.
*/
-void __perf_event_task_sched_in(struct task_struct *task)
+void __perf_event_task_sched_in(struct task_struct *prev,
+ struct task_struct *task)
{
struct perf_event_context *ctx;
int ctxn;
@@ -2171,7 +2214,7 @@
* cgroup event are system-wide mode only
*/
if (atomic_read(&__get_cpu_var(perf_cgroup_events)))
- perf_cgroup_sched_in(task);
+ perf_cgroup_sched_in(prev, task);
}
static u64 perf_calculate_period(struct perf_event *event, u64 nsec, u64 count)
@@ -2427,7 +2470,7 @@
* ctxswin cgroup events which are already scheduled
* in.
*/
- perf_cgroup_sched_out(current);
+ perf_cgroup_sched_out(current, NULL);
raw_spin_lock(&ctx->lock);
task_ctx_sched_out(ctx);
@@ -3353,8 +3396,8 @@
}
static void calc_timer_values(struct perf_event *event,
- u64 *running,
- u64 *enabled)
+ u64 *enabled,
+ u64 *running)
{
u64 now, ctx_time;
@@ -5715,6 +5758,7 @@
pmu = idr_find(&pmu_idr, event->attr.type);
rcu_read_unlock();
if (pmu) {
+ event->pmu = pmu;
ret = pmu->event_init(event);
if (ret)
pmu = ERR_PTR(ret);
@@ -5722,6 +5766,7 @@
}
list_for_each_entry_rcu(pmu, &pmus, entry) {
+ event->pmu = pmu;
ret = pmu->event_init(event);
if (!ret)
goto unlock;
@@ -5848,8 +5893,6 @@
return ERR_PTR(err);
}
- event->pmu = pmu;
-
if (!event->parent) {
if (event->attach_state & PERF_ATTACH_TASK)
jump_label_inc(&perf_sched_events);
diff --git a/kernel/irq/manage.c b/kernel/irq/manage.c
index 2e94258..9b956fa 100644
--- a/kernel/irq/manage.c
+++ b/kernel/irq/manage.c
@@ -1331,7 +1331,6 @@
if (!thread_fn)
return -EINVAL;
handler = irq_default_primary_handler;
- irqflags |= IRQF_ONESHOT;
}
action = kzalloc(sizeof(struct irqaction), GFP_KERNEL);
diff --git a/kernel/power/Kconfig b/kernel/power/Kconfig
index 3744c59..80a8597 100644
--- a/kernel/power/Kconfig
+++ b/kernel/power/Kconfig
@@ -235,3 +235,7 @@
config PM_GENERIC_DOMAINS_RUNTIME
def_bool y
depends on PM_RUNTIME && PM_GENERIC_DOMAINS
+
+config CPU_PM
+ bool
+ depends on SUSPEND || CPU_IDLE
diff --git a/kernel/printk.c b/kernel/printk.c
index 836a2ae..28a40d8 100644
--- a/kernel/printk.c
+++ b/kernel/printk.c
@@ -1604,7 +1604,7 @@
struct console *con;
for_each_console(con) {
- if (con->flags & CON_BOOT) {
+ if (!keep_bootcon && con->flags & CON_BOOT) {
printk(KERN_INFO "turn off boot console %s%d\n",
con->name, con->index);
unregister_console(con);
diff --git a/kernel/sched.c b/kernel/sched.c
index ccacdbd..ec5f472 100644
--- a/kernel/sched.c
+++ b/kernel/sched.c
@@ -3065,7 +3065,7 @@
#ifdef __ARCH_WANT_INTERRUPTS_ON_CTXSW
local_irq_disable();
#endif /* __ARCH_WANT_INTERRUPTS_ON_CTXSW */
- perf_event_task_sched_in(current);
+ perf_event_task_sched_in(prev, current);
#ifdef __ARCH_WANT_INTERRUPTS_ON_CTXSW
local_irq_enable();
#endif /* __ARCH_WANT_INTERRUPTS_ON_CTXSW */
@@ -4279,9 +4279,9 @@
}
/*
- * schedule() is the main scheduler function.
+ * __schedule() is the main scheduler function.
*/
-asmlinkage void __sched schedule(void)
+static void __sched __schedule(void)
{
struct task_struct *prev, *next;
unsigned long *switch_count;
@@ -4322,16 +4322,6 @@
if (to_wakeup)
try_to_wake_up_local(to_wakeup);
}
-
- /*
- * If we are going to sleep and we have plugged IO
- * queued, make sure to submit it to avoid deadlocks.
- */
- if (blk_needs_flush_plug(prev)) {
- raw_spin_unlock(&rq->lock);
- blk_schedule_flush_plug(prev);
- raw_spin_lock(&rq->lock);
- }
}
switch_count = &prev->nvcsw;
}
@@ -4369,6 +4359,26 @@
if (need_resched())
goto need_resched;
}
+
+static inline void sched_submit_work(struct task_struct *tsk)
+{
+ if (!tsk->state)
+ return;
+ /*
+ * If we are going to sleep and we have plugged IO queued,
+ * make sure to submit it to avoid deadlocks.
+ */
+ if (blk_needs_flush_plug(tsk))
+ blk_schedule_flush_plug(tsk);
+}
+
+asmlinkage void schedule(void)
+{
+ struct task_struct *tsk = current;
+
+ sched_submit_work(tsk);
+ __schedule();
+}
EXPORT_SYMBOL(schedule);
#ifdef CONFIG_MUTEX_SPIN_ON_OWNER
@@ -4435,7 +4445,7 @@
do {
add_preempt_count_notrace(PREEMPT_ACTIVE);
- schedule();
+ __schedule();
sub_preempt_count_notrace(PREEMPT_ACTIVE);
/*
@@ -4463,7 +4473,7 @@
do {
add_preempt_count(PREEMPT_ACTIVE);
local_irq_enable();
- schedule();
+ __schedule();
local_irq_disable();
sub_preempt_count(PREEMPT_ACTIVE);
@@ -5588,7 +5598,7 @@
static void __cond_resched(void)
{
add_preempt_count(PREEMPT_ACTIVE);
- schedule();
+ __schedule();
sub_preempt_count(PREEMPT_ACTIVE);
}
@@ -7443,6 +7453,7 @@
struct sched_domain *sd = *per_cpu_ptr(sdd->sd, j);
if (sd && (sd->flags & SD_OVERLAP))
free_sched_groups(sd->groups, 0);
+ kfree(*per_cpu_ptr(sdd->sd, j));
kfree(*per_cpu_ptr(sdd->sg, j));
kfree(*per_cpu_ptr(sdd->sgp, j));
}
diff --git a/kernel/sys.c b/kernel/sys.c
index dd948a1..18ee1d2 100644
--- a/kernel/sys.c
+++ b/kernel/sys.c
@@ -37,6 +37,8 @@
#include <linux/fs_struct.h>
#include <linux/gfp.h>
#include <linux/syscore_ops.h>
+#include <linux/version.h>
+#include <linux/ctype.h>
#include <linux/compat.h>
#include <linux/syscalls.h>
@@ -44,6 +46,8 @@
#include <linux/user_namespace.h>
#include <linux/kmsg_dump.h>
+/* Move somewhere else to avoid recompiling? */
+#include <generated/utsrelease.h>
#include <asm/uaccess.h>
#include <asm/io.h>
@@ -1161,6 +1165,34 @@
#define override_architecture(name) 0
#endif
+/*
+ * Work around broken programs that cannot handle "Linux 3.0".
+ * Instead we map 3.x to 2.6.40+x, so e.g. 3.0 would be 2.6.40
+ */
+static int override_release(char __user *release, int len)
+{
+ int ret = 0;
+ char buf[len];
+
+ if (current->personality & UNAME26) {
+ char *rest = UTS_RELEASE;
+ int ndots = 0;
+ unsigned v;
+
+ while (*rest) {
+ if (*rest == '.' && ++ndots >= 3)
+ break;
+ if (!isdigit(*rest) && *rest != '.')
+ break;
+ rest++;
+ }
+ v = ((LINUX_VERSION_CODE >> 8) & 0xff) + 40;
+ snprintf(buf, len, "2.6.%u%s", v, rest);
+ ret = copy_to_user(release, buf, len);
+ }
+ return ret;
+}
+
SYSCALL_DEFINE1(newuname, struct new_utsname __user *, name)
{
int errno = 0;
@@ -1170,6 +1202,8 @@
errno = -EFAULT;
up_read(&uts_sem);
+ if (!errno && override_release(name->release, sizeof(name->release)))
+ errno = -EFAULT;
if (!errno && override_architecture(name))
errno = -EFAULT;
return errno;
@@ -1191,6 +1225,8 @@
error = -EFAULT;
up_read(&uts_sem);
+ if (!error && override_release(name->release, sizeof(name->release)))
+ error = -EFAULT;
if (!error && override_architecture(name))
error = -EFAULT;
return error;
@@ -1225,6 +1261,8 @@
if (!error && override_architecture(name))
error = -EFAULT;
+ if (!error && override_release(name->release, sizeof(name->release)))
+ error = -EFAULT;
return error ? -EFAULT : 0;
}
#endif
diff --git a/kernel/sys_ni.c b/kernel/sys_ni.c
index 62cbc88..a9a5de0 100644
--- a/kernel/sys_ni.c
+++ b/kernel/sys_ni.c
@@ -16,7 +16,6 @@
return -ENOSYS;
}
-cond_syscall(sys_nfsservctl);
cond_syscall(sys_quotactl);
cond_syscall(sys32_quotactl);
cond_syscall(sys_acct);
diff --git a/kernel/sysctl_binary.c b/kernel/sysctl_binary.c
index 3b8e028..e8bffbe 100644
--- a/kernel/sysctl_binary.c
+++ b/kernel/sysctl_binary.c
@@ -1,6 +1,6 @@
#include <linux/stat.h>
#include <linux/sysctl.h>
-#include "../fs/xfs/linux-2.6/xfs_sysctl.h"
+#include "../fs/xfs/xfs_sysctl.h"
#include <linux/sunrpc/debug.h>
#include <linux/string.h>
#include <net/ip_vs.h>
diff --git a/kernel/sysctl_check.c b/kernel/sysctl_check.c
index 4e4932a..362da65 100644
--- a/kernel/sysctl_check.c
+++ b/kernel/sysctl_check.c
@@ -1,6 +1,6 @@
#include <linux/stat.h>
#include <linux/sysctl.h>
-#include "../fs/xfs/linux-2.6/xfs_sysctl.h"
+#include "../fs/xfs/xfs_sysctl.h"
#include <linux/sunrpc/debug.h>
#include <linux/string.h>
#include <net/ip_vs.h>
diff --git a/kernel/time/alarmtimer.c b/kernel/time/alarmtimer.c
index 59f369f..ea5e1a9 100644
--- a/kernel/time/alarmtimer.c
+++ b/kernel/time/alarmtimer.c
@@ -441,6 +441,8 @@
static void alarm_timer_get(struct k_itimer *timr,
struct itimerspec *cur_setting)
{
+ memset(cur_setting, 0, sizeof(struct itimerspec));
+
cur_setting->it_interval =
ktime_to_timespec(timr->it.alarmtimer.period);
cur_setting->it_value =
@@ -479,11 +481,17 @@
if (!rtcdev)
return -ENOTSUPP;
- /* Save old values */
- old_setting->it_interval =
- ktime_to_timespec(timr->it.alarmtimer.period);
- old_setting->it_value =
- ktime_to_timespec(timr->it.alarmtimer.node.expires);
+ /*
+ * XXX HACK! Currently we can DOS a system if the interval
+ * period on alarmtimers is too small. Cap the interval here
+ * to 100us and solve this properly in a future patch! -jstultz
+ */
+ if ((new_setting->it_interval.tv_sec == 0) &&
+ (new_setting->it_interval.tv_nsec < 100000))
+ new_setting->it_interval.tv_nsec = 100000;
+
+ if (old_setting)
+ alarm_timer_get(timr, old_setting);
/* If the timer was already set, cancel it */
alarm_cancel(&timr->it.alarmtimer);
diff --git a/lib/Makefile b/lib/Makefile
index d5d175c..3f5bc6d 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -12,7 +12,7 @@
idr.o int_sqrt.o extable.o prio_tree.o \
sha1.o md5.o irq_regs.o reciprocal_div.o argv_split.o \
proportions.o prio_heap.o ratelimit.o show_mem.o \
- is_single_threaded.o plist.o decompress.o find_next_bit.o
+ is_single_threaded.o plist.o decompress.o
lib-$(CONFIG_MMU) += ioremap.o
lib-$(CONFIG_SMP) += cpumask.o
@@ -22,7 +22,7 @@
obj-y += bcd.o div64.o sort.o parser.o halfmd4.o debug_locks.o random32.o \
bust_spinlocks.o hexdump.o kasprintf.o bitmap.o scatterlist.o \
string_helpers.o gcd.o lcm.o list_sort.o uuid.o flex_array.o \
- bsearch.o find_last_bit.o
+ bsearch.o find_last_bit.o find_next_bit.o
obj-y += kstrtox.o
obj-$(CONFIG_TEST_KSTRTOX) += test-kstrtox.o
diff --git a/mm/memcontrol.c b/mm/memcontrol.c
index 930de94..ebd1e86 100644
--- a/mm/memcontrol.c
+++ b/mm/memcontrol.c
@@ -1841,29 +1841,23 @@
*/
static bool mem_cgroup_oom_lock(struct mem_cgroup *mem)
{
- int lock_count = -1;
struct mem_cgroup *iter, *failed = NULL;
bool cond = true;
for_each_mem_cgroup_tree_cond(iter, mem, cond) {
- bool locked = iter->oom_lock;
-
- iter->oom_lock = true;
- if (lock_count == -1)
- lock_count = iter->oom_lock;
- else if (lock_count != locked) {
+ if (iter->oom_lock) {
/*
* this subtree of our hierarchy is already locked
* so we cannot give a lock.
*/
- lock_count = 0;
failed = iter;
cond = false;
- }
+ } else
+ iter->oom_lock = true;
}
if (!failed)
- goto done;
+ return true;
/*
* OK, we failed to lock the whole subtree so we have to clean up
@@ -1877,8 +1871,7 @@
}
iter->oom_lock = false;
}
-done:
- return lock_count;
+ return false;
}
/*
@@ -2169,13 +2162,7 @@
/* Notify other cpus that system-wide "drain" is running */
get_online_cpus();
- /*
- * Get a hint for avoiding draining charges on the current cpu,
- * which must be exhausted by our charging. It is not required that
- * this be a precise check, so we use raw_smp_processor_id() instead of
- * getcpu()/putcpu().
- */
- curcpu = raw_smp_processor_id();
+ curcpu = get_cpu();
for_each_online_cpu(cpu) {
struct memcg_stock_pcp *stock = &per_cpu(memcg_stock, cpu);
struct mem_cgroup *mem;
@@ -2192,6 +2179,7 @@
schedule_work_on(cpu, &stock->work);
}
}
+ put_cpu();
if (!sync)
goto out;
diff --git a/mm/page-writeback.c b/mm/page-writeback.c
index d196074..0e309cd 100644
--- a/mm/page-writeback.c
+++ b/mm/page-writeback.c
@@ -754,21 +754,10 @@
* 200ms is typically more than enough to curb heavy dirtiers;
* (b) the pause time limit makes the dirtiers more responsive.
*/
- if (nr_dirty < dirty_thresh +
- dirty_thresh / DIRTY_MAXPAUSE_AREA &&
+ if (nr_dirty < dirty_thresh &&
+ bdi_dirty < (task_bdi_thresh + bdi_thresh) / 2 &&
time_after(jiffies, start_time + MAX_PAUSE))
break;
- /*
- * pass-good area. When some bdi gets blocked (eg. NFS server
- * not responding), or write bandwidth dropped dramatically due
- * to concurrent reads, or dirty threshold suddenly dropped and
- * the dirty pages cannot be brought down anytime soon (eg. on
- * slow USB stick), at least let go of the good bdi's.
- */
- if (nr_dirty < dirty_thresh +
- dirty_thresh / DIRTY_PASSGOOD_AREA &&
- bdi_dirty < bdi_thresh)
- break;
/*
* Increase the delay for each loop, up to our previous
diff --git a/mm/vmscan.c b/mm/vmscan.c
index 7ef6912..b7719ec 100644
--- a/mm/vmscan.c
+++ b/mm/vmscan.c
@@ -2283,7 +2283,7 @@
.mem_cgroup = mem,
.memcg_record = rec,
};
- unsigned long start, end;
+ ktime_t start, end;
sc.gfp_mask = (gfp_mask & GFP_RECLAIM_MASK) |
(GFP_HIGHUSER_MOVABLE & ~GFP_RECLAIM_MASK);
@@ -2292,7 +2292,7 @@
sc.may_writepage,
sc.gfp_mask);
- start = sched_clock();
+ start = ktime_get();
/*
* NOTE: Although we can get the priority field, using it
* here is not a good idea, since it limits the pages we can scan.
@@ -2301,10 +2301,10 @@
* the priority and make it zero.
*/
shrink_zone(0, zone, &sc);
- end = sched_clock();
+ end = ktime_get();
if (rec)
- rec->elapsed += end - start;
+ rec->elapsed += ktime_to_ns(ktime_sub(end, start));
*scanned = sc.nr_scanned;
trace_mm_vmscan_memcg_softlimit_reclaim_end(sc.nr_reclaimed);
@@ -2319,7 +2319,7 @@
{
struct zonelist *zonelist;
unsigned long nr_reclaimed;
- unsigned long start, end;
+ ktime_t start, end;
int nid;
struct scan_control sc = {
.may_writepage = !laptop_mode,
@@ -2337,7 +2337,7 @@
.gfp_mask = sc.gfp_mask,
};
- start = sched_clock();
+ start = ktime_get();
/*
* Unlike direct reclaim via alloc_pages(), memcg's reclaim doesn't
* take care of from where we get pages. So the node where we start the
@@ -2352,9 +2352,9 @@
sc.gfp_mask);
nr_reclaimed = do_try_to_free_pages(zonelist, &sc, &shrink);
- end = sched_clock();
+ end = ktime_get();
if (rec)
- rec->elapsed += end - start;
+ rec->elapsed += ktime_to_ns(ktime_sub(end, start));
trace_mm_vmscan_memcg_reclaim_end(nr_reclaimed);
@@ -2529,6 +2529,9 @@
high_wmark_pages(zone), 0, 0)) {
end_zone = i;
break;
+ } else {
+ /* If balanced, clear the congested flag */
+ zone_clear_flag(zone, ZONE_CONGESTED);
}
}
if (i < 0)
diff --git a/net/8021q/vlan_core.c b/net/8021q/vlan_core.c
index 5f27f8e..f1f2f7b 100644
--- a/net/8021q/vlan_core.c
+++ b/net/8021q/vlan_core.c
@@ -167,6 +167,8 @@
if (unlikely(!skb))
goto err_free;
+ skb_reset_network_header(skb);
+ skb_reset_transport_header(skb);
return skb;
err_free:
diff --git a/net/9p/trans_virtio.c b/net/9p/trans_virtio.c
index 175b513..e317583 100644
--- a/net/9p/trans_virtio.c
+++ b/net/9p/trans_virtio.c
@@ -263,7 +263,6 @@
{
int in, out, inp, outp;
struct virtio_chan *chan = client->trans;
- char *rdata = (char *)req->rc+sizeof(struct p9_fcall);
unsigned long flags;
size_t pdata_off = 0;
struct trans_rpage_info *rpinfo = NULL;
@@ -346,7 +345,8 @@
* Arrange in such a way that server places header in the
* alloced memory and payload onto the user buffer.
*/
- inp = pack_sg_list(chan->sg, out, VIRTQUEUE_NUM, rdata, 11);
+ inp = pack_sg_list(chan->sg, out,
+ VIRTQUEUE_NUM, req->rc->sdata, 11);
/*
* Running executables in the filesystem may result in
* a read request with kernel buffer as opposed to user buffer.
@@ -366,8 +366,8 @@
}
in += inp;
} else {
- in = pack_sg_list(chan->sg, out, VIRTQUEUE_NUM, rdata,
- req->rc->capacity);
+ in = pack_sg_list(chan->sg, out, VIRTQUEUE_NUM,
+ req->rc->sdata, req->rc->capacity);
}
err = virtqueue_add_buf(chan->vq, chan->sg, out, in, req->tc);
@@ -592,7 +592,14 @@
.close = p9_virtio_close,
.request = p9_virtio_request,
.cancel = p9_virtio_cancel,
- .maxsize = PAGE_SIZE*VIRTQUEUE_NUM,
+
+ /*
+ * We leave one entry for input and one entry for response
+ * headers. We also skip one more entry to accomodate, address
+ * that are not at page boundary, that can result in an extra
+ * page in zero copy.
+ */
+ .maxsize = PAGE_SIZE * (VIRTQUEUE_NUM - 3),
.pref = P9_TRANS_PREF_PAYLOAD_SEP,
.def = 0,
.owner = THIS_MODULE,
diff --git a/net/atm/br2684.c b/net/atm/br2684.c
index 52cfd0c..d07223c 100644
--- a/net/atm/br2684.c
+++ b/net/atm/br2684.c
@@ -558,12 +558,13 @@
spin_unlock_irqrestore(&rq->lock, flags);
skb_queue_walk_safe(&queue, skb, tmp) {
- struct net_device *dev = skb->dev;
+ struct net_device *dev;
+
+ br2684_push(atmvcc, skb);
+ dev = skb->dev;
dev->stats.rx_bytes -= skb->len;
dev->stats.rx_packets--;
-
- br2684_push(atmvcc, skb);
}
/* initialize netdev carrier state */
diff --git a/net/bluetooth/af_bluetooth.c b/net/bluetooth/af_bluetooth.c
index 8add9b4..117e0d1 100644
--- a/net/bluetooth/af_bluetooth.c
+++ b/net/bluetooth/af_bluetooth.c
@@ -494,9 +494,8 @@
BT_DBG("sk %p", sk);
add_wait_queue(sk_sleep(sk), &wait);
+ set_current_state(TASK_INTERRUPTIBLE);
while (sk->sk_state != state) {
- set_current_state(TASK_INTERRUPTIBLE);
-
if (!timeo) {
err = -EINPROGRESS;
break;
@@ -510,12 +509,13 @@
release_sock(sk);
timeo = schedule_timeout(timeo);
lock_sock(sk);
+ set_current_state(TASK_INTERRUPTIBLE);
err = sock_error(sk);
if (err)
break;
}
- set_current_state(TASK_RUNNING);
+ __set_current_state(TASK_RUNNING);
remove_wait_queue(sk_sleep(sk), &wait);
return err;
}
diff --git a/net/bluetooth/bnep/bnep.h b/net/bluetooth/bnep/bnep.h
index 8e6c061..e7ee531 100644
--- a/net/bluetooth/bnep/bnep.h
+++ b/net/bluetooth/bnep/bnep.h
@@ -155,6 +155,7 @@
unsigned int role;
unsigned long state;
unsigned long flags;
+ atomic_t terminate;
struct task_struct *task;
struct ethhdr eh;
diff --git a/net/bluetooth/bnep/core.c b/net/bluetooth/bnep/core.c
index ca39fcf..d9edfe8 100644
--- a/net/bluetooth/bnep/core.c
+++ b/net/bluetooth/bnep/core.c
@@ -484,9 +484,11 @@
init_waitqueue_entry(&wait, current);
add_wait_queue(sk_sleep(sk), &wait);
- while (!kthread_should_stop()) {
+ while (1) {
set_current_state(TASK_INTERRUPTIBLE);
+ if (atomic_read(&s->terminate))
+ break;
/* RX */
while ((skb = skb_dequeue(&sk->sk_receive_queue))) {
skb_orphan(skb);
@@ -504,7 +506,7 @@
schedule();
}
- set_current_state(TASK_RUNNING);
+ __set_current_state(TASK_RUNNING);
remove_wait_queue(sk_sleep(sk), &wait);
/* Cleanup session */
@@ -640,9 +642,10 @@
down_read(&bnep_session_sem);
s = __bnep_get_session(req->dst);
- if (s)
- kthread_stop(s->task);
- else
+ if (s) {
+ atomic_inc(&s->terminate);
+ wake_up_process(s->task);
+ } else
err = -ENOENT;
up_read(&bnep_session_sem);
diff --git a/net/bluetooth/cmtp/capi.c b/net/bluetooth/cmtp/capi.c
index 040f67b..50f0d13 100644
--- a/net/bluetooth/cmtp/capi.c
+++ b/net/bluetooth/cmtp/capi.c
@@ -386,7 +386,8 @@
capi_ctr_down(ctrl);
- kthread_stop(session->task);
+ atomic_inc(&session->terminate);
+ wake_up_process(session->task);
}
static void cmtp_register_appl(struct capi_ctr *ctrl, __u16 appl, capi_register_params *rp)
diff --git a/net/bluetooth/cmtp/cmtp.h b/net/bluetooth/cmtp/cmtp.h
index db43b54..c32638d 100644
--- a/net/bluetooth/cmtp/cmtp.h
+++ b/net/bluetooth/cmtp/cmtp.h
@@ -81,6 +81,7 @@
char name[BTNAMSIZ];
+ atomic_t terminate;
struct task_struct *task;
wait_queue_head_t wait;
diff --git a/net/bluetooth/cmtp/core.c b/net/bluetooth/cmtp/core.c
index c5b11af..521baa4 100644
--- a/net/bluetooth/cmtp/core.c
+++ b/net/bluetooth/cmtp/core.c
@@ -292,9 +292,11 @@
init_waitqueue_entry(&wait, current);
add_wait_queue(sk_sleep(sk), &wait);
- while (!kthread_should_stop()) {
+ while (1) {
set_current_state(TASK_INTERRUPTIBLE);
+ if (atomic_read(&session->terminate))
+ break;
if (sk->sk_state != BT_CONNECTED)
break;
@@ -307,7 +309,7 @@
schedule();
}
- set_current_state(TASK_RUNNING);
+ __set_current_state(TASK_RUNNING);
remove_wait_queue(sk_sleep(sk), &wait);
down_write(&cmtp_session_sem);
@@ -380,16 +382,17 @@
if (!(session->flags & (1 << CMTP_LOOPBACK))) {
err = cmtp_attach_device(session);
- if (err < 0)
- goto detach;
+ if (err < 0) {
+ atomic_inc(&session->terminate);
+ wake_up_process(session->task);
+ up_write(&cmtp_session_sem);
+ return err;
+ }
}
up_write(&cmtp_session_sem);
return 0;
-detach:
- cmtp_detach_device(session);
-
unlink:
__cmtp_unlink_session(session);
@@ -414,7 +417,8 @@
skb_queue_purge(&session->transmit);
/* Stop session thread */
- kthread_stop(session->task);
+ atomic_inc(&session->terminate);
+ wake_up_process(session->task);
} else
err = -ENOENT;
diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c
index ec0bc3f..56943ad 100644
--- a/net/bluetooth/hci_core.c
+++ b/net/bluetooth/hci_core.c
@@ -1209,7 +1209,6 @@
BT_ERR("%s command tx timeout", hdev->name);
atomic_set(&hdev->cmd_cnt, 1);
- clear_bit(HCI_RESET, &hdev->flags);
tasklet_schedule(&hdev->cmd_task);
}
@@ -1327,7 +1326,7 @@
entry = kzalloc(sizeof(struct bdaddr_list), GFP_KERNEL);
if (!entry) {
- return -ENOMEM;
+ err = -ENOMEM;
goto err;
}
@@ -2408,7 +2407,10 @@
if (hdev->sent_cmd) {
atomic_dec(&hdev->cmd_cnt);
hci_send_frame(skb);
- mod_timer(&hdev->cmd_timer,
+ if (test_bit(HCI_RESET, &hdev->flags))
+ del_timer(&hdev->cmd_timer);
+ else
+ mod_timer(&hdev->cmd_timer,
jiffies + msecs_to_jiffies(HCI_CMD_TIMEOUT));
} else {
skb_queue_head(&hdev->cmd_q, skb);
diff --git a/net/bluetooth/hidp/core.c b/net/bluetooth/hidp/core.c
index 43b4c2d..fb68f34 100644
--- a/net/bluetooth/hidp/core.c
+++ b/net/bluetooth/hidp/core.c
@@ -764,6 +764,7 @@
up_write(&hidp_session_sem);
+ kfree(session->rd_data);
kfree(session);
return 0;
}
@@ -841,7 +842,8 @@
err = input_register_device(input);
if (err < 0) {
- hci_conn_put_device(session->conn);
+ input_free_device(input);
+ session->input = NULL;
return err;
}
@@ -1044,8 +1046,12 @@
}
err = hid_add_device(session->hid);
- if (err < 0)
- goto err_add_device;
+ if (err < 0) {
+ atomic_inc(&session->terminate);
+ wake_up_process(session->task);
+ up_write(&hidp_session_sem);
+ return err;
+ }
if (session->input) {
hidp_send_ctrl_message(session,
@@ -1059,12 +1065,6 @@
up_write(&hidp_session_sem);
return 0;
-err_add_device:
- hid_destroy_device(session->hid);
- session->hid = NULL;
- atomic_inc(&session->terminate);
- wake_up_process(session->task);
-
unlink:
hidp_del_timer(session);
@@ -1090,7 +1090,6 @@
failed:
up_write(&hidp_session_sem);
- input_free_device(session->input);
kfree(session);
return err;
}
diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c
index 3204ba8..b3bdb48 100644
--- a/net/bluetooth/l2cap_core.c
+++ b/net/bluetooth/l2cap_core.c
@@ -1159,9 +1159,8 @@
int timeo = HZ/5;
add_wait_queue(sk_sleep(sk), &wait);
- while ((chan->unacked_frames > 0 && chan->conn)) {
- set_current_state(TASK_INTERRUPTIBLE);
-
+ set_current_state(TASK_INTERRUPTIBLE);
+ while (chan->unacked_frames > 0 && chan->conn) {
if (!timeo)
timeo = HZ/5;
@@ -1173,6 +1172,7 @@
release_sock(sk);
timeo = schedule_timeout(timeo);
lock_sock(sk);
+ set_current_state(TASK_INTERRUPTIBLE);
err = sock_error(sk);
if (err)
diff --git a/net/bluetooth/l2cap_sock.c b/net/bluetooth/l2cap_sock.c
index 5c36b3e..61f1f62 100644
--- a/net/bluetooth/l2cap_sock.c
+++ b/net/bluetooth/l2cap_sock.c
@@ -235,39 +235,39 @@
lock_sock_nested(sk, SINGLE_DEPTH_NESTING);
- if (sk->sk_state != BT_LISTEN) {
- err = -EBADFD;
- goto done;
- }
-
timeo = sock_rcvtimeo(sk, flags & O_NONBLOCK);
BT_DBG("sk %p timeo %ld", sk, timeo);
/* Wait for an incoming connection. (wake-one). */
add_wait_queue_exclusive(sk_sleep(sk), &wait);
- while (!(nsk = bt_accept_dequeue(sk, newsock))) {
+ while (1) {
set_current_state(TASK_INTERRUPTIBLE);
- if (!timeo) {
- err = -EAGAIN;
- break;
- }
-
- release_sock(sk);
- timeo = schedule_timeout(timeo);
- lock_sock_nested(sk, SINGLE_DEPTH_NESTING);
if (sk->sk_state != BT_LISTEN) {
err = -EBADFD;
break;
}
+ nsk = bt_accept_dequeue(sk, newsock);
+ if (nsk)
+ break;
+
+ if (!timeo) {
+ err = -EAGAIN;
+ break;
+ }
+
if (signal_pending(current)) {
err = sock_intr_errno(timeo);
break;
}
+
+ release_sock(sk);
+ timeo = schedule_timeout(timeo);
+ lock_sock_nested(sk, SINGLE_DEPTH_NESTING);
}
- set_current_state(TASK_RUNNING);
+ __set_current_state(TASK_RUNNING);
remove_wait_queue(sk_sleep(sk), &wait);
if (err)
@@ -993,7 +993,7 @@
INIT_LIST_HEAD(&bt_sk(sk)->accept_q);
sk->sk_destruct = l2cap_sock_destruct;
- sk->sk_sndtimeo = msecs_to_jiffies(L2CAP_CONN_TIMEOUT);
+ sk->sk_sndtimeo = L2CAP_CONN_TIMEOUT;
sock_reset_flag(sk, SOCK_ZAPPED);
diff --git a/net/bluetooth/rfcomm/core.c b/net/bluetooth/rfcomm/core.c
index 5759bb7..5ba3f6d 100644
--- a/net/bluetooth/rfcomm/core.c
+++ b/net/bluetooth/rfcomm/core.c
@@ -62,7 +62,6 @@
#define rfcomm_lock() mutex_lock(&rfcomm_mutex)
#define rfcomm_unlock() mutex_unlock(&rfcomm_mutex)
-static unsigned long rfcomm_event;
static LIST_HEAD(session_list);
@@ -120,7 +119,6 @@
{
if (!rfcomm_thread)
return;
- set_bit(RFCOMM_SCHED_WAKEUP, &rfcomm_event);
wake_up_process(rfcomm_thread);
}
@@ -2038,19 +2036,18 @@
rfcomm_add_listener(BDADDR_ANY);
- while (!kthread_should_stop()) {
+ while (1) {
set_current_state(TASK_INTERRUPTIBLE);
- if (!test_bit(RFCOMM_SCHED_WAKEUP, &rfcomm_event)) {
- /* No pending events. Let's sleep.
- * Incoming connections and data will wake us up. */
- schedule();
- }
- set_current_state(TASK_RUNNING);
+
+ if (kthread_should_stop())
+ break;
/* Process stuff */
- clear_bit(RFCOMM_SCHED_WAKEUP, &rfcomm_event);
rfcomm_process_sessions();
+
+ schedule();
}
+ __set_current_state(TASK_RUNNING);
rfcomm_kill_listener();
diff --git a/net/bluetooth/rfcomm/sock.c b/net/bluetooth/rfcomm/sock.c
index 8f01e6b..482722b 100644
--- a/net/bluetooth/rfcomm/sock.c
+++ b/net/bluetooth/rfcomm/sock.c
@@ -485,11 +485,6 @@
lock_sock(sk);
- if (sk->sk_state != BT_LISTEN) {
- err = -EBADFD;
- goto done;
- }
-
if (sk->sk_type != SOCK_STREAM) {
err = -EINVAL;
goto done;
@@ -501,28 +496,33 @@
/* Wait for an incoming connection. (wake-one). */
add_wait_queue_exclusive(sk_sleep(sk), &wait);
- while (!(nsk = bt_accept_dequeue(sk, newsock))) {
+ while (1) {
set_current_state(TASK_INTERRUPTIBLE);
- if (!timeo) {
- err = -EAGAIN;
- break;
- }
-
- release_sock(sk);
- timeo = schedule_timeout(timeo);
- lock_sock(sk);
if (sk->sk_state != BT_LISTEN) {
err = -EBADFD;
break;
}
+ nsk = bt_accept_dequeue(sk, newsock);
+ if (nsk)
+ break;
+
+ if (!timeo) {
+ err = -EAGAIN;
+ break;
+ }
+
if (signal_pending(current)) {
err = sock_intr_errno(timeo);
break;
}
+
+ release_sock(sk);
+ timeo = schedule_timeout(timeo);
+ lock_sock(sk);
}
- set_current_state(TASK_RUNNING);
+ __set_current_state(TASK_RUNNING);
remove_wait_queue(sk_sleep(sk), &wait);
if (err)
diff --git a/net/bluetooth/sco.c b/net/bluetooth/sco.c
index 4c3621b..8270f05 100644
--- a/net/bluetooth/sco.c
+++ b/net/bluetooth/sco.c
@@ -564,39 +564,39 @@
lock_sock(sk);
- if (sk->sk_state != BT_LISTEN) {
- err = -EBADFD;
- goto done;
- }
-
timeo = sock_rcvtimeo(sk, flags & O_NONBLOCK);
BT_DBG("sk %p timeo %ld", sk, timeo);
/* Wait for an incoming connection. (wake-one). */
add_wait_queue_exclusive(sk_sleep(sk), &wait);
- while (!(ch = bt_accept_dequeue(sk, newsock))) {
+ while (1) {
set_current_state(TASK_INTERRUPTIBLE);
- if (!timeo) {
- err = -EAGAIN;
- break;
- }
-
- release_sock(sk);
- timeo = schedule_timeout(timeo);
- lock_sock(sk);
if (sk->sk_state != BT_LISTEN) {
err = -EBADFD;
break;
}
+ ch = bt_accept_dequeue(sk, newsock);
+ if (ch)
+ break;
+
+ if (!timeo) {
+ err = -EAGAIN;
+ break;
+ }
+
if (signal_pending(current)) {
err = sock_intr_errno(timeo);
break;
}
+
+ release_sock(sk);
+ timeo = schedule_timeout(timeo);
+ lock_sock(sk);
}
- set_current_state(TASK_RUNNING);
+ __set_current_state(TASK_RUNNING);
remove_wait_queue(sk_sleep(sk), &wait);
if (err)
diff --git a/net/bridge/br_if.c b/net/bridge/br_if.c
index 2cdf007..e738154 100644
--- a/net/bridge/br_if.c
+++ b/net/bridge/br_if.c
@@ -231,6 +231,7 @@
int br_add_bridge(struct net *net, const char *name)
{
struct net_device *dev;
+ int res;
dev = alloc_netdev(sizeof(struct net_bridge), name,
br_dev_setup);
@@ -240,7 +241,10 @@
dev_net_set(dev, net);
- return register_netdev(dev);
+ res = register_netdev(dev);
+ if (res)
+ free_netdev(dev);
+ return res;
}
int br_del_bridge(struct net *net, const char *name)
diff --git a/net/bridge/br_multicast.c b/net/bridge/br_multicast.c
index 2d85ca7..995cbe0 100644
--- a/net/bridge/br_multicast.c
+++ b/net/bridge/br_multicast.c
@@ -1456,7 +1456,7 @@
{
struct sk_buff *skb2;
const struct ipv6hdr *ip6h;
- struct icmp6hdr *icmp6h;
+ u8 icmp6_type;
u8 nexthdr;
unsigned len;
int offset;
@@ -1502,9 +1502,9 @@
__skb_pull(skb2, offset);
skb_reset_transport_header(skb2);
- icmp6h = icmp6_hdr(skb2);
+ icmp6_type = icmp6_hdr(skb2)->icmp6_type;
- switch (icmp6h->icmp6_type) {
+ switch (icmp6_type) {
case ICMPV6_MGM_QUERY:
case ICMPV6_MGM_REPORT:
case ICMPV6_MGM_REDUCTION:
@@ -1520,16 +1520,23 @@
err = pskb_trim_rcsum(skb2, len);
if (err)
goto out;
+ err = -EINVAL;
}
+ ip6h = ipv6_hdr(skb2);
+
switch (skb2->ip_summed) {
case CHECKSUM_COMPLETE:
- if (!csum_fold(skb2->csum))
+ if (!csum_ipv6_magic(&ip6h->saddr, &ip6h->daddr, skb2->len,
+ IPPROTO_ICMPV6, skb2->csum))
break;
/*FALLTHROUGH*/
case CHECKSUM_NONE:
- skb2->csum = 0;
- if (skb_checksum_complete(skb2))
+ skb2->csum = ~csum_unfold(csum_ipv6_magic(&ip6h->saddr,
+ &ip6h->daddr,
+ skb2->len,
+ IPPROTO_ICMPV6, 0));
+ if (__skb_checksum_complete(skb2))
goto out;
}
@@ -1537,7 +1544,7 @@
BR_INPUT_SKB_CB(skb)->igmp = 1;
- switch (icmp6h->icmp6_type) {
+ switch (icmp6_type) {
case ICMPV6_MGM_REPORT:
{
struct mld_msg *mld;
diff --git a/net/ceph/msgpool.c b/net/ceph/msgpool.c
index d5f2d97..1f4cb30 100644
--- a/net/ceph/msgpool.c
+++ b/net/ceph/msgpool.c
@@ -7,27 +7,37 @@
#include <linux/ceph/msgpool.h>
-static void *alloc_fn(gfp_t gfp_mask, void *arg)
+static void *msgpool_alloc(gfp_t gfp_mask, void *arg)
{
struct ceph_msgpool *pool = arg;
- void *p;
+ struct ceph_msg *msg;
- p = ceph_msg_new(0, pool->front_len, gfp_mask);
- if (!p)
- pr_err("msgpool %s alloc failed\n", pool->name);
- return p;
+ msg = ceph_msg_new(0, pool->front_len, gfp_mask);
+ if (!msg) {
+ dout("msgpool_alloc %s failed\n", pool->name);
+ } else {
+ dout("msgpool_alloc %s %p\n", pool->name, msg);
+ msg->pool = pool;
+ }
+ return msg;
}
-static void free_fn(void *element, void *arg)
+static void msgpool_free(void *element, void *arg)
{
- ceph_msg_put(element);
+ struct ceph_msgpool *pool = arg;
+ struct ceph_msg *msg = element;
+
+ dout("msgpool_release %s %p\n", pool->name, msg);
+ msg->pool = NULL;
+ ceph_msg_put(msg);
}
int ceph_msgpool_init(struct ceph_msgpool *pool,
int front_len, int size, bool blocking, const char *name)
{
+ dout("msgpool %s init\n", name);
pool->front_len = front_len;
- pool->pool = mempool_create(size, alloc_fn, free_fn, pool);
+ pool->pool = mempool_create(size, msgpool_alloc, msgpool_free, pool);
if (!pool->pool)
return -ENOMEM;
pool->name = name;
@@ -36,14 +46,17 @@
void ceph_msgpool_destroy(struct ceph_msgpool *pool)
{
+ dout("msgpool %s destroy\n", pool->name);
mempool_destroy(pool->pool);
}
struct ceph_msg *ceph_msgpool_get(struct ceph_msgpool *pool,
int front_len)
{
+ struct ceph_msg *msg;
+
if (front_len > pool->front_len) {
- pr_err("msgpool_get pool %s need front %d, pool size is %d\n",
+ dout("msgpool_get %s need front %d, pool size is %d\n",
pool->name, front_len, pool->front_len);
WARN_ON(1);
@@ -51,14 +64,19 @@
return ceph_msg_new(0, front_len, GFP_NOFS);
}
- return mempool_alloc(pool->pool, GFP_NOFS);
+ msg = mempool_alloc(pool->pool, GFP_NOFS);
+ dout("msgpool_get %s %p\n", pool->name, msg);
+ return msg;
}
void ceph_msgpool_put(struct ceph_msgpool *pool, struct ceph_msg *msg)
{
+ dout("msgpool_put %s %p\n", pool->name, msg);
+
/* reset msg front_len; user may have changed it */
msg->front.iov_len = pool->front_len;
msg->hdr.front_len = cpu_to_le32(pool->front_len);
kref_init(&msg->kref); /* retake single ref */
+ mempool_free(msg, pool->pool);
}
diff --git a/net/ceph/osd_client.c b/net/ceph/osd_client.c
index ce310ee..16836a7 100644
--- a/net/ceph/osd_client.c
+++ b/net/ceph/osd_client.c
@@ -685,6 +685,18 @@
put_osd(osd);
}
+static void remove_all_osds(struct ceph_osd_client *osdc)
+{
+ dout("__remove_old_osds %p\n", osdc);
+ mutex_lock(&osdc->request_mutex);
+ while (!RB_EMPTY_ROOT(&osdc->osds)) {
+ struct ceph_osd *osd = rb_entry(rb_first(&osdc->osds),
+ struct ceph_osd, o_node);
+ __remove_osd(osdc, osd);
+ }
+ mutex_unlock(&osdc->request_mutex);
+}
+
static void __move_osd_to_lru(struct ceph_osd_client *osdc,
struct ceph_osd *osd)
{
@@ -701,14 +713,14 @@
list_del_init(&osd->o_osd_lru);
}
-static void remove_old_osds(struct ceph_osd_client *osdc, int remove_all)
+static void remove_old_osds(struct ceph_osd_client *osdc)
{
struct ceph_osd *osd, *nosd;
dout("__remove_old_osds %p\n", osdc);
mutex_lock(&osdc->request_mutex);
list_for_each_entry_safe(osd, nosd, &osdc->osd_lru, o_osd_lru) {
- if (!remove_all && time_before(jiffies, osd->lru_ttl))
+ if (time_before(jiffies, osd->lru_ttl))
break;
__remove_osd(osdc, osd);
}
@@ -751,6 +763,7 @@
struct rb_node *parent = NULL;
struct ceph_osd *osd = NULL;
+ dout("__insert_osd %p osd%d\n", new, new->o_osd);
while (*p) {
parent = *p;
osd = rb_entry(parent, struct ceph_osd, o_node);
@@ -1144,7 +1157,7 @@
dout("osds timeout\n");
down_read(&osdc->map_sem);
- remove_old_osds(osdc, 0);
+ remove_old_osds(osdc);
up_read(&osdc->map_sem);
schedule_delayed_work(&osdc->osds_timeout_work,
@@ -1862,8 +1875,7 @@
ceph_osdmap_destroy(osdc->osdmap);
osdc->osdmap = NULL;
}
- remove_old_osds(osdc, 1);
- WARN_ON(!RB_EMPTY_ROOT(&osdc->osds));
+ remove_all_osds(osdc);
mempool_destroy(osdc->req_mempool);
ceph_msgpool_destroy(&osdc->msgpool_op);
ceph_msgpool_destroy(&osdc->msgpool_op_reply);
diff --git a/net/core/neighbour.c b/net/core/neighbour.c
index 8fab9b0..1334d7e 100644
--- a/net/core/neighbour.c
+++ b/net/core/neighbour.c
@@ -1319,11 +1319,15 @@
if (tdif <= 0) {
struct net_device *dev = skb->dev;
+
__skb_unlink(skb, &tbl->proxy_queue);
- if (tbl->proxy_redo && netif_running(dev))
+ if (tbl->proxy_redo && netif_running(dev)) {
+ rcu_read_lock();
tbl->proxy_redo(skb);
- else
+ rcu_read_unlock();
+ } else {
kfree_skb(skb);
+ }
dev_put(dev);
} else if (!sched_next || tdif < sched_next)
diff --git a/net/core/netpoll.c b/net/core/netpoll.c
index adf84dd..5262251 100644
--- a/net/core/netpoll.c
+++ b/net/core/netpoll.c
@@ -558,13 +558,14 @@
if (skb_shared(skb))
goto out;
- iph = (struct iphdr *)skb->data;
if (!pskb_may_pull(skb, sizeof(struct iphdr)))
goto out;
+ iph = (struct iphdr *)skb->data;
if (iph->ihl < 5 || iph->version != 4)
goto out;
if (!pskb_may_pull(skb, iph->ihl*4))
goto out;
+ iph = (struct iphdr *)skb->data;
if (ip_fast_csum((u8 *)iph, iph->ihl) != 0)
goto out;
@@ -579,6 +580,7 @@
if (pskb_trim_rcsum(skb, len))
goto out;
+ iph = (struct iphdr *)skb->data;
if (iph->protocol != IPPROTO_UDP)
goto out;
diff --git a/net/ipv4/igmp.c b/net/ipv4/igmp.c
index 283c0a2..d577199 100644
--- a/net/ipv4/igmp.c
+++ b/net/ipv4/igmp.c
@@ -767,7 +767,7 @@
break;
for (i=0; i<nsrcs; i++) {
/* skip inactive filters */
- if (pmc->sfcount[MCAST_INCLUDE] ||
+ if (psf->sf_count[MCAST_INCLUDE] ||
pmc->sfcount[MCAST_EXCLUDE] !=
psf->sf_count[MCAST_EXCLUDE])
continue;
diff --git a/net/ipv6/ipv6_sockglue.c b/net/ipv6/ipv6_sockglue.c
index 9cb191e..147ede38 100644
--- a/net/ipv6/ipv6_sockglue.c
+++ b/net/ipv6/ipv6_sockglue.c
@@ -913,7 +913,7 @@
}
static int do_ipv6_getsockopt(struct sock *sk, int level, int optname,
- char __user *optval, int __user *optlen)
+ char __user *optval, int __user *optlen, unsigned flags)
{
struct ipv6_pinfo *np = inet6_sk(sk);
int len;
@@ -962,7 +962,7 @@
msg.msg_control = optval;
msg.msg_controllen = len;
- msg.msg_flags = 0;
+ msg.msg_flags = flags;
lock_sock(sk);
skb = np->pktoptions;
@@ -1222,7 +1222,7 @@
if(level != SOL_IPV6)
return -ENOPROTOOPT;
- err = do_ipv6_getsockopt(sk, level, optname, optval, optlen);
+ err = do_ipv6_getsockopt(sk, level, optname, optval, optlen, 0);
#ifdef CONFIG_NETFILTER
/* we need to exclude all possible ENOPROTOOPTs except default case */
if (err == -ENOPROTOOPT && optname != IPV6_2292PKTOPTIONS) {
@@ -1264,7 +1264,8 @@
return compat_mc_getsockopt(sk, level, optname, optval, optlen,
ipv6_getsockopt);
- err = do_ipv6_getsockopt(sk, level, optname, optval, optlen);
+ err = do_ipv6_getsockopt(sk, level, optname, optval, optlen,
+ MSG_CMSG_COMPAT);
#ifdef CONFIG_NETFILTER
/* we need to exclude all possible ENOPROTOOPTs except default case */
if (err == -ENOPROTOOPT && optname != IPV6_2292PKTOPTIONS) {
diff --git a/net/ipv6/mcast.c b/net/ipv6/mcast.c
index 3e6ebcd..ee7839f 100644
--- a/net/ipv6/mcast.c
+++ b/net/ipv6/mcast.c
@@ -1059,7 +1059,7 @@
break;
for (i=0; i<nsrcs; i++) {
/* skip inactive filters */
- if (pmc->mca_sfcount[MCAST_INCLUDE] ||
+ if (psf->sf_count[MCAST_INCLUDE] ||
pmc->mca_sfcount[MCAST_EXCLUDE] !=
psf->sf_count[MCAST_EXCLUDE])
continue;
diff --git a/net/ipv6/sit.c b/net/ipv6/sit.c
index 07bf108..00b15ac 100644
--- a/net/ipv6/sit.c
+++ b/net/ipv6/sit.c
@@ -672,6 +672,9 @@
if (skb->protocol != htons(ETH_P_IPV6))
goto tx_error;
+ if (tos == 1)
+ tos = ipv6_get_dsfield(iph6);
+
/* ISATAP (RFC4214) - must come before 6to4 */
if (dev->priv_flags & IFF_ISATAP) {
struct neighbour *neigh = NULL;
diff --git a/net/mac80211/main.c b/net/mac80211/main.c
index 866f269..acb4423 100644
--- a/net/mac80211/main.c
+++ b/net/mac80211/main.c
@@ -1012,7 +1012,6 @@
cancel_work_sync(&local->reconfig_filter);
ieee80211_clear_tx_pending(local);
- sta_info_stop(local);
rate_control_deinitialize(local);
if (skb_queue_len(&local->skb_queue) ||
@@ -1024,6 +1023,7 @@
destroy_workqueue(local->workqueue);
wiphy_unregister(local->hw.wiphy);
+ sta_info_stop(local);
ieee80211_wep_free(local);
ieee80211_led_exit(local);
kfree(local->int_scan_req);
diff --git a/net/sched/act_mirred.c b/net/sched/act_mirred.c
index 102fc21..e051398 100644
--- a/net/sched/act_mirred.c
+++ b/net/sched/act_mirred.c
@@ -196,8 +196,7 @@
skb2->skb_iif = skb->dev->ifindex;
skb2->dev = dev;
- dev_queue_xmit(skb2);
- err = 0;
+ err = dev_queue_xmit(skb2);
out:
if (err) {
diff --git a/net/socket.c b/net/socket.c
index 24a7740..ffe92ca 100644
--- a/net/socket.c
+++ b/net/socket.c
@@ -1965,8 +1965,9 @@
* used_address->name_len is initialized to UINT_MAX so that the first
* destination address never matches.
*/
- if (used_address && used_address->name_len == msg_sys->msg_namelen &&
- !memcmp(&used_address->name, msg->msg_name,
+ if (used_address && msg_sys->msg_name &&
+ used_address->name_len == msg_sys->msg_namelen &&
+ !memcmp(&used_address->name, msg_sys->msg_name,
used_address->name_len)) {
err = sock_sendmsg_nosec(sock, msg_sys, total_len);
goto out_freectl;
@@ -1978,8 +1979,9 @@
*/
if (used_address && err >= 0) {
used_address->name_len = msg_sys->msg_namelen;
- memcpy(&used_address->name, msg->msg_name,
- used_address->name_len);
+ if (msg_sys->msg_name)
+ memcpy(&used_address->name, msg_sys->msg_name,
+ used_address->name_len);
}
out_freectl:
diff --git a/net/wireless/core.c b/net/wireless/core.c
index 645437c..c148651 100644
--- a/net/wireless/core.c
+++ b/net/wireless/core.c
@@ -616,6 +616,9 @@
if (res)
goto out_rm_dev;
+ rtnl_lock();
+ rdev->wiphy.registered = true;
+ rtnl_unlock();
return 0;
out_rm_dev:
@@ -647,6 +650,10 @@
{
struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
+ rtnl_lock();
+ rdev->wiphy.registered = false;
+ rtnl_unlock();
+
rfkill_unregister(rdev->rfkill);
/* protect the device list */
diff --git a/net/wireless/sysfs.c b/net/wireless/sysfs.c
index c6e4ca6..ff57459 100644
--- a/net/wireless/sysfs.c
+++ b/net/wireless/sysfs.c
@@ -93,7 +93,8 @@
if (rdev->ops->suspend) {
rtnl_lock();
- ret = rdev->ops->suspend(&rdev->wiphy, rdev->wowlan);
+ if (rdev->wiphy.registered)
+ ret = rdev->ops->suspend(&rdev->wiphy, rdev->wowlan);
rtnl_unlock();
}
@@ -112,7 +113,8 @@
if (rdev->ops->resume) {
rtnl_lock();
- ret = rdev->ops->resume(&rdev->wiphy);
+ if (rdev->wiphy.registered)
+ ret = rdev->ops->resume(&rdev->wiphy);
rtnl_unlock();
}
diff --git a/scripts/checkpatch.pl b/scripts/checkpatch.pl
index 9d761c9..3dfc471 100755
--- a/scripts/checkpatch.pl
+++ b/scripts/checkpatch.pl
@@ -2574,7 +2574,8 @@
} else {
$cast = $cast2;
}
- WARN("$call() should probably be ${call}_t($cast, $arg1, $arg2)\n" . $herecurr);
+ WARN("MINMAX",
+ "$call() should probably be ${call}_t($cast, $arg1, $arg2)\n" . $herecurr);
}
}
diff --git a/scripts/get_maintainer.pl b/scripts/get_maintainer.pl
index eb2f1e6..4594f33 100755
--- a/scripts/get_maintainer.pl
+++ b/scripts/get_maintainer.pl
@@ -1389,7 +1389,7 @@
warn("$P: No supported VCS found. Add --nogit to options?\n");
warn("Using a git repository produces better results.\n");
warn("Try Linus Torvalds' latest git repository using:\n");
- warn("git clone git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux-2.6.git\n");
+ warn("git clone git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git\n");
$printed_novcs = 1;
}
return 0;
diff --git a/sound/pci/hda/patch_conexant.c b/sound/pci/hda/patch_conexant.c
index 502fc94..7696d05 100644
--- a/sound/pci/hda/patch_conexant.c
+++ b/sound/pci/hda/patch_conexant.c
@@ -3348,6 +3348,8 @@
#define MAX_AUTO_DACS 5
+#define DAC_SLAVE_FLAG 0x8000 /* filled dac is a slave */
+
/* fill analog DAC list from the widget tree */
static int fill_cx_auto_dacs(struct hda_codec *codec, hda_nid_t *dacs)
{
@@ -3370,16 +3372,26 @@
/* fill pin_dac_pair list from the pin and dac list */
static int fill_dacs_for_pins(struct hda_codec *codec, hda_nid_t *pins,
int num_pins, hda_nid_t *dacs, int *rest,
- struct pin_dac_pair *filled, int type)
+ struct pin_dac_pair *filled, int nums,
+ int type)
{
- int i, nums;
+ int i, start = nums;
- nums = 0;
- for (i = 0; i < num_pins; i++) {
+ for (i = 0; i < num_pins; i++, nums++) {
filled[nums].pin = pins[i];
filled[nums].type = type;
filled[nums].dac = get_unassigned_dac(codec, pins[i], dacs, rest);
- nums++;
+ if (filled[nums].dac)
+ continue;
+ if (filled[start].dac && get_connection_index(codec, pins[i], filled[start].dac) >= 0) {
+ filled[nums].dac = filled[start].dac | DAC_SLAVE_FLAG;
+ continue;
+ }
+ if (filled[0].dac && get_connection_index(codec, pins[i], filled[0].dac) >= 0) {
+ filled[nums].dac = filled[0].dac | DAC_SLAVE_FLAG;
+ continue;
+ }
+ snd_printdd("Failed to find a DAC for pin 0x%x", pins[i]);
}
return nums;
}
@@ -3395,19 +3407,19 @@
rest = fill_cx_auto_dacs(codec, dacs);
/* parse all analog output pins */
nums = fill_dacs_for_pins(codec, cfg->line_out_pins, cfg->line_outs,
- dacs, &rest, spec->dac_info,
- AUTO_PIN_LINE_OUT);
- nums += fill_dacs_for_pins(codec, cfg->hp_pins, cfg->hp_outs,
- dacs, &rest, spec->dac_info + nums,
- AUTO_PIN_HP_OUT);
- nums += fill_dacs_for_pins(codec, cfg->speaker_pins, cfg->speaker_outs,
- dacs, &rest, spec->dac_info + nums,
- AUTO_PIN_SPEAKER_OUT);
+ dacs, &rest, spec->dac_info, 0,
+ AUTO_PIN_LINE_OUT);
+ nums = fill_dacs_for_pins(codec, cfg->hp_pins, cfg->hp_outs,
+ dacs, &rest, spec->dac_info, nums,
+ AUTO_PIN_HP_OUT);
+ nums = fill_dacs_for_pins(codec, cfg->speaker_pins, cfg->speaker_outs,
+ dacs, &rest, spec->dac_info, nums,
+ AUTO_PIN_SPEAKER_OUT);
spec->dac_info_filled = nums;
/* fill multiout struct */
for (i = 0; i < nums; i++) {
hda_nid_t dac = spec->dac_info[i].dac;
- if (!dac)
+ if (!dac || (dac & DAC_SLAVE_FLAG))
continue;
switch (spec->dac_info[i].type) {
case AUTO_PIN_LINE_OUT:
@@ -3862,7 +3874,7 @@
}
if (imux->num_items >= 2 && cfg->num_inputs == imux->num_items)
cx_auto_check_auto_mic(codec);
- if (imux->num_items > 1 && !spec->auto_mic) {
+ if (imux->num_items > 1) {
for (i = 1; i < imux->num_items; i++) {
if (spec->imux_info[i].adc != spec->imux_info[0].adc) {
spec->adc_switching = 1;
@@ -4035,6 +4047,8 @@
nid = spec->dac_info[i].dac;
if (!nid)
nid = spec->multiout.dac_nids[0];
+ else if (nid & DAC_SLAVE_FLAG)
+ nid &= ~DAC_SLAVE_FLAG;
select_connection(codec, spec->dac_info[i].pin, nid);
}
if (spec->auto_mute) {
@@ -4167,9 +4181,11 @@
hda_nid_t pin, const char *name, int idx)
{
unsigned int caps;
- caps = query_amp_caps(codec, dac, HDA_OUTPUT);
- if (caps & AC_AMPCAP_NUM_STEPS)
- return cx_auto_add_pb_volume(codec, dac, name, idx);
+ if (dac && !(dac & DAC_SLAVE_FLAG)) {
+ caps = query_amp_caps(codec, dac, HDA_OUTPUT);
+ if (caps & AC_AMPCAP_NUM_STEPS)
+ return cx_auto_add_pb_volume(codec, dac, name, idx);
+ }
caps = query_amp_caps(codec, pin, HDA_OUTPUT);
if (caps & AC_AMPCAP_NUM_STEPS)
return cx_auto_add_pb_volume(codec, pin, name, idx);
@@ -4191,8 +4207,7 @@
for (i = 0; i < spec->dac_info_filled; i++) {
const char *label;
int idx, type;
- if (!spec->dac_info[i].dac)
- continue;
+ hda_nid_t dac = spec->dac_info[i].dac;
type = spec->dac_info[i].type;
if (type == AUTO_PIN_LINE_OUT)
type = spec->autocfg.line_out_type;
@@ -4211,7 +4226,7 @@
idx = num_spk++;
break;
}
- err = try_add_pb_volume(codec, spec->dac_info[i].dac,
+ err = try_add_pb_volume(codec, dac,
spec->dac_info[i].pin,
label, idx);
if (err < 0)
diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c
index fcb11af..7cabd73 100644
--- a/sound/pci/hda/patch_realtek.c
+++ b/sound/pci/hda/patch_realtek.c
@@ -565,11 +565,11 @@
{
struct alc_spec *spec = codec->spec;
- if (!spec->automute)
- return;
spec->jack_present =
detect_jacks(codec, ARRAY_SIZE(spec->autocfg.hp_pins),
spec->autocfg.hp_pins);
+ if (!spec->automute)
+ return;
update_speakers(codec);
}
@@ -578,11 +578,11 @@
{
struct alc_spec *spec = codec->spec;
- if (!spec->automute || !spec->detect_line)
- return;
spec->line_jack_present =
detect_jacks(codec, ARRAY_SIZE(spec->autocfg.line_out_pins),
spec->autocfg.line_out_pins);
+ if (!spec->automute || !spec->detect_line)
+ return;
update_speakers(codec);
}
@@ -3083,16 +3083,22 @@
static void alc_auto_init_extra_out(struct hda_codec *codec)
{
struct alc_spec *spec = codec->spec;
- hda_nid_t pin;
+ hda_nid_t pin, dac;
pin = spec->autocfg.hp_pins[0];
- if (pin)
- alc_auto_set_output_and_unmute(codec, pin, PIN_HP,
- spec->multiout.hp_nid);
+ if (pin) {
+ dac = spec->multiout.hp_nid;
+ if (!dac)
+ dac = spec->multiout.dac_nids[0];
+ alc_auto_set_output_and_unmute(codec, pin, PIN_HP, dac);
+ }
pin = spec->autocfg.speaker_pins[0];
- if (pin)
- alc_auto_set_output_and_unmute(codec, pin, PIN_OUT,
- spec->multiout.extra_out_nid[0]);
+ if (pin) {
+ dac = spec->multiout.extra_out_nid[0];
+ if (!dac)
+ dac = spec->multiout.dac_nids[0];
+ alc_auto_set_output_and_unmute(codec, pin, PIN_OUT, dac);
+ }
}
/*
diff --git a/sound/soc/blackfin/bf5xx-ad193x.c b/sound/soc/blackfin/bf5xx-ad193x.c
index d6651c0..a118a0f 100644
--- a/sound/soc/blackfin/bf5xx-ad193x.c
+++ b/sound/soc/blackfin/bf5xx-ad193x.c
@@ -56,7 +56,7 @@
switch (params_rate(params)) {
case 48000:
- clk = 12288000;
+ clk = 24576000;
break;
}
diff --git a/sound/soc/codecs/ad193x.c b/sound/soc/codecs/ad193x.c
index 2374ca5..eedb6f5 100644
--- a/sound/soc/codecs/ad193x.c
+++ b/sound/soc/codecs/ad193x.c
@@ -27,11 +27,6 @@
int sysclk;
};
-/* ad193x register cache & default register settings */
-static const u8 ad193x_reg[AD193X_NUM_REGS] = {
- 0, 0, 0, 0, 0, 0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0, 0, 0,
-};
-
/*
* AD193X volume/mute/de-emphasis etc. controls
*/
@@ -307,7 +302,8 @@
snd_soc_write(codec, AD193X_PLL_CLK_CTRL0, reg);
reg = snd_soc_read(codec, AD193X_DAC_CTRL2);
- reg = (reg & (~AD193X_DAC_WORD_LEN_MASK)) | word_len;
+ reg = (reg & (~AD193X_DAC_WORD_LEN_MASK))
+ | (word_len << AD193X_DAC_WORD_LEN_SHFT);
snd_soc_write(codec, AD193X_DAC_CTRL2, reg);
reg = snd_soc_read(codec, AD193X_ADC_CTRL1);
@@ -389,9 +385,6 @@
static struct snd_soc_codec_driver soc_codec_dev_ad193x = {
.probe = ad193x_probe,
- .reg_cache_default = ad193x_reg,
- .reg_cache_size = AD193X_NUM_REGS,
- .reg_word_size = sizeof(u16),
};
#if defined(CONFIG_SPI_MASTER)
diff --git a/sound/soc/codecs/ad193x.h b/sound/soc/codecs/ad193x.h
index 9747b54..cccc2e8 100644
--- a/sound/soc/codecs/ad193x.h
+++ b/sound/soc/codecs/ad193x.h
@@ -34,7 +34,8 @@
#define AD193X_DAC_LEFT_HIGH (1 << 3)
#define AD193X_DAC_BCLK_INV (1 << 7)
#define AD193X_DAC_CTRL2 0x804
-#define AD193X_DAC_WORD_LEN_MASK 0xC
+#define AD193X_DAC_WORD_LEN_SHFT 3
+#define AD193X_DAC_WORD_LEN_MASK 0x18
#define AD193X_DAC_MASTER_MUTE 1
#define AD193X_DAC_CHNL_MUTE 0x805
#define AD193X_DACL1_MUTE 0
@@ -63,7 +64,7 @@
#define AD193X_ADC_CTRL1 0x80f
#define AD193X_ADC_SERFMT_MASK 0x60
#define AD193X_ADC_SERFMT_STEREO (0 << 5)
-#define AD193X_ADC_SERFMT_TDM (1 << 2)
+#define AD193X_ADC_SERFMT_TDM (1 << 5)
#define AD193X_ADC_SERFMT_AUX (2 << 5)
#define AD193X_ADC_WORD_LEN_MASK 0x3
#define AD193X_ADC_CTRL2 0x810
diff --git a/sound/soc/codecs/sta32x.c b/sound/soc/codecs/sta32x.c
index 409d89d..fbd7eb9 100644
--- a/sound/soc/codecs/sta32x.c
+++ b/sound/soc/codecs/sta32x.c
@@ -857,6 +857,7 @@
ret = snd_soc_register_codec(&i2c->dev, &sta32x_codec, &sta32x_dai, 1);
if (ret != 0) {
dev_err(&i2c->dev, "Failed to register codec (%d)\n", ret);
+ kfree(sta32x);
return ret;
}
diff --git a/sound/soc/codecs/wm8962.c b/sound/soc/codecs/wm8962.c
index 60d740e..1725550 100644
--- a/sound/soc/codecs/wm8962.c
+++ b/sound/soc/codecs/wm8962.c
@@ -2221,6 +2221,8 @@
switch (event) {
case SND_SOC_DAPM_PRE_PMU:
if (fll) {
+ try_wait_for_completion(&wm8962->fll_lock);
+
snd_soc_update_bits(codec, WM8962_FLL_CONTROL_1,
WM8962_FLL_ENA, WM8962_FLL_ENA);
if (wm8962->irq) {
@@ -2927,10 +2929,6 @@
WM8962_BIAS_ENA | 0x180);
msleep(5);
-
- snd_soc_update_bits(codec, WM8962_CLOCKING2,
- WM8962_CLKREG_OVD,
- WM8962_CLKREG_OVD);
}
/* VMID 2*250k */
@@ -3288,6 +3286,8 @@
snd_soc_write(codec, WM8962_FLL_CONTROL_7, fll_div.lambda);
snd_soc_write(codec, WM8962_FLL_CONTROL_8, fll_div.n);
+ try_wait_for_completion(&wm8962->fll_lock);
+
snd_soc_update_bits(codec, WM8962_FLL_CONTROL_1,
WM8962_FLL_FRAC | WM8962_FLL_REFCLK_SRC_MASK |
WM8962_FLL_ENA, fll1);
@@ -3868,6 +3868,10 @@
*/
snd_soc_update_bits(codec, WM8962_CLOCKING2, WM8962_SYSCLK_ENA, 0);
+ /* Ensure we have soft control over all registers */
+ snd_soc_update_bits(codec, WM8962_CLOCKING2,
+ WM8962_CLKREG_OVD, WM8962_CLKREG_OVD);
+
regulator_bulk_disable(ARRAY_SIZE(wm8962->supplies), wm8962->supplies);
if (pdata) {
diff --git a/sound/soc/codecs/wm8996.c b/sound/soc/codecs/wm8996.c
index ab8e9d1..0cdb9d1 100644
--- a/sound/soc/codecs/wm8996.c
+++ b/sound/soc/codecs/wm8996.c
@@ -420,7 +420,7 @@
};
static const struct soc_enum sidetone_hpf =
- SOC_ENUM_SINGLE(WM8996_SIDETONE, 7, 6, sidetone_hpf_text);
+ SOC_ENUM_SINGLE(WM8996_SIDETONE, 7, 7, sidetone_hpf_text);
static const char *hpf_mode_text[] = {
"HiFi", "Custom", "Voice"
@@ -988,15 +988,10 @@
SND_SOC_DAPM_PGA("IN1L PGA", WM8996_POWER_MANAGEMENT_2, 5, 0, NULL, 0),
SND_SOC_DAPM_PGA("IN1R PGA", WM8996_POWER_MANAGEMENT_2, 4, 0, NULL, 0),
-SND_SOC_DAPM_MUX("IN1L Mux", SND_SOC_NOPM, 0, 0, &in1_mux),
-SND_SOC_DAPM_MUX("IN1R Mux", SND_SOC_NOPM, 0, 0, &in1_mux),
-SND_SOC_DAPM_MUX("IN2L Mux", SND_SOC_NOPM, 0, 0, &in2_mux),
-SND_SOC_DAPM_MUX("IN2R Mux", SND_SOC_NOPM, 0, 0, &in2_mux),
-
-SND_SOC_DAPM_PGA("IN1L", WM8996_POWER_MANAGEMENT_7, 2, 0, NULL, 0),
-SND_SOC_DAPM_PGA("IN1R", WM8996_POWER_MANAGEMENT_7, 3, 0, NULL, 0),
-SND_SOC_DAPM_PGA("IN2L", WM8996_POWER_MANAGEMENT_7, 6, 0, NULL, 0),
-SND_SOC_DAPM_PGA("IN2R", WM8996_POWER_MANAGEMENT_7, 7, 0, NULL, 0),
+SND_SOC_DAPM_MUX("IN1L Mux", WM8996_POWER_MANAGEMENT_7, 2, 0, &in1_mux),
+SND_SOC_DAPM_MUX("IN1R Mux", WM8996_POWER_MANAGEMENT_7, 3, 0, &in1_mux),
+SND_SOC_DAPM_MUX("IN2L Mux", WM8996_POWER_MANAGEMENT_7, 6, 0, &in2_mux),
+SND_SOC_DAPM_MUX("IN2R Mux", WM8996_POWER_MANAGEMENT_7, 7, 0, &in2_mux),
SND_SOC_DAPM_SUPPLY("DMIC2", WM8996_POWER_MANAGEMENT_7, 9, 0, NULL, 0),
SND_SOC_DAPM_SUPPLY("DMIC1", WM8996_POWER_MANAGEMENT_7, 8, 0, NULL, 0),
@@ -1213,6 +1208,16 @@
{ "AIF2RX0", NULL, "AIFCLK" },
{ "AIF2RX1", NULL, "AIFCLK" },
+ { "AIF1TX0", NULL, "AIFCLK" },
+ { "AIF1TX1", NULL, "AIFCLK" },
+ { "AIF1TX2", NULL, "AIFCLK" },
+ { "AIF1TX3", NULL, "AIFCLK" },
+ { "AIF1TX4", NULL, "AIFCLK" },
+ { "AIF1TX5", NULL, "AIFCLK" },
+
+ { "AIF2TX0", NULL, "AIFCLK" },
+ { "AIF2TX1", NULL, "AIFCLK" },
+
{ "DSP1RXL", NULL, "SYSDSPCLK" },
{ "DSP1RXR", NULL, "SYSDSPCLK" },
{ "DSP2RXL", NULL, "SYSDSPCLK" },
@@ -2106,6 +2111,9 @@
snd_soc_write(codec, WM8996_FLL_EFS_1, fll_div.lambda);
+ /* Clear any pending completions (eg, from failed startups) */
+ try_wait_for_completion(&wm8996->fll_lock);
+
snd_soc_update_bits(codec, WM8996_FLL_CONTROL_1,
WM8996_FLL_ENA, WM8996_FLL_ENA);
diff --git a/sound/soc/ep93xx/ep93xx-i2s.c b/sound/soc/ep93xx/ep93xx-i2s.c
index 56efa0c..099614e 100644
--- a/sound/soc/ep93xx/ep93xx-i2s.c
+++ b/sound/soc/ep93xx/ep93xx-i2s.c
@@ -385,14 +385,14 @@
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res) {
err = -ENODEV;
- goto fail;
+ goto fail_free_info;
}
info->mem = request_mem_region(res->start, resource_size(res),
pdev->name);
if (!info->mem) {
err = -EBUSY;
- goto fail;
+ goto fail_free_info;
}
info->regs = ioremap(info->mem->start, resource_size(info->mem));
@@ -435,6 +435,7 @@
iounmap(info->regs);
fail_release_mem:
release_mem_region(info->mem->start, resource_size(info->mem));
+fail_free_info:
kfree(info);
fail:
return err;
diff --git a/sound/soc/fsl/fsl_dma.c b/sound/soc/fsl/fsl_dma.c
index 732208c..cb50598 100644
--- a/sound/soc/fsl/fsl_dma.c
+++ b/sound/soc/fsl/fsl_dma.c
@@ -879,10 +879,12 @@
* assume that device_node pointers are a valid comparison.
*/
np = of_parse_phandle(ssi_np, "fsl,playback-dma", 0);
+ of_node_put(np);
if (np == dma_channel_np)
return ssi_np;
np = of_parse_phandle(ssi_np, "fsl,capture-dma", 0);
+ of_node_put(np);
if (np == dma_channel_np)
return ssi_np;
}
diff --git a/sound/soc/fsl/mpc8610_hpcd.c b/sound/soc/fsl/mpc8610_hpcd.c
index a192979..358f0ba 100644
--- a/sound/soc/fsl/mpc8610_hpcd.c
+++ b/sound/soc/fsl/mpc8610_hpcd.c
@@ -345,8 +345,10 @@
}
machine_data = kzalloc(sizeof(struct mpc8610_hpcd_data), GFP_KERNEL);
- if (!machine_data)
- return -ENOMEM;
+ if (!machine_data) {
+ ret = -ENOMEM;
+ goto error_alloc;
+ }
machine_data->dai[0].cpu_dai_name = dev_name(&ssi_pdev->dev);
machine_data->dai[0].ops = &mpc8610_hpcd_ops;
@@ -494,7 +496,7 @@
ret = platform_device_add(sound_device);
if (ret) {
dev_err(&pdev->dev, "platform device add failed\n");
- goto error;
+ goto error_sound;
}
dev_set_drvdata(&pdev->dev, sound_device);
@@ -502,14 +504,12 @@
return 0;
+error_sound:
+ platform_device_unregister(sound_device);
error:
- of_node_put(codec_np);
-
- if (sound_device)
- platform_device_unregister(sound_device);
-
kfree(machine_data);
-
+error_alloc:
+ of_node_put(codec_np);
return ret;
}
diff --git a/sound/soc/fsl/p1022_ds.c b/sound/soc/fsl/p1022_ds.c
index 8fa4d5f..fcb862e 100644
--- a/sound/soc/fsl/p1022_ds.c
+++ b/sound/soc/fsl/p1022_ds.c
@@ -297,8 +297,10 @@
* dai->platform name should already point to an allocated buffer.
*/
ret = of_address_to_resource(dma_channel_np, 0, &res);
- if (ret)
+ if (ret) {
+ of_node_put(dma_channel_np);
return ret;
+ }
snprintf((char *)dai->platform_name, DAI_NAME_SIZE, "%llx.%s",
(unsigned long long) res.start, dma_channel_np->name);
diff --git a/sound/soc/kirkwood/kirkwood-i2s.c b/sound/soc/kirkwood/kirkwood-i2s.c
index a33fc51..8f16cd3 100644
--- a/sound/soc/kirkwood/kirkwood-i2s.c
+++ b/sound/soc/kirkwood/kirkwood-i2s.c
@@ -424,7 +424,7 @@
if (!priv->mem) {
dev_err(&pdev->dev, "request_mem_region failed\n");
err = -EBUSY;
- goto error;
+ goto error_alloc;
}
priv->io = ioremap(priv->mem->start, SZ_16K);
diff --git a/sound/soc/omap/ams-delta.c b/sound/soc/omap/ams-delta.c
index 30fe0d0..0aa475f 100644
--- a/sound/soc/omap/ams-delta.c
+++ b/sound/soc/omap/ams-delta.c
@@ -514,7 +514,7 @@
}
/* Set codec bias level */
- ams_delta_set_bias_level(card, SND_SOC_BIAS_STANDBY);
+ ams_delta_set_bias_level(card, dapm, SND_SOC_BIAS_STANDBY);
/* Add hook switch - can be used to control the codec from userspace
* even if line discipline fails */
@@ -649,7 +649,9 @@
ams_delta_hook_switch_gpios);
/* Keep modem power on */
- ams_delta_set_bias_level(&ams_delta_audio_card, SND_SOC_BIAS_STANDBY);
+ ams_delta_set_bias_level(&ams_delta_audio_card,
+ &ams_delta_audio_card.rtd[0].codec->dapm,
+ SND_SOC_BIAS_STANDBY);
platform_device_unregister(cx20442_platform_device);
platform_device_unregister(ams_delta_audio_platform_device);
diff --git a/sound/soc/samsung/Kconfig b/sound/soc/samsung/Kconfig
index b99091f..65f980e 100644
--- a/sound/soc/samsung/Kconfig
+++ b/sound/soc/samsung/Kconfig
@@ -185,6 +185,7 @@
select SND_SAMSUNG_I2S
select SND_SOC_WM8996
select SND_SOC_WM9081
+ select SND_SOC_WM1250_EV1
config SND_SOC_SPEYSIDE_WM8962
tristate "Audio support for Wolfson Speyside with WM8962"
diff --git a/sound/soc/samsung/h1940_uda1380.c b/sound/soc/samsung/h1940_uda1380.c
index 241f55d..c6c6589 100644
--- a/sound/soc/samsung/h1940_uda1380.c
+++ b/sound/soc/samsung/h1940_uda1380.c
@@ -13,6 +13,7 @@
*
*/
+#include <linux/types.h>
#include <linux/gpio.h>
#include <sound/soc.h>
diff --git a/sound/soc/samsung/rx1950_uda1380.c b/sound/soc/samsung/rx1950_uda1380.c
index 1e574a5..bc8c167 100644
--- a/sound/soc/samsung/rx1950_uda1380.c
+++ b/sound/soc/samsung/rx1950_uda1380.c
@@ -17,6 +17,7 @@
*
*/
+#include <linux/types.h>
#include <linux/gpio.h>
#include <sound/soc.h>
diff --git a/sound/soc/samsung/speyside_wm8962.c b/sound/soc/samsung/speyside_wm8962.c
index 0b9eb5f..72535f2 100644
--- a/sound/soc/samsung/speyside_wm8962.c
+++ b/sound/soc/samsung/speyside_wm8962.c
@@ -23,6 +23,9 @@
struct snd_soc_dai *codec_dai = card->rtd[0].codec_dai;
int ret;
+ if (dapm->dev != codec_dai->dev)
+ return 0;
+
switch (level) {
case SND_SOC_BIAS_PREPARE:
if (dapm->bias_level == SND_SOC_BIAS_STANDBY) {
@@ -57,6 +60,9 @@
struct snd_soc_dai *codec_dai = card->rtd[0].codec_dai;
int ret;
+ if (dapm->dev != codec_dai->dev)
+ return 0;
+
switch (level) {
case SND_SOC_BIAS_STANDBY:
ret = snd_soc_dai_set_sysclk(codec_dai, WM8962_SYSCLK_MCLK,
diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c
index 83ad8ca..b085d8e 100644
--- a/sound/soc/soc-core.c
+++ b/sound/soc/soc-core.c
@@ -1913,7 +1913,7 @@
if (prefix) {
name_len = strlen(long_name) + strlen(prefix) + 2;
- name = kmalloc(name_len, GFP_ATOMIC);
+ name = kmalloc(name_len, GFP_KERNEL);
if (!name)
return NULL;
diff --git a/sound/soc/soc-io.c b/sound/soc/soc-io.c
index cca490c..a62f7dd 100644
--- a/sound/soc/soc-io.c
+++ b/sound/soc/soc-io.c
@@ -205,6 +205,25 @@
#define snd_soc_16_8_read_i2c NULL
#endif
+#if defined(CONFIG_SPI_MASTER)
+static unsigned int snd_soc_16_8_read_spi(struct snd_soc_codec *codec,
+ unsigned int r)
+{
+ struct spi_device *spi = codec->control_data;
+
+ const u16 reg = cpu_to_be16(r | 0x100);
+ u8 data;
+ int ret;
+
+ ret = spi_write_then_read(spi, ®, 2, &data, 1);
+ if (ret < 0)
+ return 0;
+ return data;
+}
+#else
+#define snd_soc_16_8_read_spi NULL
+#endif
+
static int snd_soc_16_8_write(struct snd_soc_codec *codec, unsigned int reg,
unsigned int value)
{
@@ -295,6 +314,7 @@
int (*write)(struct snd_soc_codec *codec, unsigned int, unsigned int);
unsigned int (*read)(struct snd_soc_codec *, unsigned int);
unsigned int (*i2c_read)(struct snd_soc_codec *, unsigned int);
+ unsigned int (*spi_read)(struct snd_soc_codec *, unsigned int);
} io_types[] = {
{
.addr_bits = 4, .data_bits = 12,
@@ -318,6 +338,7 @@
.addr_bits = 16, .data_bits = 8,
.write = snd_soc_16_8_write,
.i2c_read = snd_soc_16_8_read_i2c,
+ .spi_read = snd_soc_16_8_read_spi,
},
{
.addr_bits = 16, .data_bits = 16,
@@ -383,6 +404,8 @@
#ifdef CONFIG_SPI_MASTER
codec->hw_write = do_spi_write;
#endif
+ if (io_types[i].spi_read)
+ codec->hw_read = io_types[i].spi_read;
codec->control_data = container_of(codec->dev,
struct spi_device,
diff --git a/sound/soc/soc-jack.c b/sound/soc/soc-jack.c
index 7c17b98..38b0013 100644
--- a/sound/soc/soc-jack.c
+++ b/sound/soc/soc-jack.c
@@ -327,7 +327,7 @@
IRQF_TRIGGER_FALLING,
gpios[i].name,
&gpios[i]);
- if (ret)
+ if (ret < 0)
goto err;
if (gpios[i].wake) {
diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c
index b575939..2879c88 100644
--- a/sound/soc/soc-pcm.c
+++ b/sound/soc/soc-pcm.c
@@ -290,6 +290,9 @@
codec_dai->active--;
codec->active--;
+ if (!cpu_dai->active && !codec_dai->active)
+ rtd->rate = 0;
+
/* Muting the DAC suppresses artifacts caused during digital
* shutdown, for example from stopping clocks.
*/
diff --git a/sound/soc/tegra/tegra_wm8903.c b/sound/soc/tegra/tegra_wm8903.c
index 661373c..be27f1d 100644
--- a/sound/soc/tegra/tegra_wm8903.c
+++ b/sound/soc/tegra/tegra_wm8903.c
@@ -319,7 +319,7 @@
snd_soc_dapm_force_enable_pin(dapm, "Mic Bias");
/* FIXME: Calculate automatically based on DAPM routes? */
- if (!machine_is_harmony() && !machine_is_ventana())
+ if (!machine_is_harmony())
snd_soc_dapm_nc_pin(dapm, "IN1L");
if (!machine_is_seaboard() && !machine_is_aebl())
snd_soc_dapm_nc_pin(dapm, "IN1R");
@@ -395,7 +395,7 @@
platform_set_drvdata(pdev, card);
snd_soc_card_set_drvdata(card, machine);
- if (machine_is_harmony() || machine_is_ventana()) {
+ if (machine_is_harmony()) {
card->dapm_routes = harmony_audio_map;
card->num_dapm_routes = ARRAY_SIZE(harmony_audio_map);
} else if (machine_is_seaboard()) {
diff --git a/tools/perf/arch/arm/util/dwarf-regs.c b/tools/perf/arch/arm/util/dwarf-regs.c
index fff6450..e8d5c55 100644
--- a/tools/perf/arch/arm/util/dwarf-regs.c
+++ b/tools/perf/arch/arm/util/dwarf-regs.c
@@ -8,7 +8,10 @@
* published by the Free Software Foundation.
*/
+#include <stdlib.h>
+#ifndef __UCLIBC__
#include <libio.h>
+#endif
#include <dwarf-regs.h>
struct pt_regs_dwarfnum {
diff --git a/tools/power/cpupower/Makefile b/tools/power/cpupower/Makefile
index 94c2cf0..e8a03ac 100644
--- a/tools/power/cpupower/Makefile
+++ b/tools/power/cpupower/Makefile
@@ -24,7 +24,7 @@
# Set the following to `true' to make a unstripped, unoptimized
# binary. Leave this set to `false' for production use.
-DEBUG ?= false
+DEBUG ?= true
# make the build silent. Set this to something else to make it noisy again.
V ?= false
@@ -35,7 +35,7 @@
# Set the following to 'true' to build/install the
# cpufreq-bench benchmarking tool
-CPUFRQ_BENCH ?= true
+CPUFREQ_BENCH ?= true
# Prefix to the directories we're installing to
DESTDIR ?=
@@ -137,9 +137,10 @@
ifeq ($(strip $(NLS)),true)
INSTALL_NLS += install-gmo
COMPILE_NLS += create-gmo
+ CFLAGS += -DNLS
endif
-ifeq ($(strip $(CPUFRQ_BENCH)),true)
+ifeq ($(strip $(CPUFREQ_BENCH)),true)
INSTALL_BENCH += install-bench
COMPILE_BENCH += compile-bench
endif
diff --git a/tools/power/cpupower/debug/x86_64/Makefile b/tools/power/cpupower/debug/x86_64/Makefile
index dbf1399..3326217 100644
--- a/tools/power/cpupower/debug/x86_64/Makefile
+++ b/tools/power/cpupower/debug/x86_64/Makefile
@@ -1,10 +1,10 @@
default: all
-centrino-decode: centrino-decode.c
- $(CC) $(CFLAGS) -o centrino-decode centrino-decode.c
+centrino-decode: ../i386/centrino-decode.c
+ $(CC) $(CFLAGS) -o $@ $<
-powernow-k8-decode: powernow-k8-decode.c
- $(CC) $(CFLAGS) -o powernow-k8-decode powernow-k8-decode.c
+powernow-k8-decode: ../i386/powernow-k8-decode.c
+ $(CC) $(CFLAGS) -o $@ $<
all: centrino-decode powernow-k8-decode
diff --git a/tools/power/cpupower/debug/x86_64/centrino-decode.c b/tools/power/cpupower/debug/x86_64/centrino-decode.c
deleted file mode 120000
index 26fb3f1..0000000
--- a/tools/power/cpupower/debug/x86_64/centrino-decode.c
+++ /dev/null
@@ -1 +0,0 @@
-../i386/centrino-decode.c
\ No newline at end of file
diff --git a/tools/power/cpupower/debug/x86_64/powernow-k8-decode.c b/tools/power/cpupower/debug/x86_64/powernow-k8-decode.c
deleted file mode 120000
index eb30c79..0000000
--- a/tools/power/cpupower/debug/x86_64/powernow-k8-decode.c
+++ /dev/null
@@ -1 +0,0 @@
-../i386/powernow-k8-decode.c
\ No newline at end of file
diff --git a/tools/power/cpupower/man/cpupower-frequency-info.1 b/tools/power/cpupower/man/cpupower-frequency-info.1
index 3194811..bb60a8d 100644
--- a/tools/power/cpupower/man/cpupower-frequency-info.1
+++ b/tools/power/cpupower/man/cpupower-frequency-info.1
@@ -1,10 +1,10 @@
-.TH "cpufreq-info" "1" "0.1" "Mattia Dongili" ""
+.TH "cpupower-frequency-info" "1" "0.1" "Mattia Dongili" ""
.SH "NAME"
.LP
-cpufreq\-info \- Utility to retrieve cpufreq kernel information
+cpupower frequency\-info \- Utility to retrieve cpufreq kernel information
.SH "SYNTAX"
.LP
-cpufreq\-info [\fIoptions\fP]
+cpupower [ \-c cpulist ] frequency\-info [\fIoptions\fP]
.SH "DESCRIPTION"
.LP
A small tool which prints out cpufreq information helpful to developers and interested users.
diff --git a/tools/power/cpupower/man/cpupower-frequency-set.1 b/tools/power/cpupower/man/cpupower-frequency-set.1
index 26e3e13..685f469 100644
--- a/tools/power/cpupower/man/cpupower-frequency-set.1
+++ b/tools/power/cpupower/man/cpupower-frequency-set.1
@@ -1,13 +1,13 @@
-.TH "cpufreq-set" "1" "0.1" "Mattia Dongili" ""
+.TH "cpupower-freqency-set" "1" "0.1" "Mattia Dongili" ""
.SH "NAME"
.LP
-cpufreq\-set \- A small tool which allows to modify cpufreq settings.
+cpupower frequency\-set \- A small tool which allows to modify cpufreq settings.
.SH "SYNTAX"
.LP
-cpufreq\-set [\fIoptions\fP]
+cpupower [ \-c cpu ] frequency\-set [\fIoptions\fP]
.SH "DESCRIPTION"
.LP
-cpufreq\-set allows you to modify cpufreq settings without having to type e.g. "/sys/devices/system/cpu/cpu0/cpufreq/scaling_set_speed" all the time.
+cpupower frequency\-set allows you to modify cpufreq settings without having to type e.g. "/sys/devices/system/cpu/cpu0/cpufreq/scaling_set_speed" all the time.
.SH "OPTIONS"
.LP
.TP
diff --git a/tools/power/cpupower/man/cpupower.1 b/tools/power/cpupower/man/cpupower.1
index 78c20fe..baf741d 100644
--- a/tools/power/cpupower/man/cpupower.1
+++ b/tools/power/cpupower/man/cpupower.1
@@ -3,7 +3,7 @@
cpupower \- Shows and sets processor power related values
.SH SYNOPSIS
.ft B
-.B cpupower [ \-c cpulist ] subcommand [ARGS]
+.B cpupower [ \-c cpulist ] <command> [ARGS]
.B cpupower \-v|\-\-version
@@ -13,24 +13,24 @@
\fBcpupower \fP is a collection of tools to examine and tune power saving
related features of your processor.
-The manpages of the subcommands (cpupower\-<subcommand>(1)) provide detailed
+The manpages of the commands (cpupower\-<command>(1)) provide detailed
descriptions of supported features. Run \fBcpupower help\fP to get an overview
-of supported subcommands.
+of supported commands.
.SH Options
.PP
\-\-help, \-h
.RS 4
-Shows supported subcommands and general usage.
+Shows supported commands and general usage.
.RE
.PP
\-\-cpu cpulist, \-c cpulist
.RS 4
Only show or set values for specific cores.
-This option is not supported by all subcommands, details can be found in the
-manpages of the subcommands.
+This option is not supported by all commands, details can be found in the
+manpages of the commands.
-Some subcommands access all cores (typically the *\-set commands), some only
+Some commands access all cores (typically the *\-set commands), some only
the first core (typically the *\-info commands) by default.
The syntax for <cpulist> is based on how the kernel exports CPU bitmasks via
diff --git a/tools/power/cpupower/utils/builtin.h b/tools/power/cpupower/utils/builtin.h
index c870ffb..c10496f 100644
--- a/tools/power/cpupower/utils/builtin.h
+++ b/tools/power/cpupower/utils/builtin.h
@@ -8,11 +8,4 @@
extern int cmd_idle_info(int argc, const char **argv);
extern int cmd_monitor(int argc, const char **argv);
-extern void set_help(void);
-extern void info_help(void);
-extern void freq_set_help(void);
-extern void freq_info_help(void);
-extern void idle_info_help(void);
-extern void monitor_help(void);
-
#endif
diff --git a/tools/power/cpupower/utils/cpufreq-info.c b/tools/power/cpupower/utils/cpufreq-info.c
index 5a1d25f..28953c9 100644
--- a/tools/power/cpupower/utils/cpufreq-info.c
+++ b/tools/power/cpupower/utils/cpufreq-info.c
@@ -510,37 +510,6 @@
return 0;
}
-void freq_info_help(void)
-{
- printf(_("Usage: cpupower freqinfo [options]\n"));
- printf(_("Options:\n"));
- printf(_(" -e, --debug Prints out debug information [default]\n"));
- printf(_(" -f, --freq Get frequency the CPU currently runs at, according\n"
- " to the cpufreq core *\n"));
- printf(_(" -w, --hwfreq Get frequency the CPU currently runs at, by reading\n"
- " it from hardware (only available to root) *\n"));
- printf(_(" -l, --hwlimits Determine the minimum and maximum CPU frequency allowed *\n"));
- printf(_(" -d, --driver Determines the used cpufreq kernel driver *\n"));
- printf(_(" -p, --policy Gets the currently used cpufreq policy *\n"));
- printf(_(" -g, --governors Determines available cpufreq governors *\n"));
- printf(_(" -r, --related-cpus Determines which CPUs run at the same hardware frequency *\n"));
- printf(_(" -a, --affected-cpus Determines which CPUs need to have their frequency\n"
- " coordinated by software *\n"));
- printf(_(" -s, --stats Shows cpufreq statistics if available\n"));
- printf(_(" -y, --latency Determines the maximum latency on CPU frequency changes *\n"));
- printf(_(" -b, --boost Checks for turbo or boost modes *\n"));
- printf(_(" -o, --proc Prints out information like provided by the /proc/cpufreq\n"
- " interface in 2.4. and early 2.6. kernels\n"));
- printf(_(" -m, --human human-readable output for the -f, -w, -s and -y parameters\n"));
- printf(_(" -h, --help Prints out this screen\n"));
-
- printf("\n");
- printf(_("If no argument is given, full output about\n"
- "cpufreq is printed which is useful e.g. for reporting bugs.\n\n"));
- printf(_("By default info of CPU 0 is shown which can be overridden\n"
- "with the cpupower --cpu main command option.\n"));
-}
-
static struct option info_opts[] = {
{ .name = "debug", .has_arg = no_argument, .flag = NULL, .val = 'e'},
{ .name = "boost", .has_arg = no_argument, .flag = NULL, .val = 'b'},
@@ -556,7 +525,6 @@
{ .name = "latency", .has_arg = no_argument, .flag = NULL, .val = 'y'},
{ .name = "proc", .has_arg = no_argument, .flag = NULL, .val = 'o'},
{ .name = "human", .has_arg = no_argument, .flag = NULL, .val = 'm'},
- { .name = "help", .has_arg = no_argument, .flag = NULL, .val = 'h'},
{ },
};
@@ -570,16 +538,12 @@
int output_param = 0;
do {
- ret = getopt_long(argc, argv, "hoefwldpgrasmyb", info_opts, NULL);
+ ret = getopt_long(argc, argv, "oefwldpgrasmyb", info_opts, NULL);
switch (ret) {
case '?':
output_param = '?';
cont = 0;
break;
- case 'h':
- output_param = 'h';
- cont = 0;
- break;
case -1:
cont = 0;
break;
@@ -642,11 +606,7 @@
return -EINVAL;
case '?':
printf(_("invalid or unknown argument\n"));
- freq_info_help();
return -EINVAL;
- case 'h':
- freq_info_help();
- return EXIT_SUCCESS;
case 'o':
proc_cpufreq_output();
return EXIT_SUCCESS;
diff --git a/tools/power/cpupower/utils/cpufreq-set.c b/tools/power/cpupower/utils/cpufreq-set.c
index 5f78362..dd1539e 100644
--- a/tools/power/cpupower/utils/cpufreq-set.c
+++ b/tools/power/cpupower/utils/cpufreq-set.c
@@ -20,34 +20,11 @@
#define NORM_FREQ_LEN 32
-void freq_set_help(void)
-{
- printf(_("Usage: cpupower frequency-set [options]\n"));
- printf(_("Options:\n"));
- printf(_(" -d FREQ, --min FREQ new minimum CPU frequency the governor may select\n"));
- printf(_(" -u FREQ, --max FREQ new maximum CPU frequency the governor may select\n"));
- printf(_(" -g GOV, --governor GOV new cpufreq governor\n"));
- printf(_(" -f FREQ, --freq FREQ specific frequency to be set. Requires userspace\n"
- " governor to be available and loaded\n"));
- printf(_(" -r, --related Switches all hardware-related CPUs\n"));
- printf(_(" -h, --help Prints out this screen\n"));
- printf("\n");
- printf(_("Notes:\n"
- "1. Omitting the -c or --cpu argument is equivalent to setting it to \"all\"\n"));
- printf(_("2. The -f FREQ, --freq FREQ parameter cannot be combined with any other parameter\n"
- " except the -c CPU, --cpu CPU parameter\n"
- "3. FREQuencies can be passed in Hz, kHz (default), MHz, GHz, or THz\n"
- " by postfixing the value with the wanted unit name, without any space\n"
- " (FREQuency in kHz =^ Hz * 0.001 =^ MHz * 1000 =^ GHz * 1000000).\n"));
-
-}
-
static struct option set_opts[] = {
{ .name = "min", .has_arg = required_argument, .flag = NULL, .val = 'd'},
{ .name = "max", .has_arg = required_argument, .flag = NULL, .val = 'u'},
{ .name = "governor", .has_arg = required_argument, .flag = NULL, .val = 'g'},
{ .name = "freq", .has_arg = required_argument, .flag = NULL, .val = 'f'},
- { .name = "help", .has_arg = no_argument, .flag = NULL, .val = 'h'},
{ .name = "related", .has_arg = no_argument, .flag = NULL, .val='r'},
{ },
};
@@ -80,7 +57,6 @@
static void print_unknown_arg(void)
{
printf(_("invalid or unknown argument\n"));
- freq_set_help();
}
static unsigned long string_to_frequency(const char *str)
@@ -231,14 +207,11 @@
/* parameter parsing */
do {
- ret = getopt_long(argc, argv, "d:u:g:f:hr", set_opts, NULL);
+ ret = getopt_long(argc, argv, "d:u:g:f:r", set_opts, NULL);
switch (ret) {
case '?':
print_unknown_arg();
return -EINVAL;
- case 'h':
- freq_set_help();
- return 0;
case -1:
cont = 0;
break;
diff --git a/tools/power/cpupower/utils/cpuidle-info.c b/tools/power/cpupower/utils/cpuidle-info.c
index 70da357..b028267 100644
--- a/tools/power/cpupower/utils/cpuidle-info.c
+++ b/tools/power/cpupower/utils/cpuidle-info.c
@@ -139,30 +139,14 @@
}
}
-/* --freq / -f */
-
-void idle_info_help(void)
-{
- printf(_ ("Usage: cpupower idleinfo [options]\n"));
- printf(_ ("Options:\n"));
- printf(_ (" -s, --silent Only show general C-state information\n"));
- printf(_ (" -o, --proc Prints out information like provided by the /proc/acpi/processor/*/power\n"
- " interface in older kernels\n"));
- printf(_ (" -h, --help Prints out this screen\n"));
-
- printf("\n");
-}
-
static struct option info_opts[] = {
{ .name = "silent", .has_arg = no_argument, .flag = NULL, .val = 's'},
{ .name = "proc", .has_arg = no_argument, .flag = NULL, .val = 'o'},
- { .name = "help", .has_arg = no_argument, .flag = NULL, .val = 'h'},
{ },
};
static inline void cpuidle_exit(int fail)
{
- idle_info_help();
exit(EXIT_FAILURE);
}
@@ -174,7 +158,7 @@
unsigned int cpu = 0;
do {
- ret = getopt_long(argc, argv, "hos", info_opts, NULL);
+ ret = getopt_long(argc, argv, "os", info_opts, NULL);
if (ret == -1)
break;
switch (ret) {
@@ -182,10 +166,6 @@
output_param = '?';
cont = 0;
break;
- case 'h':
- output_param = 'h';
- cont = 0;
- break;
case 's':
verbose = 0;
break;
@@ -211,8 +191,6 @@
case '?':
printf(_("invalid or unknown argument\n"));
cpuidle_exit(EXIT_FAILURE);
- case 'h':
- cpuidle_exit(EXIT_SUCCESS);
}
/* Default is: show output of CPU 0 only */
diff --git a/tools/power/cpupower/utils/cpupower-info.c b/tools/power/cpupower/utils/cpupower-info.c
index 85253cb..3f68632 100644
--- a/tools/power/cpupower/utils/cpupower-info.c
+++ b/tools/power/cpupower/utils/cpupower-info.c
@@ -16,31 +16,16 @@
#include "helpers/helpers.h"
#include "helpers/sysfs.h"
-void info_help(void)
-{
- printf(_("Usage: cpupower info [ -b ] [ -m ] [ -s ]\n"));
- printf(_("Options:\n"));
- printf(_(" -b, --perf-bias Gets CPU's power vs performance policy on some\n"
- " Intel models [0-15], see manpage for details\n"));
- printf(_(" -m, --sched-mc Gets the kernel's multi core scheduler policy.\n"));
- printf(_(" -s, --sched-smt Gets the kernel's thread sibling scheduler policy.\n"));
- printf(_(" -h, --help Prints out this screen\n"));
- printf(_("\nPassing no option will show all info, by default only on core 0\n"));
- printf("\n");
-}
-
static struct option set_opts[] = {
{ .name = "perf-bias", .has_arg = optional_argument, .flag = NULL, .val = 'b'},
{ .name = "sched-mc", .has_arg = optional_argument, .flag = NULL, .val = 'm'},
{ .name = "sched-smt", .has_arg = optional_argument, .flag = NULL, .val = 's'},
- { .name = "help", .has_arg = no_argument, .flag = NULL, .val = 'h'},
{ },
};
static void print_wrong_arg_exit(void)
{
printf(_("invalid or unknown argument\n"));
- info_help();
exit(EXIT_FAILURE);
}
@@ -64,11 +49,8 @@
textdomain(PACKAGE);
/* parameter parsing */
- while ((ret = getopt_long(argc, argv, "msbh", set_opts, NULL)) != -1) {
+ while ((ret = getopt_long(argc, argv, "msb", set_opts, NULL)) != -1) {
switch (ret) {
- case 'h':
- info_help();
- return 0;
case 'b':
if (params.perf_bias)
print_wrong_arg_exit();
diff --git a/tools/power/cpupower/utils/cpupower-set.c b/tools/power/cpupower/utils/cpupower-set.c
index bc1b391..dc4de37 100644
--- a/tools/power/cpupower/utils/cpupower-set.c
+++ b/tools/power/cpupower/utils/cpupower-set.c
@@ -17,30 +17,16 @@
#include "helpers/sysfs.h"
#include "helpers/bitmask.h"
-void set_help(void)
-{
- printf(_("Usage: cpupower set [ -b val ] [ -m val ] [ -s val ]\n"));
- printf(_("Options:\n"));
- printf(_(" -b, --perf-bias [VAL] Sets CPU's power vs performance policy on some\n"
- " Intel models [0-15], see manpage for details\n"));
- printf(_(" -m, --sched-mc [VAL] Sets the kernel's multi core scheduler policy.\n"));
- printf(_(" -s, --sched-smt [VAL] Sets the kernel's thread sibling scheduler policy.\n"));
- printf(_(" -h, --help Prints out this screen\n"));
- printf("\n");
-}
-
static struct option set_opts[] = {
{ .name = "perf-bias", .has_arg = optional_argument, .flag = NULL, .val = 'b'},
{ .name = "sched-mc", .has_arg = optional_argument, .flag = NULL, .val = 'm'},
{ .name = "sched-smt", .has_arg = optional_argument, .flag = NULL, .val = 's'},
- { .name = "help", .has_arg = no_argument, .flag = NULL, .val = 'h'},
{ },
};
static void print_wrong_arg_exit(void)
{
printf(_("invalid or unknown argument\n"));
- set_help();
exit(EXIT_FAILURE);
}
@@ -66,12 +52,9 @@
params.params = 0;
/* parameter parsing */
- while ((ret = getopt_long(argc, argv, "m:s:b:h",
+ while ((ret = getopt_long(argc, argv, "m:s:b:",
set_opts, NULL)) != -1) {
switch (ret) {
- case 'h':
- set_help();
- return 0;
case 'b':
if (params.perf_bias)
print_wrong_arg_exit();
@@ -110,10 +93,8 @@
}
};
- if (!params.params) {
- set_help();
- return -EINVAL;
- }
+ if (!params.params)
+ print_wrong_arg_exit();
if (params.sched_mc) {
ret = sysfs_set_sched("mc", sched_mc);
diff --git a/tools/power/cpupower/utils/cpupower.c b/tools/power/cpupower/utils/cpupower.c
index 5844ae0..52bee59 100644
--- a/tools/power/cpupower/utils/cpupower.c
+++ b/tools/power/cpupower/utils/cpupower.c
@@ -11,6 +11,7 @@
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
+#include <errno.h>
#include "builtin.h"
#include "helpers/helpers.h"
@@ -19,13 +20,12 @@
struct cmd_struct {
const char *cmd;
int (*main)(int, const char **);
- void (*usage)(void);
int needs_root;
};
#define ARRAY_SIZE(x) (sizeof(x)/sizeof(x[0]))
-int cmd_help(int argc, const char **argv);
+static int cmd_help(int argc, const char **argv);
/* Global cpu_info object available for all binaries
* Info only retrieved from CPU 0
@@ -44,55 +44,66 @@
static void print_help(void);
static struct cmd_struct commands[] = {
- { "frequency-info", cmd_freq_info, freq_info_help, 0 },
- { "frequency-set", cmd_freq_set, freq_set_help, 1 },
- { "idle-info", cmd_idle_info, idle_info_help, 0 },
- { "set", cmd_set, set_help, 1 },
- { "info", cmd_info, info_help, 0 },
- { "monitor", cmd_monitor, monitor_help, 0 },
- { "help", cmd_help, print_help, 0 },
- /* { "bench", cmd_bench, NULL, 1 }, */
+ { "frequency-info", cmd_freq_info, 0 },
+ { "frequency-set", cmd_freq_set, 1 },
+ { "idle-info", cmd_idle_info, 0 },
+ { "set", cmd_set, 1 },
+ { "info", cmd_info, 0 },
+ { "monitor", cmd_monitor, 0 },
+ { "help", cmd_help, 0 },
+ /* { "bench", cmd_bench, 1 }, */
};
-int cmd_help(int argc, const char **argv)
-{
- unsigned int i;
-
- if (argc > 1) {
- for (i = 0; i < ARRAY_SIZE(commands); i++) {
- struct cmd_struct *p = commands + i;
- if (strcmp(p->cmd, argv[1]))
- continue;
- if (p->usage) {
- p->usage();
- return EXIT_SUCCESS;
- }
- }
- }
- print_help();
- if (argc == 1)
- return EXIT_SUCCESS; /* cpupower help */
- return EXIT_FAILURE;
-}
-
static void print_help(void)
{
unsigned int i;
#ifdef DEBUG
- printf(_("cpupower [ -d ][ -c cpulist ] subcommand [ARGS]\n"));
- printf(_(" -d, --debug May increase output (stderr) on some subcommands\n"));
+ printf(_("Usage:\tcpupower [-d|--debug] [-c|--cpu cpulist ] <command> [<args>]\n"));
#else
- printf(_("cpupower [ -c cpulist ] subcommand [ARGS]\n"));
+ printf(_("Usage:\tcpupower [-c|--cpu cpulist ] <command> [<args>]\n"));
#endif
- printf(_("cpupower --version\n"));
- printf(_("Supported subcommands are:\n"));
+ printf(_("Supported commands are:\n"));
for (i = 0; i < ARRAY_SIZE(commands); i++)
printf("\t%s\n", commands[i].cmd);
- printf(_("\nSome subcommands can make use of the -c cpulist option.\n"));
- printf(_("Look at the general cpupower manpage how to use it\n"));
- printf(_("and read up the subcommand's manpage whether it is supported.\n"));
- printf(_("\nUse cpupower help subcommand for getting help for above subcommands.\n"));
+ printf(_("\nNot all commands can make use of the -c cpulist option.\n"));
+ printf(_("\nUse 'cpupower help <command>' for getting help for above commands.\n"));
+}
+
+static int print_man_page(const char *subpage)
+{
+ int len;
+ char *page;
+
+ len = 10; /* enough for "cpupower-" */
+ if (subpage != NULL)
+ len += strlen(subpage);
+
+ page = malloc(len);
+ if (!page)
+ return -ENOMEM;
+
+ sprintf(page, "cpupower");
+ if ((subpage != NULL) && strcmp(subpage, "help")) {
+ strcat(page, "-");
+ strcat(page, subpage);
+ }
+
+ execlp("man", "man", page, NULL);
+
+ /* should not be reached */
+ return -EINVAL;
+}
+
+static int cmd_help(int argc, const char **argv)
+{
+ if (argc > 1) {
+ print_man_page(argv[1]); /* exits within execlp() */
+ return EXIT_FAILURE;
+ }
+
+ print_help();
+ return EXIT_SUCCESS;
}
static void print_version(void)
diff --git a/tools/power/cpupower/utils/helpers/helpers.h b/tools/power/cpupower/utils/helpers/helpers.h
index 592ee36..2747e73 100644
--- a/tools/power/cpupower/utils/helpers/helpers.h
+++ b/tools/power/cpupower/utils/helpers/helpers.h
@@ -16,11 +16,20 @@
#include "helpers/bitmask.h"
/* Internationalization ****************************/
+#ifdef NLS
+
#define _(String) gettext(String)
#ifndef gettext_noop
#define gettext_noop(String) String
#endif
#define N_(String) gettext_noop(String)
+
+#else /* !NLS */
+
+#define _(String) String
+#define N_(String) String
+
+#endif
/* Internationalization ****************************/
extern int run_as_root;
@@ -96,6 +105,9 @@
int pkg;
int core;
int cpu;
+
+ /* flags */
+ unsigned int is_online:1;
} *core_info;
};
diff --git a/tools/power/cpupower/utils/helpers/sysfs.c b/tools/power/cpupower/utils/helpers/sysfs.c
index 55e2466..c634302 100644
--- a/tools/power/cpupower/utils/helpers/sysfs.c
+++ b/tools/power/cpupower/utils/helpers/sysfs.c
@@ -56,6 +56,56 @@
return (unsigned int) numwrite;
}
+/*
+ * Detect whether a CPU is online
+ *
+ * Returns:
+ * 1 -> if CPU is online
+ * 0 -> if CPU is offline
+ * negative errno values in error case
+ */
+int sysfs_is_cpu_online(unsigned int cpu)
+{
+ char path[SYSFS_PATH_MAX];
+ int fd;
+ ssize_t numread;
+ unsigned long long value;
+ char linebuf[MAX_LINE_LEN];
+ char *endp;
+ struct stat statbuf;
+
+ snprintf(path, sizeof(path), PATH_TO_CPU "cpu%u", cpu);
+
+ if (stat(path, &statbuf) != 0)
+ return 0;
+
+ /*
+ * kernel without CONFIG_HOTPLUG_CPU
+ * -> cpuX directory exists, but not cpuX/online file
+ */
+ snprintf(path, sizeof(path), PATH_TO_CPU "cpu%u/online", cpu);
+ if (stat(path, &statbuf) != 0)
+ return 1;
+
+ fd = open(path, O_RDONLY);
+ if (fd == -1)
+ return -errno;
+
+ numread = read(fd, linebuf, MAX_LINE_LEN - 1);
+ if (numread < 1) {
+ close(fd);
+ return -EIO;
+ }
+ linebuf[numread] = '\0';
+ close(fd);
+
+ value = strtoull(linebuf, &endp, 0);
+ if (value > 1 || value < 0)
+ return -EINVAL;
+
+ return value;
+}
+
/* CPUidle idlestate specific /sys/devices/system/cpu/cpuX/cpuidle/ access */
/*
diff --git a/tools/power/cpupower/utils/helpers/sysfs.h b/tools/power/cpupower/utils/helpers/sysfs.h
index f9373e0..8cb797b 100644
--- a/tools/power/cpupower/utils/helpers/sysfs.h
+++ b/tools/power/cpupower/utils/helpers/sysfs.h
@@ -7,6 +7,8 @@
extern unsigned int sysfs_read_file(const char *path, char *buf, size_t buflen);
+extern int sysfs_is_cpu_online(unsigned int cpu);
+
extern unsigned long sysfs_get_idlestate_latency(unsigned int cpu,
unsigned int idlestate);
extern unsigned long sysfs_get_idlestate_usage(unsigned int cpu,
diff --git a/tools/power/cpupower/utils/helpers/topology.c b/tools/power/cpupower/utils/helpers/topology.c
index 385ee5c..4eae2c4 100644
--- a/tools/power/cpupower/utils/helpers/topology.c
+++ b/tools/power/cpupower/utils/helpers/topology.c
@@ -41,6 +41,8 @@
unsigned int pkg;
unsigned int thread;
unsigned int cpu;
+ /* flags */
+ unsigned int is_online:1;
};
static int __compare(const void *t1, const void *t2)
@@ -78,6 +80,8 @@
return -ENOMEM;
cpu_top->pkgs = cpu_top->cores = 0;
for (cpu = 0; cpu < cpus; cpu++) {
+ cpu_top->core_info[cpu].cpu = cpu;
+ cpu_top->core_info[cpu].is_online = sysfs_is_cpu_online(cpu);
cpu_top->core_info[cpu].pkg =
sysfs_topology_read_file(cpu, "physical_package_id");
if ((int)cpu_top->core_info[cpu].pkg != -1 &&
@@ -85,7 +89,6 @@
cpu_top->pkgs = cpu_top->core_info[cpu].pkg;
cpu_top->core_info[cpu].core =
sysfs_topology_read_file(cpu, "core_id");
- cpu_top->core_info[cpu].cpu = cpu;
}
cpu_top->pkgs++;
diff --git a/tools/power/cpupower/utils/idle_monitor/cpuidle_sysfs.c b/tools/power/cpupower/utils/idle_monitor/cpuidle_sysfs.c
index d048b96..bcd22a1 100644
--- a/tools/power/cpupower/utils/idle_monitor/cpuidle_sysfs.c
+++ b/tools/power/cpupower/utils/idle_monitor/cpuidle_sysfs.c
@@ -134,7 +134,7 @@
/* Assume idle state count is the same for all CPUs */
cpuidle_sysfs_monitor.hw_states_num = sysfs_get_idlestate_count(0);
- if (cpuidle_sysfs_monitor.hw_states_num == 0)
+ if (cpuidle_sysfs_monitor.hw_states_num <= 0)
return NULL;
for (num = 0; num < cpuidle_sysfs_monitor.hw_states_num; num++) {
diff --git a/tools/power/cpupower/utils/idle_monitor/cpupower-monitor.c b/tools/power/cpupower/utils/idle_monitor/cpupower-monitor.c
index ba4bf06..0d6571e 100644
--- a/tools/power/cpupower/utils/idle_monitor/cpupower-monitor.c
+++ b/tools/power/cpupower/utils/idle_monitor/cpupower-monitor.c
@@ -43,6 +43,12 @@
/* ToDo: Document this in the manpage */
static char range_abbr[RANGE_MAX] = { 'T', 'C', 'P', 'M', };
+static void print_wrong_arg_exit(void)
+{
+ printf(_("invalid or unknown argument\n"));
+ exit(EXIT_FAILURE);
+}
+
long long timespec_diff_us(struct timespec start, struct timespec end)
{
struct timespec temp;
@@ -56,21 +62,6 @@
return (temp.tv_sec * 1000000) + (temp.tv_nsec / 1000);
}
-void monitor_help(void)
-{
- printf(_("cpupower monitor: [-m <mon1>,[<mon2>],.. ] command\n"));
- printf(_("cpupower monitor: [-m <mon1>,[<mon2>],.. ] [ -i interval_sec ]\n"));
- printf(_("cpupower monitor: -l\n"));
- printf(_("\t command: pass an arbitrary command to measure specific workload\n"));
- printf(_("\t -i: time intervall to measure for in seconds (default 1)\n"));
- printf(_("\t -l: list available CPU sleep monitors (for use with -m)\n"));
- printf(_("\t -m: show specific CPU sleep monitors only (in same order)\n"));
- printf(_("\t -h: print this help\n"));
- printf("\n");
- printf(_("only one of: -l, -m are allowed\nIf none of them is passed,"));
- printf(_(" all supported monitors are shown\n"));
-}
-
void print_n_spaces(int n)
{
int x;
@@ -149,6 +140,10 @@
unsigned long long result;
cstate_t s;
+ /* Be careful CPUs may got resorted for pkg value do not just use cpu */
+ if (!bitmask_isbitset(cpus_chosen, cpu_top.core_info[cpu].cpu))
+ return;
+
if (topology_depth > 2)
printf("%4d|", cpu_top.core_info[cpu].pkg);
if (topology_depth > 1)
@@ -190,9 +185,13 @@
}
}
}
- /* cpu offline */
- if (cpu_top.core_info[cpu].pkg == -1 ||
- cpu_top.core_info[cpu].core == -1) {
+ /*
+ * The monitor could still provide useful data, for example
+ * AMD HW counters partly sit in PCI config space.
+ * It's up to the monitor plug-in to check .is_online, this one
+ * is just for additional info.
+ */
+ if (!cpu_top.core_info[cpu].is_online) {
printf(_(" *is offline\n"));
return;
} else
@@ -238,7 +237,6 @@
if (hits == 0) {
printf(_("No matching monitor found in %s, "
"try -l option\n"), param);
- monitor_help();
exit(EXIT_FAILURE);
}
/* Override detected/registerd monitors array with requested one */
@@ -335,37 +333,27 @@
int opt;
progname = basename(argv[0]);
- while ((opt = getopt(argc, argv, "+hli:m:")) != -1) {
+ while ((opt = getopt(argc, argv, "+li:m:")) != -1) {
switch (opt) {
- case 'h':
- monitor_help();
- exit(EXIT_SUCCESS);
case 'l':
- if (mode) {
- monitor_help();
- exit(EXIT_FAILURE);
- }
+ if (mode)
+ print_wrong_arg_exit();
mode = list;
break;
case 'i':
/* only allow -i with -m or no option */
- if (mode && mode != show) {
- monitor_help();
- exit(EXIT_FAILURE);
- }
+ if (mode && mode != show)
+ print_wrong_arg_exit();
interval = atoi(optarg);
break;
case 'm':
- if (mode) {
- monitor_help();
- exit(EXIT_FAILURE);
- }
+ if (mode)
+ print_wrong_arg_exit();
mode = show;
show_monitors_param = optarg;
break;
default:
- monitor_help();
- exit(EXIT_FAILURE);
+ print_wrong_arg_exit();
}
}
if (!mode)
@@ -385,6 +373,10 @@
return EXIT_FAILURE;
}
+ /* Default is: monitor all CPUs */
+ if (bitmask_isallclear(cpus_chosen))
+ bitmask_setall(cpus_chosen);
+
dprint("System has up to %d CPU cores\n", cpu_count);
for (num = 0; all_monitors[num]; num++) {
diff --git a/tools/power/cpupower/utils/idle_monitor/mperf_monitor.c b/tools/power/cpupower/utils/idle_monitor/mperf_monitor.c
index 63ca87a..5650ab5 100644
--- a/tools/power/cpupower/utils/idle_monitor/mperf_monitor.c
+++ b/tools/power/cpupower/utils/idle_monitor/mperf_monitor.c
@@ -22,12 +22,15 @@
#define MSR_TSC 0x10
+#define MSR_AMD_HWCR 0xc0010015
+
enum mperf_id { C0 = 0, Cx, AVG_FREQ, MPERF_CSTATE_COUNT };
static int mperf_get_count_percent(unsigned int self_id, double *percent,
unsigned int cpu);
static int mperf_get_count_freq(unsigned int id, unsigned long long *count,
unsigned int cpu);
+static struct timespec time_start, time_end;
static cstate_t mperf_cstates[MPERF_CSTATE_COUNT] = {
{
@@ -54,19 +57,33 @@
},
};
+enum MAX_FREQ_MODE { MAX_FREQ_SYSFS, MAX_FREQ_TSC_REF };
+static int max_freq_mode;
+/*
+ * The max frequency mperf is ticking at (in C0), either retrieved via:
+ * 1) calculated after measurements if we know TSC ticks at mperf/P0 frequency
+ * 2) cpufreq /sys/devices/.../cpu0/cpufreq/cpuinfo_max_freq at init time
+ * 1. Is preferred as it also works without cpufreq subsystem (e.g. on Xen)
+ */
+static unsigned long max_frequency;
+
static unsigned long long tsc_at_measure_start;
static unsigned long long tsc_at_measure_end;
-static unsigned long max_frequency;
static unsigned long long *mperf_previous_count;
static unsigned long long *aperf_previous_count;
static unsigned long long *mperf_current_count;
static unsigned long long *aperf_current_count;
+
/* valid flag for all CPUs. If a MSR read failed it will be zero */
static int *is_valid;
static int mperf_get_tsc(unsigned long long *tsc)
{
- return read_msr(0, MSR_TSC, tsc);
+ int ret;
+ ret = read_msr(0, MSR_TSC, tsc);
+ if (ret)
+ dprint("Reading TSC MSR failed, returning %llu\n", *tsc);
+ return ret;
}
static int mperf_init_stats(unsigned int cpu)
@@ -97,36 +114,11 @@
return 0;
}
-/*
- * get_average_perf()
- *
- * Returns the average performance (also considers boosted frequencies)
- *
- * Input:
- * aperf_diff: Difference of the aperf register over a time period
- * mperf_diff: Difference of the mperf register over the same time period
- * max_freq: Maximum frequency (P0)
- *
- * Returns:
- * Average performance over the time period
- */
-static unsigned long get_average_perf(unsigned long long aperf_diff,
- unsigned long long mperf_diff)
-{
- unsigned int perf_percent = 0;
- if (((unsigned long)(-1) / 100) < aperf_diff) {
- int shift_count = 7;
- aperf_diff >>= shift_count;
- mperf_diff >>= shift_count;
- }
- perf_percent = (aperf_diff * 100) / mperf_diff;
- return (max_frequency * perf_percent) / 100;
-}
-
static int mperf_get_count_percent(unsigned int id, double *percent,
unsigned int cpu)
{
unsigned long long aperf_diff, mperf_diff, tsc_diff;
+ unsigned long long timediff;
if (!is_valid[cpu])
return -1;
@@ -136,11 +128,19 @@
mperf_diff = mperf_current_count[cpu] - mperf_previous_count[cpu];
aperf_diff = aperf_current_count[cpu] - aperf_previous_count[cpu];
- tsc_diff = tsc_at_measure_end - tsc_at_measure_start;
- *percent = 100.0 * mperf_diff / tsc_diff;
- dprint("%s: mperf_diff: %llu, tsc_diff: %llu\n",
- mperf_cstates[id].name, mperf_diff, tsc_diff);
+ if (max_freq_mode == MAX_FREQ_TSC_REF) {
+ tsc_diff = tsc_at_measure_end - tsc_at_measure_start;
+ *percent = 100.0 * mperf_diff / tsc_diff;
+ dprint("%s: TSC Ref - mperf_diff: %llu, tsc_diff: %llu\n",
+ mperf_cstates[id].name, mperf_diff, tsc_diff);
+ } else if (max_freq_mode == MAX_FREQ_SYSFS) {
+ timediff = timespec_diff_us(time_start, time_end);
+ *percent = 100.0 * mperf_diff / timediff;
+ dprint("%s: MAXFREQ - mperf_diff: %llu, time_diff: %llu\n",
+ mperf_cstates[id].name, mperf_diff, timediff);
+ } else
+ return -1;
if (id == Cx)
*percent = 100.0 - *percent;
@@ -154,7 +154,7 @@
static int mperf_get_count_freq(unsigned int id, unsigned long long *count,
unsigned int cpu)
{
- unsigned long long aperf_diff, mperf_diff;
+ unsigned long long aperf_diff, mperf_diff, time_diff, tsc_diff;
if (id != AVG_FREQ)
return 1;
@@ -165,11 +165,21 @@
mperf_diff = mperf_current_count[cpu] - mperf_previous_count[cpu];
aperf_diff = aperf_current_count[cpu] - aperf_previous_count[cpu];
- /* Return MHz for now, might want to return KHz if column width is more
- generic */
- *count = get_average_perf(aperf_diff, mperf_diff) / 1000;
- dprint("%s: %llu\n", mperf_cstates[id].name, *count);
+ if (max_freq_mode == MAX_FREQ_TSC_REF) {
+ /* Calculate max_freq from TSC count */
+ tsc_diff = tsc_at_measure_end - tsc_at_measure_start;
+ time_diff = timespec_diff_us(time_start, time_end);
+ max_frequency = tsc_diff / time_diff;
+ }
+ *count = max_frequency * ((double)aperf_diff / mperf_diff);
+ dprint("%s: Average freq based on %s maximum frequency:\n",
+ mperf_cstates[id].name,
+ (max_freq_mode == MAX_FREQ_TSC_REF) ? "TSC calculated" : "sysfs read");
+ dprint("%max_frequency: %lu", max_frequency);
+ dprint("aperf_diff: %llu\n", aperf_diff);
+ dprint("mperf_diff: %llu\n", mperf_diff);
+ dprint("avg freq: %llu\n", *count);
return 0;
}
@@ -178,6 +188,7 @@
int cpu;
unsigned long long dbg;
+ clock_gettime(CLOCK_REALTIME, &time_start);
mperf_get_tsc(&tsc_at_measure_start);
for (cpu = 0; cpu < cpu_count; cpu++)
@@ -193,32 +204,104 @@
unsigned long long dbg;
int cpu;
- mperf_get_tsc(&tsc_at_measure_end);
-
for (cpu = 0; cpu < cpu_count; cpu++)
mperf_measure_stats(cpu);
+ mperf_get_tsc(&tsc_at_measure_end);
+ clock_gettime(CLOCK_REALTIME, &time_end);
+
mperf_get_tsc(&dbg);
dprint("TSC diff: %llu\n", dbg - tsc_at_measure_end);
return 0;
}
-struct cpuidle_monitor mperf_monitor;
-
-struct cpuidle_monitor *mperf_register(void)
+/*
+ * Mperf register is defined to tick at P0 (maximum) frequency
+ *
+ * Instead of reading out P0 which can be tricky to read out from HW,
+ * we use TSC counter if it reliably ticks at P0/mperf frequency.
+ *
+ * Still try to fall back to:
+ * /sys/devices/system/cpu/cpu0/cpufreq/cpuinfo_max_freq
+ * on older Intel HW without invariant TSC feature.
+ * Or on AMD machines where TSC does not tick at P0 (do not exist yet, but
+ * it's still double checked (MSR_AMD_HWCR)).
+ *
+ * On these machines the user would still get useful mperf
+ * stats when acpi-cpufreq driver is loaded.
+ */
+static int init_maxfreq_mode(void)
{
+ int ret;
+ unsigned long long hwcr;
unsigned long min;
- if (!(cpupower_cpu_info.caps & CPUPOWER_CAP_APERF))
- return NULL;
+ if (!cpupower_cpu_info.caps & CPUPOWER_CAP_INV_TSC)
+ goto use_sysfs;
- /* Assume min/max all the same on all cores */
+ if (cpupower_cpu_info.vendor == X86_VENDOR_AMD) {
+ /* MSR_AMD_HWCR tells us whether TSC runs at P0/mperf
+ * freq.
+ * A test whether hwcr is accessable/available would be:
+ * (cpupower_cpu_info.family > 0x10 ||
+ * cpupower_cpu_info.family == 0x10 &&
+ * cpupower_cpu_info.model >= 0x2))
+ * This should be the case for all aperf/mperf
+ * capable AMD machines and is therefore safe to test here.
+ * Compare with Linus kernel git commit: acf01734b1747b1ec4
+ */
+ ret = read_msr(0, MSR_AMD_HWCR, &hwcr);
+ /*
+ * If the MSR read failed, assume a Xen system that did
+ * not explicitly provide access to it and assume TSC works
+ */
+ if (ret != 0) {
+ dprint("TSC read 0x%x failed - assume TSC working\n",
+ MSR_AMD_HWCR);
+ return 0;
+ } else if (1 & (hwcr >> 24)) {
+ max_freq_mode = MAX_FREQ_TSC_REF;
+ return 0;
+ } else { /* Use sysfs max frequency if available */ }
+ } else if (cpupower_cpu_info.vendor == X86_VENDOR_INTEL) {
+ /*
+ * On Intel we assume mperf (in C0) is ticking at same
+ * rate than TSC
+ */
+ max_freq_mode = MAX_FREQ_TSC_REF;
+ return 0;
+ }
+use_sysfs:
if (cpufreq_get_hardware_limits(0, &min, &max_frequency)) {
dprint("Cannot retrieve max freq from cpufreq kernel "
"subsystem\n");
- return NULL;
+ return -1;
}
+ max_freq_mode = MAX_FREQ_SYSFS;
+ return 0;
+}
+
+/*
+ * This monitor provides:
+ *
+ * 1) Average frequency a CPU resided in
+ * This always works if the CPU has aperf/mperf capabilities
+ *
+ * 2) C0 and Cx (any sleep state) time a CPU resided in
+ * Works if mperf timer stops ticking in sleep states which
+ * seem to be the case on all current HW.
+ * Both is directly retrieved from HW registers and is independent
+ * from kernel statistics.
+ */
+struct cpuidle_monitor mperf_monitor;
+struct cpuidle_monitor *mperf_register(void)
+{
+ if (!(cpupower_cpu_info.caps & CPUPOWER_CAP_APERF))
+ return NULL;
+
+ if (init_maxfreq_mode())
+ return NULL;
/* Free this at program termination */
is_valid = calloc(cpu_count, sizeof(int));