summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Documentation/devicetree/bindings/arm/atmel-at91.txt2
-rw-r--r--MAINTAINERS17
-rw-r--r--Makefile2
-rw-r--r--arch/arm/boot/dts/at91sam9g20ek_common.dtsi4
-rw-r--r--arch/arm/boot/dts/dbx5x0.dtsi17
-rw-r--r--arch/arm/boot/dts/exynos4210-trats.dts6
-rw-r--r--arch/arm/boot/dts/imx23.dtsi1
-rw-r--r--arch/arm/boot/dts/imx28.dtsi1
-rw-r--r--arch/arm/boot/dts/omap3.dtsi4
-rw-r--r--arch/arm/configs/imx_v6_v7_defconfig2
-rw-r--r--arch/arm/configs/mvebu_defconfig10
-rw-r--r--arch/arm/configs/versatile_defconfig1
-rw-r--r--arch/arm/include/debug/8250_32.S27
-rw-r--r--arch/arm/include/debug/picoxcell.S18
-rw-r--r--arch/arm/include/debug/socfpga.S5
-rw-r--r--arch/arm/mach-at91/Kconfig10
-rw-r--r--arch/arm/mach-at91/at91rm9200.c2
-rw-r--r--arch/arm/mach-at91/at91rm9200_devices.c4
-rw-r--r--arch/arm/mach-at91/at91sam9260.c4
-rw-r--r--arch/arm/mach-at91/at91sam9260_devices.c4
-rw-r--r--arch/arm/mach-at91/at91sam9261.c4
-rw-r--r--arch/arm/mach-at91/at91sam9261_devices.c4
-rw-r--r--arch/arm/mach-at91/at91sam9263.c2
-rw-r--r--arch/arm/mach-at91/at91sam9263_devices.c4
-rw-r--r--arch/arm/mach-at91/at91sam9rl_devices.c4
-rw-r--r--arch/arm/mach-at91/at91x40.c2
-rw-r--r--arch/arm/mach-at91/board-neocore926.c2
-rw-r--r--arch/arm/mach-at91/board-sam9261ek.c2
-rw-r--r--arch/arm/mach-at91/board-sam9263ek.c2
-rw-r--r--arch/arm/mach-at91/generic.h3
-rw-r--r--arch/arm/mach-at91/irq.c9
-rw-r--r--arch/arm/mach-at91/setup.c4
-rw-r--r--arch/arm/mach-exynos/common.c5
-rw-r--r--arch/arm/mach-exynos/mach-exynos4-dt.c1
-rw-r--r--arch/arm/mach-imx/clk-busy.c2
-rw-r--r--arch/arm/mach-imx/clk-imx25.c4
-rw-r--r--arch/arm/mach-imx/clk-imx27.c4
-rw-r--r--arch/arm/mach-imx/mm-imx3.c5
-rw-r--r--arch/arm/mach-omap2/Kconfig1
-rw-r--r--arch/arm/mach-omap2/board-omap3beagle.c22
-rw-r--r--arch/arm/mach-omap2/clock33xx_data.c2
-rw-r--r--arch/arm/mach-omap2/mux34xx.c8
-rw-r--r--arch/arm/mach-omap2/pm.h1
-rw-r--r--arch/arm/mach-omap2/pm34xx.c30
-rw-r--r--arch/arm/mach-omap2/serial.c5
-rw-r--r--arch/arm/mach-s3c24xx/s3c2416.c2
-rw-r--r--arch/arm/mach-s3c24xx/s3c2443.c4
-rw-r--r--arch/arm/mach-s5p64x0/common.c3
-rw-r--r--arch/arm/mach-s5pc100/common.c3
-rw-r--r--arch/arm/mach-s5pv210/common.c3
-rw-r--r--arch/arm/mach-shmobile/setup-r8a7779.c2
-rw-r--r--arch/arm/mach-spear13xx/include/mach/spear1310_misc_regs.h0
-rw-r--r--arch/arm/mach-spear13xx/include/mach/spear1340_misc_regs.h0
-rw-r--r--arch/arm/mach-ux500/cpu.c1
-rw-r--r--arch/arm/plat-mxc/devices/platform-mxc-mmc.c2
-rw-r--r--arch/arm/plat-omap/Kconfig1
-rw-r--r--arch/arm/plat-samsung/include/plat/spi-core.h30
-rw-r--r--arch/arm64/Kconfig2
-rw-r--r--arch/arm64/include/asm/processor.h5
-rw-r--r--arch/arm64/include/asm/syscalls.h3
-rw-r--r--arch/arm64/include/asm/unistd.h1
-rw-r--r--arch/arm64/include/asm/unistd32.h2
-rw-r--r--arch/arm64/kernel/entry.S12
-rw-r--r--arch/arm64/kernel/process.c77
-rw-r--r--arch/arm64/kernel/sys.c65
-rw-r--r--arch/arm64/kernel/sys32.S5
-rw-r--r--arch/arm64/kernel/sys_compat.c18
-rw-r--r--arch/c6x/Kconfig1
-rw-r--r--arch/c6x/include/uapi/asm/unistd.h1
-rw-r--r--arch/c6x/kernel/entry.S12
-rw-r--r--arch/frv/Kconfig1
-rw-r--r--arch/frv/boot/Makefile10
-rw-r--r--arch/frv/include/asm/unistd.h1
-rw-r--r--arch/frv/kernel/entry.S28
-rw-r--r--arch/frv/kernel/process.c5
-rw-r--r--arch/frv/mb93090-mb00/pci-dma-nommu.c1
-rw-r--r--arch/hexagon/Kconfig2
-rw-r--r--arch/hexagon/include/asm/processor.h1
-rw-r--r--arch/hexagon/include/uapi/asm/ptrace.h4
-rw-r--r--arch/hexagon/include/uapi/asm/unistd.h1
-rw-r--r--arch/hexagon/kernel/process.c102
-rw-r--r--arch/hexagon/kernel/signal.c4
-rw-r--r--arch/hexagon/kernel/syscall.c44
-rw-r--r--arch/hexagon/kernel/vm_entry.S4
-rw-r--r--arch/ia64/Kconfig2
-rw-r--r--arch/ia64/include/asm/processor.h16
-rw-r--r--arch/ia64/include/asm/unistd.h1
-rw-r--r--arch/ia64/kernel/entry.S39
-rw-r--r--arch/ia64/kernel/head.S13
-rw-r--r--arch/ia64/kernel/process.c158
-rw-r--r--arch/m68k/Kconfig1
-rw-r--r--arch/m68k/include/asm/unistd.h1
-rw-r--r--arch/m68k/kernel/entry.S7
-rw-r--r--arch/mips/Kconfig2
-rw-r--r--arch/mips/include/asm/processor.h2
-rw-r--r--arch/mips/include/asm/ptrace.h6
-rw-r--r--arch/mips/include/asm/unistd.h1
-rw-r--r--arch/mips/kernel/entry.S6
-rw-r--r--arch/mips/kernel/linux32.c21
-rw-r--r--arch/mips/kernel/mips_ksyms.c2
-rw-r--r--arch/mips/kernel/process.c62
-rw-r--r--arch/mips/kernel/scall64-n32.S2
-rw-r--r--arch/mips/kernel/scall64-o32.S2
-rw-r--r--arch/mips/kernel/syscall.c53
-rw-r--r--arch/openrisc/Kconfig2
-rw-r--r--arch/openrisc/include/uapi/asm/unistd.h2
-rw-r--r--arch/openrisc/kernel/entry.S43
-rw-r--r--arch/openrisc/kernel/process.c163
-rw-r--r--arch/parisc/Kconfig2
-rw-r--r--arch/parisc/include/asm/unistd.h1
-rw-r--r--arch/parisc/kernel/entry.S217
-rw-r--r--arch/parisc/kernel/process.c96
-rw-r--r--arch/parisc/kernel/sys_parisc32.c22
-rw-r--r--arch/parisc/kernel/syscall_table.S2
-rw-r--r--arch/s390/Kconfig1
-rw-r--r--arch/s390/include/asm/unistd.h1
-rw-r--r--arch/s390/kernel/entry.S32
-rw-r--r--arch/s390/kernel/entry64.S26
-rw-r--r--arch/tile/Kconfig2
-rw-r--r--arch/tile/include/asm/compat.h15
-rw-r--r--arch/tile/include/asm/elf.h1
-rw-r--r--arch/tile/include/asm/processor.h4
-rw-r--r--arch/tile/include/asm/switch_to.h5
-rw-r--r--arch/tile/include/asm/syscalls.h20
-rw-r--r--arch/tile/include/asm/unistd.h1
-rw-r--r--arch/tile/kernel/compat.c5
-rw-r--r--arch/tile/kernel/compat_signal.c10
-rw-r--r--arch/tile/kernel/entry.S11
-rw-r--r--arch/tile/kernel/intvec_32.S29
-rw-r--r--arch/tile/kernel/intvec_64.S30
-rw-r--r--arch/tile/kernel/process.c170
-rw-r--r--arch/tile/kernel/signal.c9
-rw-r--r--arch/tile/kernel/sys.c9
-rw-r--r--arch/tile/mm/fault.c5
-rw-r--r--arch/x86/kvm/x86.c60
-rw-r--r--arch/xtensa/Kconfig2
-rw-r--r--arch/xtensa/include/asm/io.h4
-rw-r--r--arch/xtensa/include/asm/processor.h4
-rw-r--r--arch/xtensa/include/asm/syscall.h2
-rw-r--r--arch/xtensa/include/asm/unistd.h15
-rw-r--r--arch/xtensa/include/uapi/asm/unistd.h16
-rw-r--r--arch/xtensa/kernel/entry.S57
-rw-r--r--arch/xtensa/kernel/process.c128
-rw-r--r--arch/xtensa/kernel/syscall.c7
-rw-r--r--arch/xtensa/kernel/xtensa_ksyms.c1
-rw-r--r--block/Kconfig2
-rw-r--r--block/blk-cgroup.c10
-rw-r--r--block/blk-core.c3
-rw-r--r--drivers/acpi/glue.c1
-rw-r--r--drivers/acpi/processor_driver.c1
-rw-r--r--drivers/base/power/domain.c5
-rw-r--r--drivers/bcma/main.c5
-rw-r--r--drivers/block/Kconfig15
-rw-r--r--drivers/block/cciss.c1
-rw-r--r--drivers/block/floppy.c90
-rw-r--r--drivers/block/loop.c17
-rw-r--r--drivers/block/mtip32xx/mtip32xx.c19
-rw-r--r--drivers/block/mtip32xx/mtip32xx.h3
-rw-r--r--drivers/block/xen-blkback/common.h4
-rw-r--r--drivers/block/xen-blkback/xenbus.c9
-rw-r--r--drivers/cpufreq/cpufreq_stats.c1
-rw-r--r--drivers/cpufreq/powernow-k8.c9
-rw-r--r--drivers/dma/imx-dma.c4
-rw-r--r--drivers/dma/sirf-dma.c4
-rw-r--r--drivers/gpio/gpio-74x164.c2
-rw-r--r--drivers/gpio/gpio-mvebu.c4
-rw-r--r--drivers/gpio/gpio-omap.c35
-rw-r--r--drivers/gpio/gpio-timberdale.c4
-rw-r--r--drivers/gpio/gpiolib.c10
-rw-r--r--drivers/gpu/drm/nouveau/core/core/mm.c9
-rw-r--r--drivers/gpu/drm/nouveau/core/include/core/mm.h1
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/fb/nv50.c10
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/i2c/base.c2
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_display.c36
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_drm.c36
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_drm.h2
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_irq.c16
-rw-r--r--drivers/gpu/drm/nouveau/nv04_dac.c16
-rw-r--r--drivers/gpu/drm/nouveau/nv04_dfp.c14
-rw-r--r--drivers/gpu/drm/nouveau/nv04_tv.c9
-rw-r--r--drivers/hid/hid-apple.c6
-rw-r--r--drivers/hid/hid-core.c6
-rw-r--r--drivers/hid/hid-ids.h3
-rw-r--r--drivers/hid/hid-microsoft.c18
-rw-r--r--drivers/hid/hid-multitouch.c5
-rw-r--r--drivers/i2c/Makefile1
-rw-r--r--drivers/i2c/busses/Kconfig1
-rw-r--r--drivers/i2c/busses/Makefile1
-rw-r--r--drivers/i2c/busses/i2c-i801.c11
-rw-r--r--drivers/i2c/i2c-stub.c (renamed from drivers/i2c/busses/i2c-stub.c)66
-rw-r--r--drivers/infiniband/hw/cxgb4/mem.c2
-rw-r--r--drivers/infiniband/hw/mlx4/alias_GUID.c2
-rw-r--r--drivers/infiniband/hw/mlx4/mad.c85
-rw-r--r--drivers/infiniband/hw/mlx4/mcg.c18
-rw-r--r--drivers/input/mouse/bcm5974.c21
-rw-r--r--drivers/isdn/gigaset/bas-gigaset.c19
-rw-r--r--drivers/md/faulty.c5
-rw-r--r--drivers/md/raid1.c2
-rw-r--r--drivers/md/raid10.c15
-rw-r--r--drivers/net/can/flexcan.c19
-rw-r--r--drivers/net/can/sja1000/peak_pci.c13
-rw-r--r--drivers/net/ethernet/chelsio/cxgb4/cxgb4.h19
-rw-r--r--drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c29
-rw-r--r--drivers/net/ethernet/chelsio/cxgb4/cxgb4_uld.h3
-rw-r--r--drivers/net/ethernet/freescale/gianfar_ptp.c2
-rw-r--r--drivers/net/ethernet/mellanox/mlx4/en_tx.c3
-rw-r--r--drivers/net/ethernet/mellanox/mlx4/eq.c24
-rw-r--r--drivers/net/ethernet/mellanox/mlx4/main.c5
-rw-r--r--drivers/net/ethernet/mellanox/mlx4/resource_tracker.c6
-rw-r--r--drivers/net/ethernet/oki-semi/pch_gbe/pch_gbe_main.c116
-rw-r--r--drivers/net/ethernet/qlogic/qla3xxx.c9
-rw-r--r--drivers/net/ethernet/ti/Kconfig2
-rw-r--r--drivers/net/ethernet/tile/tilegx.c35
-rw-r--r--drivers/net/phy/Kconfig5
-rw-r--r--drivers/net/phy/Makefile1
-rw-r--r--drivers/net/phy/at803x.c176
-rw-r--r--drivers/net/usb/cdc_ether.c41
-rw-r--r--drivers/net/usb/ipheth.c5
-rw-r--r--drivers/net/usb/qmi_wwan.c55
-rw-r--r--drivers/net/usb/usbnet.c3
-rw-r--r--drivers/net/wireless/ath/ath9k/ar9003_2p2_initvals.h164
-rw-r--r--drivers/net/wireless/ath/ath9k/hif_usb.c1
-rw-r--r--drivers/net/wireless/b43/main.c4
-rw-r--r--drivers/net/wireless/brcm80211/brcmfmac/usb.c2
-rw-r--r--drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c70
-rw-r--r--drivers/net/wireless/ipw2x00/ipw2200.c2
-rw-r--r--drivers/net/wireless/iwlwifi/dvm/devices.c39
-rw-r--r--drivers/net/wireless/mwifiex/cfg80211.c7
-rw-r--r--drivers/net/wireless/mwifiex/scan.c13
-rw-r--r--drivers/net/wireless/rt2x00/rt2500usb.c1
-rw-r--r--drivers/net/wireless/rt2x00/rt2800usb.c1
-rw-r--r--drivers/net/wireless/rt2x00/rt73usb.c1
-rw-r--r--drivers/net/wireless/rtlwifi/usb.c2
-rw-r--r--drivers/scsi/qla2xxx/qla_mid.c3
-rw-r--r--drivers/scsi/qla2xxx/qla_target.c25
-rw-r--r--drivers/scsi/qla2xxx/qla_target.h1
-rw-r--r--drivers/scsi/qla2xxx/tcm_qla2xxx.c77
-rw-r--r--drivers/scsi/qla2xxx/tcm_qla2xxx.h2
-rw-r--r--drivers/spi/spi-mxs.c3
-rw-r--r--drivers/target/target_core_sbc.c18
-rw-r--r--drivers/target/target_core_transport.c1
-rw-r--r--drivers/vhost/net.c3
-rw-r--r--fs/bio.c6
-rw-r--r--fs/block_dev.c37
-rw-r--r--fs/ceph/export.c2
-rw-r--r--fs/exec.c3
-rw-r--r--fs/ext4/ialloc.c19
-rw-r--r--fs/file.c4
-rw-r--r--include/linux/compat.h2
-rw-r--r--include/linux/kvm_host.h15
-rw-r--r--include/linux/percpu-rwsem.h28
-rw-r--r--include/linux/raid/Kbuild2
-rw-r--r--include/linux/raid/md_u.h141
-rw-r--r--include/linux/tcp.h3
-rw-r--r--include/net/cfg80211.h1
-rw-r--r--include/sound/core.h3
-rw-r--r--include/uapi/linux/raid/Kbuild2
-rw-r--r--include/uapi/linux/raid/md_p.h (renamed from include/linux/raid/md_p.h)0
-rw-r--r--include/uapi/linux/raid/md_u.h155
-rw-r--r--include/uapi/linux/tcp.h1
-rw-r--r--init/main.c2
-rw-r--r--net/8021q/vlan.c4
-rw-r--r--net/batman-adv/bridge_loop_avoidance.c27
-rw-r--r--net/batman-adv/routing.c8
-rw-r--r--net/batman-adv/types.h2
-rw-r--r--net/bluetooth/smp.c6
-rw-r--r--net/ceph/messenger.c6
-rw-r--r--net/core/skbuff.c6
-rw-r--r--net/ipv4/route.c9
-rw-r--r--net/ipv4/tcp.c10
-rw-r--r--net/ipv4/tcp_input.c13
-rw-r--r--net/ipv4/tcp_ipv4.c1
-rw-r--r--net/ipv4/tcp_minisocks.c1
-rw-r--r--net/ipv4/tcp_timer.c4
-rw-r--r--net/ipv6/route.c4
-rw-r--r--net/mac80211/iface.c2
-rw-r--r--net/mac80211/mlme.c35
-rw-r--r--net/mac80211/sta_info.c4
-rw-r--r--net/mac80211/util.c4
-rw-r--r--net/mac80211/wpa.c14
-rw-r--r--net/netfilter/ipvs/ip_vs_ctl.c3
-rw-r--r--net/netfilter/xt_CT.c10
-rw-r--r--net/netfilter/xt_TEE.c1
-rw-r--r--net/netfilter/xt_nat.c8
-rw-r--r--net/netlink/af_netlink.c19
-rw-r--r--net/wireless/mlme.c12
-rw-r--r--sound/core/compress_offload.c9
-rw-r--r--sound/core/control.c5
-rw-r--r--sound/core/hwdep.c12
-rw-r--r--sound/core/init.c50
-rw-r--r--sound/core/oss/mixer_oss.c10
-rw-r--r--sound/core/oss/pcm_oss.c6
-rw-r--r--sound/core/pcm.c13
-rw-r--r--sound/core/pcm_native.c33
-rw-r--r--sound/core/rawmidi.c26
-rw-r--r--sound/core/sound.c11
-rw-r--r--sound/core/sound_oss.c10
-rw-r--r--sound/pci/hda/patch_sigmatel.c2
-rw-r--r--sound/pci/ice1712/ice1724.c7
-rw-r--r--sound/soc/omap/omap-dmic.c4
-rw-r--r--sound/soc/omap/zoom2.c5
-rw-r--r--sound/usb/card.c12
-rw-r--r--sound/usb/card.h1
-rw-r--r--sound/usb/mixer.c65
-rw-r--r--sound/usb/mixer_quirks.c58
-rw-r--r--sound/usb/pcm.c53
-rw-r--r--sound/usb/proc.c4
-rw-r--r--sound/usb/stream.c1
-rw-r--r--sound/usb/usbaudio.h2
-rwxr-xr-xtools/testing/ktest/ktest.pl6
310 files changed, 2627 insertions, 2489 deletions
diff --git a/Documentation/devicetree/bindings/arm/atmel-at91.txt b/Documentation/devicetree/bindings/arm/atmel-at91.txt
index ecc81e368715..d187e9f7cf1c 100644
--- a/Documentation/devicetree/bindings/arm/atmel-at91.txt
+++ b/Documentation/devicetree/bindings/arm/atmel-at91.txt
@@ -8,7 +8,7 @@ PIT Timer required properties:
shared across all System Controller members.
TC/TCLIB Timer required properties:
-- compatible: Should be "atmel,<chip>-pit".
+- compatible: Should be "atmel,<chip>-tcb".
<chip> can be "at91rm9200" or "at91sam9x5"
- reg: Should contain registers location and length
- interrupts: Should contain all interrupts for the TC block
diff --git a/MAINTAINERS b/MAINTAINERS
index f39a82dc0260..cb7d1a42f2cd 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -637,6 +637,13 @@ W: http://www.arm.linux.org.uk/
S: Maintained
F: arch/arm/
+ARM SUB-ARCHITECTURES
+L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
+S: MAINTAINED
+F: arch/arm/mach-*/
+F: arch/arm/plat-*/
+T: git git://git.kernel.org/pub/scm/linux/kernel/git/arm/arm-soc.git
+
ARM PRIMECELL AACI PL041 DRIVER
M: Russell King <linux@arm.linux.org.uk>
S: Maintained
@@ -5062,7 +5069,13 @@ T: git git://git.kernel.org/pub/scm/linux/kernel/git/davem/net-next.git
S: Odd Fixes
F: drivers/net/
F: include/linux/if_*
-F: include/linux/*device.h
+F: include/linux/netdevice.h
+F: include/linux/arcdevice.h
+F: include/linux/etherdevice.h
+F: include/linux/fcdevice.h
+F: include/linux/fddidevice.h
+F: include/linux/hippidevice.h
+F: include/linux/inetdevice.h
NETXEN (1/10) GbE SUPPORT
M: Sony Chacko <sony.chacko@qlogic.com>
@@ -5634,7 +5647,7 @@ S: Maintained
F: drivers/pinctrl/spear/
PKTCDVD DRIVER
-M: Peter Osterlund <petero2@telia.com>
+M: Jiri Kosina <jkosina@suse.cz>
S: Maintained
F: drivers/block/pktcdvd.c
F: include/linux/pktcdvd.h
diff --git a/Makefile b/Makefile
index 14c93b39b929..42d0e56818ea 100644
--- a/Makefile
+++ b/Makefile
@@ -1,7 +1,7 @@
VERSION = 3
PATCHLEVEL = 7
SUBLEVEL = 0
-EXTRAVERSION = -rc2
+EXTRAVERSION = -rc3
NAME = Terrified Chipmunk
# *DOCUMENTATION*
diff --git a/arch/arm/boot/dts/at91sam9g20ek_common.dtsi b/arch/arm/boot/dts/at91sam9g20ek_common.dtsi
index b06c0db273b1..e6391a4e6649 100644
--- a/arch/arm/boot/dts/at91sam9g20ek_common.dtsi
+++ b/arch/arm/boot/dts/at91sam9g20ek_common.dtsi
@@ -126,14 +126,14 @@
#size-cells = <0>;
btn3 {
- label = "Buttin 3";
+ label = "Button 3";
gpios = <&pioA 30 1>;
linux,code = <0x103>;
gpio-key,wakeup;
};
btn4 {
- label = "Buttin 4";
+ label = "Button 4";
gpios = <&pioA 31 1>;
linux,code = <0x104>;
gpio-key,wakeup;
diff --git a/arch/arm/boot/dts/dbx5x0.dtsi b/arch/arm/boot/dts/dbx5x0.dtsi
index 748ba7aa746c..4b0e0ca08f40 100644
--- a/arch/arm/boot/dts/dbx5x0.dtsi
+++ b/arch/arm/boot/dts/dbx5x0.dtsi
@@ -483,6 +483,8 @@
compatible = "stericsson,db8500-i2c", "st,nomadik-i2c", "arm,primecell";
reg = <0x80004000 0x1000>;
interrupts = <0 21 0x4>;
+ arm,primecell-periphid = <0x180024>;
+
#address-cells = <1>;
#size-cells = <0>;
v-i2c-supply = <&db8500_vape_reg>;
@@ -494,6 +496,8 @@
compatible = "stericsson,db8500-i2c", "st,nomadik-i2c", "arm,primecell";
reg = <0x80122000 0x1000>;
interrupts = <0 22 0x4>;
+ arm,primecell-periphid = <0x180024>;
+
#address-cells = <1>;
#size-cells = <0>;
v-i2c-supply = <&db8500_vape_reg>;
@@ -505,6 +509,8 @@
compatible = "stericsson,db8500-i2c", "st,nomadik-i2c", "arm,primecell";
reg = <0x80128000 0x1000>;
interrupts = <0 55 0x4>;
+ arm,primecell-periphid = <0x180024>;
+
#address-cells = <1>;
#size-cells = <0>;
v-i2c-supply = <&db8500_vape_reg>;
@@ -516,6 +522,8 @@
compatible = "stericsson,db8500-i2c", "st,nomadik-i2c", "arm,primecell";
reg = <0x80110000 0x1000>;
interrupts = <0 12 0x4>;
+ arm,primecell-periphid = <0x180024>;
+
#address-cells = <1>;
#size-cells = <0>;
v-i2c-supply = <&db8500_vape_reg>;
@@ -527,6 +535,8 @@
compatible = "stericsson,db8500-i2c", "st,nomadik-i2c", "arm,primecell";
reg = <0x8012a000 0x1000>;
interrupts = <0 51 0x4>;
+ arm,primecell-periphid = <0x180024>;
+
#address-cells = <1>;
#size-cells = <0>;
v-i2c-supply = <&db8500_vape_reg>;
@@ -573,33 +583,38 @@
interrupts = <0 60 0x4>;
status = "disabled";
};
+
sdi@80118000 {
compatible = "arm,pl18x", "arm,primecell";
reg = <0x80118000 0x1000>;
interrupts = <0 50 0x4>;
status = "disabled";
};
+
sdi@80005000 {
compatible = "arm,pl18x", "arm,primecell";
reg = <0x80005000 0x1000>;
interrupts = <0 41 0x4>;
status = "disabled";
};
+
sdi@80119000 {
compatible = "arm,pl18x", "arm,primecell";
reg = <0x80119000 0x1000>;
interrupts = <0 59 0x4>;
status = "disabled";
};
+
sdi@80114000 {
compatible = "arm,pl18x", "arm,primecell";
reg = <0x80114000 0x1000>;
interrupts = <0 99 0x4>;
status = "disabled";
};
+
sdi@80008000 {
compatible = "arm,pl18x", "arm,primecell";
- reg = <0x80114000 0x1000>;
+ reg = <0x80008000 0x1000>;
interrupts = <0 100 0x4>;
status = "disabled";
};
diff --git a/arch/arm/boot/dts/exynos4210-trats.dts b/arch/arm/boot/dts/exynos4210-trats.dts
index 73567b843e72..a21511c14071 100644
--- a/arch/arm/boot/dts/exynos4210-trats.dts
+++ b/arch/arm/boot/dts/exynos4210-trats.dts
@@ -20,8 +20,10 @@
compatible = "samsung,trats", "samsung,exynos4210";
memory {
- reg = <0x40000000 0x20000000
- 0x60000000 0x20000000>;
+ reg = <0x40000000 0x10000000
+ 0x50000000 0x10000000
+ 0x60000000 0x10000000
+ 0x70000000 0x10000000>;
};
chosen {
diff --git a/arch/arm/boot/dts/imx23.dtsi b/arch/arm/boot/dts/imx23.dtsi
index 9ca4ca70c1bc..6d31aa383460 100644
--- a/arch/arm/boot/dts/imx23.dtsi
+++ b/arch/arm/boot/dts/imx23.dtsi
@@ -69,6 +69,7 @@
interrupts = <13>, <56>;
interrupt-names = "gpmi-dma", "bch";
clocks = <&clks 34>;
+ clock-names = "gpmi_io";
fsl,gpmi-dma-channel = <4>;
status = "disabled";
};
diff --git a/arch/arm/boot/dts/imx28.dtsi b/arch/arm/boot/dts/imx28.dtsi
index e16d63155480..55c57ea6169e 100644
--- a/arch/arm/boot/dts/imx28.dtsi
+++ b/arch/arm/boot/dts/imx28.dtsi
@@ -85,6 +85,7 @@
interrupts = <88>, <41>;
interrupt-names = "gpmi-dma", "bch";
clocks = <&clks 50>;
+ clock-names = "gpmi_io";
fsl,gpmi-dma-channel = <4>;
status = "disabled";
};
diff --git a/arch/arm/boot/dts/omap3.dtsi b/arch/arm/boot/dts/omap3.dtsi
index f38ea8771b44..696e929d0304 100644
--- a/arch/arm/boot/dts/omap3.dtsi
+++ b/arch/arm/boot/dts/omap3.dtsi
@@ -257,7 +257,7 @@
interrupt-names = "common", "tx", "rx", "sidetone";
interrupt-parent = <&intc>;
ti,buffer-size = <1280>;
- ti,hwmods = "mcbsp2";
+ ti,hwmods = "mcbsp2", "mcbsp2_sidetone";
};
mcbsp3: mcbsp@49024000 {
@@ -272,7 +272,7 @@
interrupt-names = "common", "tx", "rx", "sidetone";
interrupt-parent = <&intc>;
ti,buffer-size = <128>;
- ti,hwmods = "mcbsp3";
+ ti,hwmods = "mcbsp3", "mcbsp3_sidetone";
};
mcbsp4: mcbsp@49026000 {
diff --git a/arch/arm/configs/imx_v6_v7_defconfig b/arch/arm/configs/imx_v6_v7_defconfig
index 66aa7a6db884..394ded624e37 100644
--- a/arch/arm/configs/imx_v6_v7_defconfig
+++ b/arch/arm/configs/imx_v6_v7_defconfig
@@ -139,6 +139,7 @@ CONFIG_I2C_IMX=y
CONFIG_SPI=y
CONFIG_SPI_IMX=y
CONFIG_GPIO_SYSFS=y
+CONFIG_GPIO_MC9S08DZ60=y
# CONFIG_HWMON is not set
CONFIG_WATCHDOG=y
CONFIG_IMX2_WDT=y
@@ -155,6 +156,7 @@ CONFIG_SOC_CAMERA=y
CONFIG_SOC_CAMERA_OV2640=y
CONFIG_VIDEO_MX3=y
CONFIG_FB=y
+CONFIG_LCD_PLATFORM=y
CONFIG_BACKLIGHT_LCD_SUPPORT=y
CONFIG_LCD_CLASS_DEVICE=y
CONFIG_LCD_L4F00242T03=y
diff --git a/arch/arm/configs/mvebu_defconfig b/arch/arm/configs/mvebu_defconfig
index 7bcf850eddcd..3458752c4bb2 100644
--- a/arch/arm/configs/mvebu_defconfig
+++ b/arch/arm/configs/mvebu_defconfig
@@ -1,6 +1,6 @@
CONFIG_EXPERIMENTAL=y
CONFIG_SYSVIPC=y
-CONFIG_NO_HZ=y
+CONFIG_IRQ_DOMAIN_DEBUG=y
CONFIG_HIGH_RES_TIMERS=y
CONFIG_LOG_BUF_SHIFT=14
CONFIG_BLK_DEV_INITRD=y
@@ -9,10 +9,12 @@ CONFIG_SLAB=y
CONFIG_MODULES=y
CONFIG_MODULE_UNLOAD=y
CONFIG_ARCH_MVEBU=y
-CONFIG_MACH_ARMADA_370_XP=y
+CONFIG_MACH_ARMADA_370=y
+CONFIG_MACH_ARMADA_XP=y
+# CONFIG_CACHE_L2X0 is not set
CONFIG_AEABI=y
CONFIG_HIGHMEM=y
-CONFIG_USE_OF=y
+# CONFIG_COMPACTION is not set
CONFIG_ZBOOT_ROM_TEXT=0x0
CONFIG_ZBOOT_ROM_BSS=0x0
CONFIG_ARM_APPENDED_DTB=y
@@ -23,6 +25,8 @@ CONFIG_SERIAL_8250_CONSOLE=y
CONFIG_SERIAL_OF_PLATFORM=y
CONFIG_GPIOLIB=y
CONFIG_GPIO_SYSFS=y
+# CONFIG_USB_SUPPORT is not set
+# CONFIG_IOMMU_SUPPORT is not set
CONFIG_EXT2_FS=y
CONFIG_EXT3_FS=y
# CONFIG_EXT3_FS_XATTR is not set
diff --git a/arch/arm/configs/versatile_defconfig b/arch/arm/configs/versatile_defconfig
index cdd4d2bd3962..2ba9e63d0f17 100644
--- a/arch/arm/configs/versatile_defconfig
+++ b/arch/arm/configs/versatile_defconfig
@@ -1,3 +1,4 @@
+CONFIG_ARCH_VERSATILE=y
CONFIG_EXPERIMENTAL=y
# CONFIG_LOCALVERSION_AUTO is not set
CONFIG_SYSVIPC=y
diff --git a/arch/arm/include/debug/8250_32.S b/arch/arm/include/debug/8250_32.S
new file mode 100644
index 000000000000..8db01eeabbb4
--- /dev/null
+++ b/arch/arm/include/debug/8250_32.S
@@ -0,0 +1,27 @@
+/*
+ * Copyright (c) 2011 Picochip Ltd., Jamie Iles
+ *
+ * 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.
+ *
+ * Derived from arch/arm/mach-davinci/include/mach/debug-macro.S to use 32-bit
+ * accesses to the 8250.
+ */
+
+#include <linux/serial_reg.h>
+
+ .macro senduart,rd,rx
+ str \rd, [\rx, #UART_TX << UART_SHIFT]
+ .endm
+
+ .macro busyuart,rd,rx
+1002: ldr \rd, [\rx, #UART_LSR << UART_SHIFT]
+ and \rd, \rd, #UART_LSR_TEMT | UART_LSR_THRE
+ teq \rd, #UART_LSR_TEMT | UART_LSR_THRE
+ bne 1002b
+ .endm
+
+ /* The UART's don't have any flow control IO's wired up. */
+ .macro waituart,rd,rx
+ .endm
diff --git a/arch/arm/include/debug/picoxcell.S b/arch/arm/include/debug/picoxcell.S
index 7419deb1b948..bc1f07c49cd4 100644
--- a/arch/arm/include/debug/picoxcell.S
+++ b/arch/arm/include/debug/picoxcell.S
@@ -5,10 +5,7 @@
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
- * Derived from arch/arm/mach-davinci/include/mach/debug-macro.S to use 32-bit
- * accesses to the 8250.
*/
-#include <linux/serial_reg.h>
#define UART_SHIFT 2
#define PICOXCELL_UART1_BASE 0x80230000
@@ -19,17 +16,4 @@
ldr \rp, =PICOXCELL_UART1_BASE
.endm
- .macro senduart,rd,rx
- str \rd, [\rx, #UART_TX << UART_SHIFT]
- .endm
-
- .macro busyuart,rd,rx
-1002: ldr \rd, [\rx, #UART_LSR << UART_SHIFT]
- and \rd, \rd, #UART_LSR_TEMT | UART_LSR_THRE
- teq \rd, #UART_LSR_TEMT | UART_LSR_THRE
- bne 1002b
- .endm
-
- /* The UART's don't have any flow control IO's wired up. */
- .macro waituart,rd,rx
- .endm
+#include "8250_32.S"
diff --git a/arch/arm/include/debug/socfpga.S b/arch/arm/include/debug/socfpga.S
index d6f26d23374f..966b2f994946 100644
--- a/arch/arm/include/debug/socfpga.S
+++ b/arch/arm/include/debug/socfpga.S
@@ -7,6 +7,9 @@
* published by the Free Software Foundation.
*/
+#define UART_SHIFT 2
+#define DEBUG_LL_UART_OFFSET 0x00002000
+
.macro addruart, rp, rv, tmp
mov \rp, #DEBUG_LL_UART_OFFSET
orr \rp, \rp, #0x00c00000
@@ -14,3 +17,5 @@
orr \rp, \rp, #0xff000000 @ physical base
.endm
+#include "8250_32.S"
+
diff --git a/arch/arm/mach-at91/Kconfig b/arch/arm/mach-at91/Kconfig
index b14207101938..043624219b55 100644
--- a/arch/arm/mach-at91/Kconfig
+++ b/arch/arm/mach-at91/Kconfig
@@ -21,19 +21,13 @@ config SOC_AT91SAM9
bool
select CPU_ARM926T
select GENERIC_CLOCKEVENTS
+ select MULTI_IRQ_HANDLER
+ select SPARSE_IRQ
menu "Atmel AT91 System-on-Chip"
comment "Atmel AT91 Processor"
-config SOC_AT91SAM9
- bool
- select AT91_SAM9_SMC
- select AT91_SAM9_TIME
- select CPU_ARM926T
- select MULTI_IRQ_HANDLER
- select SPARSE_IRQ
-
config SOC_AT91RM9200
bool "AT91RM9200"
select CPU_ARM920T
diff --git a/arch/arm/mach-at91/at91rm9200.c b/arch/arm/mach-at91/at91rm9200.c
index b4f0565aff63..5269825194a8 100644
--- a/arch/arm/mach-at91/at91rm9200.c
+++ b/arch/arm/mach-at91/at91rm9200.c
@@ -187,7 +187,7 @@ static struct clk_lookup periph_clocks_lookups[] = {
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),
- CLKDEV_CON_DEV_ID(NULL, "i2c-at91rm9200", &twi_clk),
+ CLKDEV_CON_DEV_ID(NULL, "i2c-at91rm9200.0", &twi_clk),
/* fake hclk clock */
CLKDEV_CON_DEV_ID("hclk", "at91_ohci", &ohci_clk),
CLKDEV_CON_ID("pioA", &pioA_clk),
diff --git a/arch/arm/mach-at91/at91rm9200_devices.c b/arch/arm/mach-at91/at91rm9200_devices.c
index a563189cdfc3..1e122bcd7845 100644
--- a/arch/arm/mach-at91/at91rm9200_devices.c
+++ b/arch/arm/mach-at91/at91rm9200_devices.c
@@ -479,7 +479,7 @@ static struct i2c_gpio_platform_data pdata = {
static struct platform_device at91rm9200_twi_device = {
.name = "i2c-gpio",
- .id = -1,
+ .id = 0,
.dev.platform_data = &pdata,
};
@@ -512,7 +512,7 @@ static struct resource twi_resources[] = {
static struct platform_device at91rm9200_twi_device = {
.name = "i2c-at91rm9200",
- .id = -1,
+ .id = 0,
.resource = twi_resources,
.num_resources = ARRAY_SIZE(twi_resources),
};
diff --git a/arch/arm/mach-at91/at91sam9260.c b/arch/arm/mach-at91/at91sam9260.c
index ad29f93f20ca..f8202615f4a8 100644
--- a/arch/arm/mach-at91/at91sam9260.c
+++ b/arch/arm/mach-at91/at91sam9260.c
@@ -211,8 +211,8 @@ static struct clk_lookup periph_clocks_lookups[] = {
CLKDEV_CON_DEV_ID("t1_clk", "atmel_tcb.1", &tc4_clk),
CLKDEV_CON_DEV_ID("t2_clk", "atmel_tcb.1", &tc5_clk),
CLKDEV_CON_DEV_ID("pclk", "ssc.0", &ssc_clk),
- CLKDEV_CON_DEV_ID(NULL, "i2c-at91sam9260", &twi_clk),
- CLKDEV_CON_DEV_ID(NULL, "i2c-at91sam9g20", &twi_clk),
+ CLKDEV_CON_DEV_ID(NULL, "i2c-at91sam9260.0", &twi_clk),
+ CLKDEV_CON_DEV_ID(NULL, "i2c-at91sam9g20.0", &twi_clk),
/* more usart lookup table for DT entries */
CLKDEV_CON_DEV_ID("usart", "fffff200.serial", &mck),
CLKDEV_CON_DEV_ID("usart", "fffb0000.serial", &usart0_clk),
diff --git a/arch/arm/mach-at91/at91sam9260_devices.c b/arch/arm/mach-at91/at91sam9260_devices.c
index a76b8684f52d..aa1e58729885 100644
--- a/arch/arm/mach-at91/at91sam9260_devices.c
+++ b/arch/arm/mach-at91/at91sam9260_devices.c
@@ -389,7 +389,7 @@ static struct i2c_gpio_platform_data pdata = {
static struct platform_device at91sam9260_twi_device = {
.name = "i2c-gpio",
- .id = -1,
+ .id = 0,
.dev.platform_data = &pdata,
};
@@ -421,7 +421,7 @@ static struct resource twi_resources[] = {
};
static struct platform_device at91sam9260_twi_device = {
- .id = -1,
+ .id = 0,
.resource = twi_resources,
.num_resources = ARRAY_SIZE(twi_resources),
};
diff --git a/arch/arm/mach-at91/at91sam9261.c b/arch/arm/mach-at91/at91sam9261.c
index 8d999eb1a137..04295c04b3e0 100644
--- a/arch/arm/mach-at91/at91sam9261.c
+++ b/arch/arm/mach-at91/at91sam9261.c
@@ -178,8 +178,8 @@ static struct clk_lookup periph_clocks_lookups[] = {
CLKDEV_CON_DEV_ID("pclk", "ssc.1", &ssc1_clk),
CLKDEV_CON_DEV_ID("pclk", "ssc.2", &ssc2_clk),
CLKDEV_CON_DEV_ID("hclk", "at91_ohci", &hck0),
- CLKDEV_CON_DEV_ID(NULL, "i2c-at91sam9261", &twi_clk),
- CLKDEV_CON_DEV_ID(NULL, "i2c-at91sam9g10", &twi_clk),
+ CLKDEV_CON_DEV_ID(NULL, "i2c-at91sam9261.0", &twi_clk),
+ CLKDEV_CON_DEV_ID(NULL, "i2c-at91sam9g10.0", &twi_clk),
CLKDEV_CON_ID("pioA", &pioA_clk),
CLKDEV_CON_ID("pioB", &pioB_clk),
CLKDEV_CON_ID("pioC", &pioC_clk),
diff --git a/arch/arm/mach-at91/at91sam9261_devices.c b/arch/arm/mach-at91/at91sam9261_devices.c
index 9752f17efba9..b9487696b7be 100644
--- a/arch/arm/mach-at91/at91sam9261_devices.c
+++ b/arch/arm/mach-at91/at91sam9261_devices.c
@@ -285,7 +285,7 @@ static struct i2c_gpio_platform_data pdata = {
static struct platform_device at91sam9261_twi_device = {
.name = "i2c-gpio",
- .id = -1,
+ .id = 0,
.dev.platform_data = &pdata,
};
@@ -317,7 +317,7 @@ static struct resource twi_resources[] = {
};
static struct platform_device at91sam9261_twi_device = {
- .id = -1,
+ .id = 0,
.resource = twi_resources,
.num_resources = ARRAY_SIZE(twi_resources),
};
diff --git a/arch/arm/mach-at91/at91sam9263.c b/arch/arm/mach-at91/at91sam9263.c
index 6a01d0360dfb..d6f9c23927c4 100644
--- a/arch/arm/mach-at91/at91sam9263.c
+++ b/arch/arm/mach-at91/at91sam9263.c
@@ -193,7 +193,7 @@ static struct clk_lookup periph_clocks_lookups[] = {
CLKDEV_CON_DEV_ID("spi_clk", "atmel_spi.0", &spi0_clk),
CLKDEV_CON_DEV_ID("spi_clk", "atmel_spi.1", &spi1_clk),
CLKDEV_CON_DEV_ID("t0_clk", "atmel_tcb.0", &tcb_clk),
- CLKDEV_CON_DEV_ID(NULL, "i2c-at91sam9260", &twi_clk),
+ CLKDEV_CON_DEV_ID(NULL, "i2c-at91sam9260.0", &twi_clk),
/* fake hclk clock */
CLKDEV_CON_DEV_ID("hclk", "at91_ohci", &ohci_clk),
CLKDEV_CON_ID("pioA", &pioA_clk),
diff --git a/arch/arm/mach-at91/at91sam9263_devices.c b/arch/arm/mach-at91/at91sam9263_devices.c
index 8dde220b42b6..cb85da2eccea 100644
--- a/arch/arm/mach-at91/at91sam9263_devices.c
+++ b/arch/arm/mach-at91/at91sam9263_devices.c
@@ -567,7 +567,7 @@ static struct i2c_gpio_platform_data pdata = {
static struct platform_device at91sam9263_twi_device = {
.name = "i2c-gpio",
- .id = -1,
+ .id = 0,
.dev.platform_data = &pdata,
};
@@ -600,7 +600,7 @@ static struct resource twi_resources[] = {
static struct platform_device at91sam9263_twi_device = {
.name = "i2c-at91sam9260",
- .id = -1,
+ .id = 0,
.resource = twi_resources,
.num_resources = ARRAY_SIZE(twi_resources),
};
diff --git a/arch/arm/mach-at91/at91sam9rl_devices.c b/arch/arm/mach-at91/at91sam9rl_devices.c
index d6ca0543ce8d..5047bdc92adf 100644
--- a/arch/arm/mach-at91/at91sam9rl_devices.c
+++ b/arch/arm/mach-at91/at91sam9rl_devices.c
@@ -314,7 +314,7 @@ static struct i2c_gpio_platform_data pdata = {
static struct platform_device at91sam9rl_twi_device = {
.name = "i2c-gpio",
- .id = -1,
+ .id = 0,
.dev.platform_data = &pdata,
};
@@ -347,7 +347,7 @@ static struct resource twi_resources[] = {
static struct platform_device at91sam9rl_twi_device = {
.name = "i2c-at91sam9g20",
- .id = -1,
+ .id = 0,
.resource = twi_resources,
.num_resources = ARRAY_SIZE(twi_resources),
};
diff --git a/arch/arm/mach-at91/at91x40.c b/arch/arm/mach-at91/at91x40.c
index 6bd7300a2bc5..bb7f54474b92 100644
--- a/arch/arm/mach-at91/at91x40.c
+++ b/arch/arm/mach-at91/at91x40.c
@@ -88,6 +88,6 @@ void __init at91x40_init_interrupts(unsigned int priority[NR_AIC_IRQS])
if (!priority)
priority = at91x40_default_irq_priority;
- at91_aic_init(priority);
+ at91_aic_init(priority, at91_extern_irq);
}
diff --git a/arch/arm/mach-at91/board-neocore926.c b/arch/arm/mach-at91/board-neocore926.c
index 9cda3fd346ae..6960778af4c2 100644
--- a/arch/arm/mach-at91/board-neocore926.c
+++ b/arch/arm/mach-at91/board-neocore926.c
@@ -129,7 +129,7 @@ static struct spi_board_info neocore926_spi_devices[] = {
.max_speed_hz = 125000 * 16,
.bus_num = 0,
.platform_data = &ads_info,
- .irq = AT91SAM9263_ID_IRQ1,
+ .irq = NR_IRQS_LEGACY + AT91SAM9263_ID_IRQ1,
},
#endif
};
diff --git a/arch/arm/mach-at91/board-sam9261ek.c b/arch/arm/mach-at91/board-sam9261ek.c
index 27b3af1a3047..a9167dd45f96 100644
--- a/arch/arm/mach-at91/board-sam9261ek.c
+++ b/arch/arm/mach-at91/board-sam9261ek.c
@@ -309,7 +309,7 @@ static struct spi_board_info ek_spi_devices[] = {
.max_speed_hz = 125000 * 26, /* (max sample rate @ 3V) * (cmd + data + overhead) */
.bus_num = 0,
.platform_data = &ads_info,
- .irq = AT91SAM9261_ID_IRQ0,
+ .irq = NR_IRQS_LEGACY + AT91SAM9261_ID_IRQ0,
.controller_data = (void *) AT91_PIN_PA28, /* CS pin */
},
#endif
diff --git a/arch/arm/mach-at91/board-sam9263ek.c b/arch/arm/mach-at91/board-sam9263ek.c
index 073e17403d98..b87dbe2be0d6 100644
--- a/arch/arm/mach-at91/board-sam9263ek.c
+++ b/arch/arm/mach-at91/board-sam9263ek.c
@@ -132,7 +132,7 @@ static struct spi_board_info ek_spi_devices[] = {
.max_speed_hz = 125000 * 26, /* (max sample rate @ 3V) * (cmd + data + overhead) */
.bus_num = 0,
.platform_data = &ads_info,
- .irq = AT91SAM9263_ID_IRQ1,
+ .irq = NR_IRQS_LEGACY + AT91SAM9263_ID_IRQ1,
},
#endif
};
diff --git a/arch/arm/mach-at91/generic.h b/arch/arm/mach-at91/generic.h
index f49650677653..b62f560e6c75 100644
--- a/arch/arm/mach-at91/generic.h
+++ b/arch/arm/mach-at91/generic.h
@@ -26,7 +26,8 @@ extern void __init at91_dt_initialize(void);
extern void __init at91_init_irq_default(void);
extern void __init at91_init_interrupts(unsigned int priority[]);
extern void __init at91x40_init_interrupts(unsigned int priority[]);
-extern void __init at91_aic_init(unsigned int priority[]);
+extern void __init at91_aic_init(unsigned int priority[],
+ unsigned int ext_irq_mask);
extern int __init at91_aic_of_init(struct device_node *node,
struct device_node *parent);
extern int __init at91_aic5_of_init(struct device_node *node,
diff --git a/arch/arm/mach-at91/irq.c b/arch/arm/mach-at91/irq.c
index 1e02c0e49dcc..febc2ee901a5 100644
--- a/arch/arm/mach-at91/irq.c
+++ b/arch/arm/mach-at91/irq.c
@@ -502,14 +502,19 @@ int __init at91_aic5_of_init(struct device_node *node,
/*
* Initialize the AIC interrupt controller.
*/
-void __init at91_aic_init(unsigned int *priority)
+void __init at91_aic_init(unsigned int *priority, unsigned int ext_irq_mask)
{
unsigned int i;
int irq_base;
- if (at91_aic_pm_init())
+ at91_extern_irq = kzalloc(BITS_TO_LONGS(n_irqs)
+ * sizeof(*at91_extern_irq), GFP_KERNEL);
+
+ if (at91_aic_pm_init() || at91_extern_irq == NULL)
panic("Unable to allocate bit maps\n");
+ *at91_extern_irq = ext_irq_mask;
+
at91_aic_base = ioremap(AT91_AIC, 512);
if (!at91_aic_base)
panic("Unable to ioremap AIC registers\n");
diff --git a/arch/arm/mach-at91/setup.c b/arch/arm/mach-at91/setup.c
index da9881b161e1..0b32c81730a5 100644
--- a/arch/arm/mach-at91/setup.c
+++ b/arch/arm/mach-at91/setup.c
@@ -47,7 +47,7 @@ void __init at91_init_irq_default(void)
void __init at91_init_interrupts(unsigned int *priority)
{
/* Initialize the AIC interrupt controller */
- at91_aic_init(priority);
+ at91_aic_init(priority, at91_extern_irq);
/* Enable GPIO interrupts */
at91_gpio_irq_setup();
@@ -151,7 +151,7 @@ static void __init soc_detect(u32 dbgu_base)
}
/* at91sam9g10 */
- if ((cidr & ~AT91_CIDR_EXT) == ARCH_ID_AT91SAM9G10) {
+ if ((socid & ~AT91_CIDR_EXT) == ARCH_ID_AT91SAM9G10) {
at91_soc_initdata.type = AT91_SOC_SAM9G10;
at91_boot_soc = at91sam9261_soc;
}
diff --git a/arch/arm/mach-exynos/common.c b/arch/arm/mach-exynos/common.c
index 715b690e5009..1947be8e5f5b 100644
--- a/arch/arm/mach-exynos/common.c
+++ b/arch/arm/mach-exynos/common.c
@@ -47,6 +47,7 @@
#include <plat/fimc-core.h>
#include <plat/iic-core.h>
#include <plat/tv-core.h>
+#include <plat/spi-core.h>
#include <plat/regs-serial.h>
#include "common.h"
@@ -346,6 +347,8 @@ static void __init exynos4_map_io(void)
s5p_fb_setname(0, "exynos4-fb");
s5p_hdmi_setname("exynos4-hdmi");
+
+ s3c64xx_spi_setname("exynos4210-spi");
}
static void __init exynos5_map_io(void)
@@ -366,6 +369,8 @@ static void __init exynos5_map_io(void)
s3c_i2c0_setname("s3c2440-i2c");
s3c_i2c1_setname("s3c2440-i2c");
s3c_i2c2_setname("s3c2440-i2c");
+
+ s3c64xx_spi_setname("exynos4210-spi");
}
static void __init exynos4_init_clocks(int xtal)
diff --git a/arch/arm/mach-exynos/mach-exynos4-dt.c b/arch/arm/mach-exynos/mach-exynos4-dt.c
index e58d786faf78..eadf4b59e7d2 100644
--- a/arch/arm/mach-exynos/mach-exynos4-dt.c
+++ b/arch/arm/mach-exynos/mach-exynos4-dt.c
@@ -99,6 +99,7 @@ static char const *exynos4_dt_compat[] __initdata = {
DT_MACHINE_START(EXYNOS4210_DT, "Samsung Exynos4 (Flattened Device Tree)")
/* Maintainer: Thomas Abraham <thomas.abraham@linaro.org> */
+ .smp = smp_ops(exynos_smp_ops),
.init_irq = exynos4_init_irq,
.map_io = exynos4_dt_map_io,
.handle_irq = gic_handle_irq,
diff --git a/arch/arm/mach-imx/clk-busy.c b/arch/arm/mach-imx/clk-busy.c
index 1a7a8dd045a1..1ab91b5209e6 100644
--- a/arch/arm/mach-imx/clk-busy.c
+++ b/arch/arm/mach-imx/clk-busy.c
@@ -108,7 +108,7 @@ struct clk *imx_clk_busy_divider(const char *name, const char *parent_name,
busy->div.hw.init = &init;
clk = clk_register(NULL, &busy->div.hw);
- if (!clk)
+ if (IS_ERR(clk))
kfree(busy);
return clk;
diff --git a/arch/arm/mach-imx/clk-imx25.c b/arch/arm/mach-imx/clk-imx25.c
index d20d4795f4ea..01e2f843bf2e 100644
--- a/arch/arm/mach-imx/clk-imx25.c
+++ b/arch/arm/mach-imx/clk-imx25.c
@@ -127,8 +127,8 @@ int __init mx25_clocks_init(void)
clk[esdhc2_ipg_per] = imx_clk_gate("esdhc2_ipg_per", "per4", ccm(CCM_CGCR0), 4);
clk[gpt_ipg_per] = imx_clk_gate("gpt_ipg_per", "per5", ccm(CCM_CGCR0), 5);
clk[i2c_ipg_per] = imx_clk_gate("i2c_ipg_per", "per6", ccm(CCM_CGCR0), 6);
- clk[lcdc_ipg_per] = imx_clk_gate("lcdc_ipg_per", "per8", ccm(CCM_CGCR0), 7);
- clk[nfc_ipg_per] = imx_clk_gate("nfc_ipg_per", "ipg_per", ccm(CCM_CGCR0), 8);
+ clk[lcdc_ipg_per] = imx_clk_gate("lcdc_ipg_per", "per7", ccm(CCM_CGCR0), 7);
+ clk[nfc_ipg_per] = imx_clk_gate("nfc_ipg_per", "per8", ccm(CCM_CGCR0), 8);
clk[ssi1_ipg_per] = imx_clk_gate("ssi1_ipg_per", "per13", ccm(CCM_CGCR0), 13);
clk[ssi2_ipg_per] = imx_clk_gate("ssi2_ipg_per", "per14", ccm(CCM_CGCR0), 14);
clk[uart_ipg_per] = imx_clk_gate("uart_ipg_per", "per15", ccm(CCM_CGCR0), 15);
diff --git a/arch/arm/mach-imx/clk-imx27.c b/arch/arm/mach-imx/clk-imx27.c
index 3b6b640eed24..366e5d59d886 100644
--- a/arch/arm/mach-imx/clk-imx27.c
+++ b/arch/arm/mach-imx/clk-imx27.c
@@ -109,7 +109,7 @@ int __init mx27_clocks_init(unsigned long fref)
clk[per3_div] = imx_clk_divider("per3_div", "mpll_main2", CCM_PCDR1, 16, 6);
clk[per4_div] = imx_clk_divider("per4_div", "mpll_main2", CCM_PCDR1, 24, 6);
clk[vpu_sel] = imx_clk_mux("vpu_sel", CCM_CSCR, 21, 1, vpu_sel_clks, ARRAY_SIZE(vpu_sel_clks));
- clk[vpu_div] = imx_clk_divider("vpu_div", "vpu_sel", CCM_PCDR0, 10, 3);
+ clk[vpu_div] = imx_clk_divider("vpu_div", "vpu_sel", CCM_PCDR0, 10, 6);
clk[usb_div] = imx_clk_divider("usb_div", "spll", CCM_CSCR, 28, 3);
clk[cpu_sel] = imx_clk_mux("cpu_sel", CCM_CSCR, 15, 1, cpu_sel_clks, ARRAY_SIZE(cpu_sel_clks));
clk[clko_sel] = imx_clk_mux("clko_sel", CCM_CCSR, 0, 5, clko_sel_clks, ARRAY_SIZE(clko_sel_clks));
@@ -121,7 +121,7 @@ int __init mx27_clocks_init(unsigned long fref)
clk[ssi1_sel] = imx_clk_mux("ssi1_sel", CCM_CSCR, 22, 1, ssi_sel_clks, ARRAY_SIZE(ssi_sel_clks));
clk[ssi2_sel] = imx_clk_mux("ssi2_sel", CCM_CSCR, 23, 1, ssi_sel_clks, ARRAY_SIZE(ssi_sel_clks));
clk[ssi1_div] = imx_clk_divider("ssi1_div", "ssi1_sel", CCM_PCDR0, 16, 6);
- clk[ssi2_div] = imx_clk_divider("ssi2_div", "ssi2_sel", CCM_PCDR0, 26, 3);
+ clk[ssi2_div] = imx_clk_divider("ssi2_div", "ssi2_sel", CCM_PCDR0, 26, 6);
clk[clko_en] = imx_clk_gate("clko_en", "clko_div", CCM_PCCR0, 0);
clk[ssi2_ipg_gate] = imx_clk_gate("ssi2_ipg_gate", "ipg", CCM_PCCR0, 0);
clk[ssi1_ipg_gate] = imx_clk_gate("ssi1_ipg_gate", "ipg", CCM_PCCR0, 1);
diff --git a/arch/arm/mach-imx/mm-imx3.c b/arch/arm/mach-imx/mm-imx3.c
index 9d2c843bde02..b5deb0554552 100644
--- a/arch/arm/mach-imx/mm-imx3.c
+++ b/arch/arm/mach-imx/mm-imx3.c
@@ -108,9 +108,8 @@ void __init imx3_init_l2x0(void)
}
l2x0_base = ioremap(MX3x_L2CC_BASE_ADDR, 4096);
- if (IS_ERR(l2x0_base)) {
- printk(KERN_ERR "remapping L2 cache area failed with %ld\n",
- PTR_ERR(l2x0_base));
+ if (!l2x0_base) {
+ printk(KERN_ERR "remapping L2 cache area failed\n");
return;
}
diff --git a/arch/arm/mach-omap2/Kconfig b/arch/arm/mach-omap2/Kconfig
index 2a1a898c7f90..d669e227e00c 100644
--- a/arch/arm/mach-omap2/Kconfig
+++ b/arch/arm/mach-omap2/Kconfig
@@ -11,7 +11,6 @@ config ARCH_OMAP2PLUS_TYPICAL
select I2C_OMAP
select MENELAUS if ARCH_OMAP2
select NEON if ARCH_OMAP3 || ARCH_OMAP4 || SOC_OMAP5
- select PINCTRL
select PM_RUNTIME
select REGULATOR
select SERIAL_OMAP
diff --git a/arch/arm/mach-omap2/board-omap3beagle.c b/arch/arm/mach-omap2/board-omap3beagle.c
index 388c431c745a..d41ab98890ff 100644
--- a/arch/arm/mach-omap2/board-omap3beagle.c
+++ b/arch/arm/mach-omap2/board-omap3beagle.c
@@ -24,6 +24,7 @@
#include <linux/input.h>
#include <linux/gpio_keys.h>
#include <linux/opp.h>
+#include <linux/cpu.h>
#include <linux/mtd/mtd.h>
#include <linux/mtd/partitions.h>
@@ -444,27 +445,31 @@ static struct omap_board_mux board_mux[] __initdata = {
};
#endif
-static void __init beagle_opp_init(void)
+static int __init beagle_opp_init(void)
{
int r = 0;
- /* Initialize the omap3 opp table */
- if (omap3_opp_init()) {
+ if (!machine_is_omap3_beagle())
+ return 0;
+
+ /* Initialize the omap3 opp table if not already created. */
+ r = omap3_opp_init();
+ if (IS_ERR_VALUE(r) && (r != -EEXIST)) {
pr_err("%s: opp default init failed\n", __func__);
- return;
+ return r;
}
/* Custom OPP enabled for all xM versions */
if (cpu_is_omap3630()) {
struct device *mpu_dev, *iva_dev;
- mpu_dev = omap_device_get_by_hwmod_name("mpu");
+ mpu_dev = get_cpu_device(0);
iva_dev = omap_device_get_by_hwmod_name("iva");
if (IS_ERR(mpu_dev) || IS_ERR(iva_dev)) {
pr_err("%s: Aiee.. no mpu/dsp devices? %p %p\n",
__func__, mpu_dev, iva_dev);
- return;
+ return -ENODEV;
}
/* Enable MPU 1GHz and lower opps */
r = opp_enable(mpu_dev, 800000000);
@@ -484,8 +489,9 @@ static void __init beagle_opp_init(void)
opp_disable(iva_dev, 660000000);
}
}
- return;
+ return 0;
}
+device_initcall(beagle_opp_init);
static void __init omap3_beagle_init(void)
{
@@ -522,8 +528,6 @@ static void __init omap3_beagle_init(void)
/* Ensure SDRC pins are mux'd for self-refresh */
omap_mux_init_signal("sdrc_cke0", OMAP_PIN_OUTPUT);
omap_mux_init_signal("sdrc_cke1", OMAP_PIN_OUTPUT);
-
- beagle_opp_init();
}
MACHINE_START(OMAP3_BEAGLE, "OMAP3 Beagle Board")
diff --git a/arch/arm/mach-omap2/clock33xx_data.c b/arch/arm/mach-omap2/clock33xx_data.c
index 114ab4b8e0e3..1a45d6bd2539 100644
--- a/arch/arm/mach-omap2/clock33xx_data.c
+++ b/arch/arm/mach-omap2/clock33xx_data.c
@@ -1073,6 +1073,8 @@ static struct omap_clk am33xx_clks[] = {
CLK(NULL, "gfx_fck_div_ck", &gfx_fck_div_ck, CK_AM33XX),
CLK(NULL, "sysclkout_pre_ck", &sysclkout_pre_ck, CK_AM33XX),
CLK(NULL, "clkout2_ck", &clkout2_ck, CK_AM33XX),
+ CLK(NULL, "timer_32k_ck", &clkdiv32k_ick, CK_AM33XX),
+ CLK(NULL, "timer_sys_ck", &sys_clkin_ck, CK_AM33XX),
};
int __init am33xx_clk_init(void)
diff --git a/arch/arm/mach-omap2/mux34xx.c b/arch/arm/mach-omap2/mux34xx.c
index 17f80e4ab162..c47140bbbec4 100644
--- a/arch/arm/mach-omap2/mux34xx.c
+++ b/arch/arm/mach-omap2/mux34xx.c
@@ -614,16 +614,16 @@ static struct omap_mux __initdata omap3_muxmodes[] = {
"sys_off_mode", NULL, NULL, NULL,
"gpio_9", NULL, NULL, "safe_mode"),
_OMAP3_MUXENTRY(UART1_CTS, 150,
- "uart1_cts", NULL, NULL, NULL,
+ "uart1_cts", "ssi1_rdy_tx", NULL, NULL,
"gpio_150", "hsusb3_tll_clk", NULL, "safe_mode"),
_OMAP3_MUXENTRY(UART1_RTS, 149,
- "uart1_rts", NULL, NULL, NULL,
+ "uart1_rts", "ssi1_flag_tx", NULL, NULL,
"gpio_149", NULL, NULL, "safe_mode"),
_OMAP3_MUXENTRY(UART1_RX, 151,
- "uart1_rx", NULL, "mcbsp1_clkr", "mcspi4_clk",
+ "uart1_rx", "ss1_wake_tx", "mcbsp1_clkr", "mcspi4_clk",
"gpio_151", NULL, NULL, "safe_mode"),
_OMAP3_MUXENTRY(UART1_TX, 148,
- "uart1_tx", NULL, NULL, NULL,
+ "uart1_tx", "ssi1_dat_tx", NULL, NULL,
"gpio_148", NULL, NULL, "safe_mode"),
_OMAP3_MUXENTRY(UART2_CTS, 144,
"uart2_cts", "mcbsp3_dx", "gpt9_pwm_evt", NULL,
diff --git a/arch/arm/mach-omap2/pm.h b/arch/arm/mach-omap2/pm.h
index 686137d164da..67d66131cfa7 100644
--- a/arch/arm/mach-omap2/pm.h
+++ b/arch/arm/mach-omap2/pm.h
@@ -91,6 +91,7 @@ extern void omap3_save_scratchpad_contents(void);
#define PM_RTA_ERRATUM_i608 (1 << 0)
#define PM_SDRC_WAKEUP_ERRATUM_i583 (1 << 1)
+#define PM_PER_MEMORIES_ERRATUM_i582 (1 << 2)
#if defined(CONFIG_PM) && defined(CONFIG_ARCH_OMAP3)
extern u16 pm34xx_errata;
diff --git a/arch/arm/mach-omap2/pm34xx.c b/arch/arm/mach-omap2/pm34xx.c
index ba670db1fd37..3a904de4313e 100644
--- a/arch/arm/mach-omap2/pm34xx.c
+++ b/arch/arm/mach-omap2/pm34xx.c
@@ -652,14 +652,17 @@ static void __init pm_errata_configure(void)
/* Enable the l2 cache toggling in sleep logic */
enable_omap3630_toggle_l2_on_restore();
if (omap_rev() < OMAP3630_REV_ES1_2)
- pm34xx_errata |= PM_SDRC_WAKEUP_ERRATUM_i583;
+ pm34xx_errata |= (PM_SDRC_WAKEUP_ERRATUM_i583 |
+ PM_PER_MEMORIES_ERRATUM_i582);
+ } else if (cpu_is_omap34xx()) {
+ pm34xx_errata |= PM_PER_MEMORIES_ERRATUM_i582;
}
}
int __init omap3_pm_init(void)
{
struct power_state *pwrst, *tmp;
- struct clockdomain *neon_clkdm, *mpu_clkdm;
+ struct clockdomain *neon_clkdm, *mpu_clkdm, *per_clkdm, *wkup_clkdm;
int ret;
if (!omap3_has_io_chain_ctrl())
@@ -711,6 +714,8 @@ int __init omap3_pm_init(void)
neon_clkdm = clkdm_lookup("neon_clkdm");
mpu_clkdm = clkdm_lookup("mpu_clkdm");
+ per_clkdm = clkdm_lookup("per_clkdm");
+ wkup_clkdm = clkdm_lookup("wkup_clkdm");
#ifdef CONFIG_SUSPEND
omap_pm_suspend = omap3_pm_suspend;
@@ -727,6 +732,27 @@ int __init omap3_pm_init(void)
if (IS_PM34XX_ERRATUM(PM_RTA_ERRATUM_i608))
omap3630_ctrl_disable_rta();
+ /*
+ * The UART3/4 FIFO and the sidetone memory in McBSP2/3 are
+ * not correctly reset when the PER powerdomain comes back
+ * from OFF or OSWR when the CORE powerdomain is kept active.
+ * See OMAP36xx Erratum i582 "PER Domain reset issue after
+ * Domain-OFF/OSWR Wakeup". This wakeup dependency is not a
+ * complete workaround. The kernel must also prevent the PER
+ * powerdomain from going to OSWR/OFF while the CORE
+ * powerdomain is not going to OSWR/OFF. And if PER last
+ * power state was off while CORE last power state was ON, the
+ * UART3/4 and McBSP2/3 SIDETONE devices need to run a
+ * self-test using their loopback tests; if that fails, those
+ * devices are unusable until the PER/CORE can complete a transition
+ * from ON to OSWR/OFF and then back to ON.
+ *
+ * XXX Technically this workaround is only needed if off-mode
+ * or OSWR is enabled.
+ */
+ if (IS_PM34XX_ERRATUM(PM_PER_MEMORIES_ERRATUM_i582))
+ clkdm_add_wkdep(per_clkdm, wkup_clkdm);
+
clkdm_add_wkdep(neon_clkdm, mpu_clkdm);
if (omap_type() != OMAP2_DEVICE_TYPE_GP) {
omap3_secure_ram_storage =
diff --git a/arch/arm/mach-omap2/serial.c b/arch/arm/mach-omap2/serial.c
index 0405c8190803..a507cd6cf4f1 100644
--- a/arch/arm/mach-omap2/serial.c
+++ b/arch/arm/mach-omap2/serial.c
@@ -329,6 +329,11 @@ void __init omap_serial_init_port(struct omap_board_data *bdata,
oh->mux = omap_hwmod_mux_init(bdata->pads, bdata->pads_cnt);
+ if (console_uart_id == bdata->id) {
+ omap_device_enable(pdev);
+ pm_runtime_set_active(&pdev->dev);
+ }
+
oh->dev_attr = uart;
if (((cpu_is_omap34xx() || cpu_is_omap44xx()) && bdata->pads)
diff --git a/arch/arm/mach-s3c24xx/s3c2416.c b/arch/arm/mach-s3c24xx/s3c2416.c
index ed5a95ece9eb..77ee0b732237 100644
--- a/arch/arm/mach-s3c24xx/s3c2416.c
+++ b/arch/arm/mach-s3c24xx/s3c2416.c
@@ -61,6 +61,7 @@
#include <plat/nand-core.h>
#include <plat/adc-core.h>
#include <plat/rtc-core.h>
+#include <plat/spi-core.h>
static struct map_desc s3c2416_iodesc[] __initdata = {
IODESC_ENT(WATCHDOG),
@@ -132,6 +133,7 @@ void __init s3c2416_map_io(void)
/* initialize device information early */
s3c2416_default_sdhci0();
s3c2416_default_sdhci1();
+ s3c64xx_spi_setname("s3c2443-spi");
iotable_init(s3c2416_iodesc, ARRAY_SIZE(s3c2416_iodesc));
}
diff --git a/arch/arm/mach-s3c24xx/s3c2443.c b/arch/arm/mach-s3c24xx/s3c2443.c
index ab648ad8fa50..165b6a6b3daa 100644
--- a/arch/arm/mach-s3c24xx/s3c2443.c
+++ b/arch/arm/mach-s3c24xx/s3c2443.c
@@ -43,6 +43,7 @@
#include <plat/nand-core.h>
#include <plat/adc-core.h>
#include <plat/rtc-core.h>
+#include <plat/spi-core.h>
static struct map_desc s3c2443_iodesc[] __initdata = {
IODESC_ENT(WATCHDOG),
@@ -100,6 +101,9 @@ void __init s3c2443_map_io(void)
s3c24xx_gpiocfg_default.set_pull = s3c2443_gpio_setpull;
s3c24xx_gpiocfg_default.get_pull = s3c2443_gpio_getpull;
+ /* initialize device information early */
+ s3c64xx_spi_setname("s3c2443-spi");
+
iotable_init(s3c2443_iodesc, ARRAY_SIZE(s3c2443_iodesc));
}
diff --git a/arch/arm/mach-s5p64x0/common.c b/arch/arm/mach-s5p64x0/common.c
index 6e6a0a9d6778..111e404a81fd 100644
--- a/arch/arm/mach-s5p64x0/common.c
+++ b/arch/arm/mach-s5p64x0/common.c
@@ -44,6 +44,7 @@
#include <plat/sdhci.h>
#include <plat/adc-core.h>
#include <plat/fb-core.h>
+#include <plat/spi-core.h>
#include <plat/gpio-cfg.h>
#include <plat/regs-irqtype.h>
#include <plat/regs-serial.h>
@@ -179,6 +180,7 @@ void __init s5p6440_map_io(void)
/* initialize any device information early */
s3c_adc_setname("s3c64xx-adc");
s3c_fb_setname("s5p64x0-fb");
+ s3c64xx_spi_setname("s5p64x0-spi");
s5p64x0_default_sdhci0();
s5p64x0_default_sdhci1();
@@ -193,6 +195,7 @@ void __init s5p6450_map_io(void)
/* initialize any device information early */
s3c_adc_setname("s3c64xx-adc");
s3c_fb_setname("s5p64x0-fb");
+ s3c64xx_spi_setname("s5p64x0-spi");
s5p64x0_default_sdhci0();
s5p64x0_default_sdhci1();
diff --git a/arch/arm/mach-s5pc100/common.c b/arch/arm/mach-s5pc100/common.c
index 621908658861..cc6e561c9958 100644
--- a/arch/arm/mach-s5pc100/common.c
+++ b/arch/arm/mach-s5pc100/common.c
@@ -45,6 +45,7 @@
#include <plat/fb-core.h>
#include <plat/iic-core.h>
#include <plat/onenand-core.h>
+#include <plat/spi-core.h>
#include <plat/regs-serial.h>
#include <plat/watchdog-reset.h>
@@ -165,6 +166,8 @@ void __init s5pc100_map_io(void)
s3c_onenand_setname("s5pc100-onenand");
s3c_fb_setname("s5pc100-fb");
s3c_cfcon_setname("s5pc100-pata");
+
+ s3c64xx_spi_setname("s5pc100-spi");
}
void __init s5pc100_init_clocks(int xtal)
diff --git a/arch/arm/mach-s5pv210/common.c b/arch/arm/mach-s5pv210/common.c
index 4c9e9027df9a..a0c50efe8145 100644
--- a/arch/arm/mach-s5pv210/common.c
+++ b/arch/arm/mach-s5pv210/common.c
@@ -43,6 +43,7 @@
#include <plat/iic-core.h>
#include <plat/keypad-core.h>
#include <plat/tv-core.h>
+#include <plat/spi-core.h>
#include <plat/regs-serial.h>
#include "common.h"
@@ -196,6 +197,8 @@ void __init s5pv210_map_io(void)
/* setup TV devices */
s5p_hdmi_setname("s5pv210-hdmi");
+
+ s3c64xx_spi_setname("s5pv210-spi");
}
void __init s5pv210_init_clocks(int xtal)
diff --git a/arch/arm/mach-shmobile/setup-r8a7779.c b/arch/arm/mach-shmobile/setup-r8a7779.c
index 2917668f0091..ebbffc25f24f 100644
--- a/arch/arm/mach-shmobile/setup-r8a7779.c
+++ b/arch/arm/mach-shmobile/setup-r8a7779.c
@@ -247,7 +247,7 @@ void __init r8a7779_add_standard_devices(void)
{
#ifdef CONFIG_CACHE_L2X0
/* Early BRESP enable, Shared attribute override enable, 64K*16way */
- l2x0_init((void __iomem __force *)(0xf0100000), 0x40470000, 0x82000fff);
+ l2x0_init(IOMEM(0xf0100000), 0x40470000, 0x82000fff);
#endif
r8a7779_pm_init();
diff --git a/arch/arm/mach-spear13xx/include/mach/spear1310_misc_regs.h b/arch/arm/mach-spear13xx/include/mach/spear1310_misc_regs.h
deleted file mode 100644
index e69de29bb2d1..000000000000
--- a/arch/arm/mach-spear13xx/include/mach/spear1310_misc_regs.h
+++ /dev/null
diff --git a/arch/arm/mach-spear13xx/include/mach/spear1340_misc_regs.h b/arch/arm/mach-spear13xx/include/mach/spear1340_misc_regs.h
deleted file mode 100644
index e69de29bb2d1..000000000000
--- a/arch/arm/mach-spear13xx/include/mach/spear1340_misc_regs.h
+++ /dev/null
diff --git a/arch/arm/mach-ux500/cpu.c b/arch/arm/mach-ux500/cpu.c
index 2236cbd03cd7..1f3fbc2bb776 100644
--- a/arch/arm/mach-ux500/cpu.c
+++ b/arch/arm/mach-ux500/cpu.c
@@ -16,6 +16,7 @@
#include <linux/stat.h>
#include <linux/of.h>
#include <linux/of_irq.h>
+#include <linux/irq.h>
#include <linux/platform_data/clk-ux500.h>
#include <asm/hardware/gic.h>
diff --git a/arch/arm/plat-mxc/devices/platform-mxc-mmc.c b/arch/arm/plat-mxc/devices/platform-mxc-mmc.c
index 540d3a7d92df..e7b920b58675 100644
--- a/arch/arm/plat-mxc/devices/platform-mxc-mmc.c
+++ b/arch/arm/plat-mxc/devices/platform-mxc-mmc.c
@@ -55,7 +55,7 @@ struct platform_device *__init imx_add_mxc_mmc(
struct resource res[] = {
{
.start = data->iobase,
- .end = data->iobase + SZ_4K - 1,
+ .end = data->iobase + data->iosize - 1,
.flags = IORESOURCE_MEM,
}, {
.start = data->irq,
diff --git a/arch/arm/plat-omap/Kconfig b/arch/arm/plat-omap/Kconfig
index 7cd56ed5cd94..82fcb206b5b2 100644
--- a/arch/arm/plat-omap/Kconfig
+++ b/arch/arm/plat-omap/Kconfig
@@ -26,6 +26,7 @@ config ARCH_OMAP2PLUS
select CLKDEV_LOOKUP
select GENERIC_IRQ_CHIP
select OMAP_DM_TIMER
+ select PINCTRL
select PROC_DEVICETREE if PROC_FS
select SPARSE_IRQ
select USE_OF
diff --git a/arch/arm/plat-samsung/include/plat/spi-core.h b/arch/arm/plat-samsung/include/plat/spi-core.h
new file mode 100644
index 000000000000..0b9428ab3fc3
--- /dev/null
+++ b/arch/arm/plat-samsung/include/plat/spi-core.h
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2012 Heiko Stuebner <heiko@sntech.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef __PLAT_S3C_SPI_CORE_H
+#define __PLAT_S3C_SPI_CORE_H
+
+/* These functions are only for use with the core support code, such as
+ * the cpu specific initialisation code
+ */
+
+/* re-define device name depending on support. */
+static inline void s3c64xx_spi_setname(char *name)
+{
+#ifdef CONFIG_S3C64XX_DEV_SPI0
+ s3c64xx_device_spi0.name = name;
+#endif
+#ifdef CONFIG_S3C64XX_DEV_SPI1
+ s3c64xx_device_spi1.name = name;
+#endif
+#ifdef CONFIG_S3C64XX_DEV_SPI2
+ s3c64xx_device_spi2.name = name;
+#endif
+}
+
+#endif /* __PLAT_S3C_SPI_CORE_H */
diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
index ef54a59a9e89..138fc9cfd783 100644
--- a/arch/arm64/Kconfig
+++ b/arch/arm64/Kconfig
@@ -6,6 +6,8 @@ config ARM64
select GENERIC_IOMAP
select GENERIC_IRQ_PROBE
select GENERIC_IRQ_SHOW
+ select GENERIC_KERNEL_EXECVE
+ select GENERIC_KERNEL_THREAD
select GENERIC_SMP_IDLE_THREAD
select GENERIC_TIME_VSYSCALL
select HARDIRQS_SW_RESEND
diff --git a/arch/arm64/include/asm/processor.h b/arch/arm64/include/asm/processor.h
index 5d810044feda..42471d07d972 100644
--- a/arch/arm64/include/asm/processor.h
+++ b/arch/arm64/include/asm/processor.h
@@ -126,11 +126,6 @@ unsigned long get_wchan(struct task_struct *p);
extern struct task_struct *cpu_switch_to(struct task_struct *prev,
struct task_struct *next);
-/*
- * Create a new kernel thread
- */
-extern int kernel_thread(int (*fn)(void *), void *arg, unsigned long flags);
-
#define task_pt_regs(p) \
((struct pt_regs *)(THREAD_START_SP + task_stack_page(p)) - 1)
diff --git a/arch/arm64/include/asm/syscalls.h b/arch/arm64/include/asm/syscalls.h
index 09ff33572aab..81680a0ae913 100644
--- a/arch/arm64/include/asm/syscalls.h
+++ b/arch/arm64/include/asm/syscalls.h
@@ -23,9 +23,6 @@
/*
* System call wrappers implemented in kernel/entry.S.
*/
-asmlinkage long sys_execve_wrapper(const char __user *filename,
- const char __user *const __user *argv,
- const char __user *const __user *envp);
asmlinkage long sys_clone_wrapper(unsigned long clone_flags,
unsigned long newsp,
void __user *parent_tid,
diff --git a/arch/arm64/include/asm/unistd.h b/arch/arm64/include/asm/unistd.h
index 63f853f8b718..b40dc6b69848 100644
--- a/arch/arm64/include/asm/unistd.h
+++ b/arch/arm64/include/asm/unistd.h
@@ -26,4 +26,5 @@
#define __ARCH_WANT_COMPAT_SYS_RT_SIGSUSPEND
#define __ARCH_WANT_COMPAT_SYS_SENDFILE
#endif
+#define __ARCH_WANT_SYS_EXECVE
#include <uapi/asm/unistd.h>
diff --git a/arch/arm64/include/asm/unistd32.h b/arch/arm64/include/asm/unistd32.h
index 6d909faebf28..9035e6add3e4 100644
--- a/arch/arm64/include/asm/unistd32.h
+++ b/arch/arm64/include/asm/unistd32.h
@@ -32,7 +32,7 @@ __SYSCALL(7, sys_ni_syscall) /* 7 was sys_waitpid */
__SYSCALL(8, sys_creat)
__SYSCALL(9, sys_link)
__SYSCALL(10, sys_unlink)
-__SYSCALL(11, compat_sys_execve_wrapper)
+__SYSCALL(11, compat_sys_execve)
__SYSCALL(12, sys_chdir)
__SYSCALL(13, sys_ni_syscall) /* 13 was sys_time */
__SYSCALL(14, sys_mknod)
diff --git a/arch/arm64/kernel/entry.S b/arch/arm64/kernel/entry.S
index a6f3f7da6880..616531862d52 100644
--- a/arch/arm64/kernel/entry.S
+++ b/arch/arm64/kernel/entry.S
@@ -594,7 +594,7 @@ work_resched:
/*
* "slow" syscall return path.
*/
-ENTRY(ret_to_user)
+ret_to_user:
disable_irq // disable interrupts
ldr x1, [tsk, #TI_FLAGS]
and x2, x1, #_TIF_WORK_MASK
@@ -611,7 +611,10 @@ ENDPROC(ret_to_user)
*/
ENTRY(ret_from_fork)
bl schedule_tail
- get_thread_info tsk
+ cbz x19, 1f // not a kernel thread
+ mov x0, x20
+ blr x19
+1: get_thread_info tsk
b ret_to_user
ENDPROC(ret_from_fork)
@@ -673,11 +676,6 @@ __sys_trace_return:
/*
* Special system call wrappers.
*/
-ENTRY(sys_execve_wrapper)
- mov x3, sp
- b sys_execve
-ENDPROC(sys_execve_wrapper)
-
ENTRY(sys_clone_wrapper)
mov x5, sp
b sys_clone
diff --git a/arch/arm64/kernel/process.c b/arch/arm64/kernel/process.c
index f22965ea1cfc..bf615e212c6c 100644
--- a/arch/arm64/kernel/process.c
+++ b/arch/arm64/kernel/process.c
@@ -240,27 +240,35 @@ int copy_thread(unsigned long clone_flags, unsigned long stack_start,
struct pt_regs *childregs = task_pt_regs(p);
unsigned long tls = p->thread.tp_value;
- *childregs = *regs;
- childregs->regs[0] = 0;
+ memset(&p->thread.cpu_context, 0, sizeof(struct cpu_context));
- if (is_compat_thread(task_thread_info(p)))
- childregs->compat_sp = stack_start;
- else {
+ if (likely(regs)) {
+ *childregs = *regs;
+ childregs->regs[0] = 0;
+ if (is_compat_thread(task_thread_info(p))) {
+ childregs->compat_sp = stack_start;
+ } else {
+ /*
+ * Read the current TLS pointer from tpidr_el0 as it may be
+ * out-of-sync with the saved value.
+ */
+ asm("mrs %0, tpidr_el0" : "=r" (tls));
+ childregs->sp = stack_start;
+ }
/*
- * Read the current TLS pointer from tpidr_el0 as it may be
- * out-of-sync with the saved value.
+ * If a TLS pointer was passed to clone (4th argument), use it
+ * for the new thread.
*/
- asm("mrs %0, tpidr_el0" : "=r" (tls));
- childregs->sp = stack_start;
+ if (clone_flags & CLONE_SETTLS)
+ tls = regs->regs[3];
+ } else {
+ memset(childregs, 0, sizeof(struct pt_regs));
+ childregs->pstate = PSR_MODE_EL1h;
+ p->thread.cpu_context.x19 = stack_start;
+ p->thread.cpu_context.x20 = stk_sz;
}
-
- memset(&p->thread.cpu_context, 0, sizeof(struct cpu_context));
- p->thread.cpu_context.sp = (unsigned long)childregs;
p->thread.cpu_context.pc = (unsigned long)ret_from_fork;
-
- /* If a TLS pointer was passed to clone, use that for the new thread. */
- if (clone_flags & CLONE_SETTLS)
- tls = regs->regs[3];
+ p->thread.cpu_context.sp = (unsigned long)childregs;
p->thread.tp_value = tls;
ptrace_hw_copy_thread(p);
@@ -327,43 +335,6 @@ int dump_fpu (struct pt_regs *regs, struct user_fp *fp)
}
EXPORT_SYMBOL(dump_fpu);
-/*
- * Shuffle the argument into the correct register before calling the
- * thread function. x1 is the thread argument, x2 is the pointer to
- * the thread function, and x3 points to the exit function.
- */
-extern void kernel_thread_helper(void);
-asm( ".section .text\n"
-" .align\n"
-" .type kernel_thread_helper, #function\n"
-"kernel_thread_helper:\n"
-" mov x0, x1\n"
-" mov x30, x3\n"
-" br x2\n"
-" .size kernel_thread_helper, . - kernel_thread_helper\n"
-" .previous");
-
-#define kernel_thread_exit do_exit
-
-/*
- * Create a kernel thread.
- */
-pid_t kernel_thread(int (*fn)(void *), void *arg, unsigned long flags)
-{
- struct pt_regs regs;
-
- memset(&regs, 0, sizeof(regs));
-
- regs.regs[1] = (unsigned long)arg;
- regs.regs[2] = (unsigned long)fn;
- regs.regs[3] = (unsigned long)kernel_thread_exit;
- regs.pc = (unsigned long)kernel_thread_helper;
- regs.pstate = PSR_MODE_EL1h;
-
- return do_fork(flags|CLONE_VM|CLONE_UNTRACED, 0, &regs, 0, NULL, NULL);
-}
-EXPORT_SYMBOL(kernel_thread);
-
unsigned long get_wchan(struct task_struct *p)
{
struct stackframe frame;
diff --git a/arch/arm64/kernel/sys.c b/arch/arm64/kernel/sys.c
index b120df37de35..9c77c0bacc1d 100644
--- a/arch/arm64/kernel/sys.c
+++ b/arch/arm64/kernel/sys.c
@@ -41,70 +41,6 @@ asmlinkage long sys_clone(unsigned long clone_flags, unsigned long newsp,
return do_fork(clone_flags, newsp, regs, 0, parent_tidptr, child_tidptr);
}
-/*
- * sys_execve() executes a new program.
- */
-asmlinkage long sys_execve(const char __user *filenamei,
- const char __user *const __user *argv,
- const char __user *const __user *envp,
- struct pt_regs *regs)
-{
- long error;
- struct filename *filename;
-
- filename = getname(filenamei);
- error = PTR_ERR(filename);
- if (IS_ERR(filename))
- goto out;
- error = do_execve(filename->name, argv, envp, regs);
- putname(filename);
-out:
- return error;
-}
-
-int kernel_execve(const char *filename,
- const char *const argv[],
- const char *const envp[])
-{
- struct pt_regs regs;
- int ret;
-
- memset(&regs, 0, sizeof(struct pt_regs));
- ret = do_execve(filename,
- (const char __user *const __user *)argv,
- (const char __user *const __user *)envp, &regs);
- if (ret < 0)
- goto out;
-
- /*
- * Save argc to the register structure for userspace.
- */
- regs.regs[0] = ret;
-
- /*
- * We were successful. We won't be returning to our caller, but
- * instead to user space by manipulating the kernel stack.
- */
- asm( "add x0, %0, %1\n\t"
- "mov x1, %2\n\t"
- "mov x2, %3\n\t"
- "bl memmove\n\t" /* copy regs to top of stack */
- "mov x27, #0\n\t" /* not a syscall */
- "mov x28, %0\n\t" /* thread structure */
- "mov sp, x0\n\t" /* reposition stack pointer */
- "b ret_to_user"
- :
- : "r" (current_thread_info()),
- "Ir" (THREAD_START_SP - sizeof(regs)),
- "r" (&regs),
- "Ir" (sizeof(regs))
- : "x0", "x1", "x2", "x27", "x28", "x30", "memory");
-
- out:
- return ret;
-}
-EXPORT_SYMBOL(kernel_execve);
-
asmlinkage long sys_mmap(unsigned long addr, unsigned long len,
unsigned long prot, unsigned long flags,
unsigned long fd, off_t off)
@@ -118,7 +54,6 @@ asmlinkage long sys_mmap(unsigned long addr, unsigned long len,
/*
* Wrappers to pass the pt_regs argument.
*/
-#define sys_execve sys_execve_wrapper
#define sys_clone sys_clone_wrapper
#define sys_rt_sigreturn sys_rt_sigreturn_wrapper
#define sys_sigaltstack sys_sigaltstack_wrapper
diff --git a/arch/arm64/kernel/sys32.S b/arch/arm64/kernel/sys32.S
index 54c4aec47a08..92145d402cf1 100644
--- a/arch/arm64/kernel/sys32.S
+++ b/arch/arm64/kernel/sys32.S
@@ -36,11 +36,6 @@ compat_sys_vfork_wrapper:
b compat_sys_vfork
ENDPROC(compat_sys_vfork_wrapper)
-compat_sys_execve_wrapper:
- mov x3, sp
- b compat_sys_execve
-ENDPROC(compat_sys_execve_wrapper)
-
compat_sys_clone_wrapper:
mov x5, sp
b compat_sys_clone
diff --git a/arch/arm64/kernel/sys_compat.c b/arch/arm64/kernel/sys_compat.c
index 906e3bd270b0..d140b73a8bc4 100644
--- a/arch/arm64/kernel/sys_compat.c
+++ b/arch/arm64/kernel/sys_compat.c
@@ -49,24 +49,6 @@ asmlinkage int compat_sys_vfork(struct pt_regs *regs)
regs, 0, NULL, NULL);
}
-asmlinkage int compat_sys_execve(const char __user *filenamei,
- compat_uptr_t argv, compat_uptr_t envp,
- struct pt_regs *regs)
-{
- int error;
- struct filename *filename;
-
- filename = getname(filenamei);
- error = PTR_ERR(filename);
- if (IS_ERR(filename))
- goto out;
- error = compat_do_execve(filename->name, compat_ptr(argv),
- compat_ptr(envp), regs);
- putname(filename);
-out:
- return error;
-}
-
asmlinkage int compat_sys_sched_rr_get_interval(compat_pid_t pid,
struct compat_timespec __user *interval)
{
diff --git a/arch/c6x/Kconfig b/arch/c6x/Kconfig
index aee1b569ee6e..66eab3703c75 100644
--- a/arch/c6x/Kconfig
+++ b/arch/c6x/Kconfig
@@ -18,6 +18,7 @@ config C6X
select OF_EARLY_FLATTREE
select GENERIC_CLOCKEVENTS
select GENERIC_KERNEL_THREAD
+ select GENERIC_KERNEL_EXECVE
select MODULES_USE_ELF_RELA
config MMU
diff --git a/arch/c6x/include/uapi/asm/unistd.h b/arch/c6x/include/uapi/asm/unistd.h
index 4ff747d12dad..625beafb9cd1 100644
--- a/arch/c6x/include/uapi/asm/unistd.h
+++ b/arch/c6x/include/uapi/asm/unistd.h
@@ -14,7 +14,6 @@
* more details.
*/
-#define __ARCH_WANT_KERNEL_EXECVE
#define __ARCH_WANT_SYS_EXECVE
/* Use the standard ABI for syscalls. */
diff --git a/arch/c6x/kernel/entry.S b/arch/c6x/kernel/entry.S
index 5449c36018fe..75f6f36472cf 100644
--- a/arch/c6x/kernel/entry.S
+++ b/arch/c6x/kernel/entry.S
@@ -413,19 +413,9 @@ ENTRY(ret_from_kernel_thread)
0:
B .S2 B10 /* call fn */
LDW .D2T1 *+SP(REGS_A1+8),A4 /* get arg */
- MVKL .S2 sys_exit,B11
- MVKH .S2 sys_exit,B11
- ADDKPC .S2 0f,B3,1
-0:
- BNOP .S2 B11,5 /* jump to sys_exit */
+ ADDKPC .S2 ret_from_fork_2,B3,3
ENDPROC(ret_from_kernel_thread)
-ENTRY(ret_from_kernel_execve)
- GET_THREAD_INFO A12
- BNOP .S2 syscall_exit,4
- ADD .D2X A4,-8,SP
-ENDPROC(ret_from_kernel_execve)
-
;;
;; These are the interrupt handlers, responsible for calling __do_IRQ()
;; int6 is used for syscalls (see _system_call entry)
diff --git a/arch/frv/Kconfig b/arch/frv/Kconfig
index b7412504f08a..df2eb4bd9fa2 100644
--- a/arch/frv/Kconfig
+++ b/arch/frv/Kconfig
@@ -13,6 +13,7 @@ config FRV
select GENERIC_CPU_DEVICES
select ARCH_WANT_IPC_PARSE_VERSION
select GENERIC_KERNEL_THREAD
+ select GENERIC_KERNEL_EXECVE
config ZONE_DMA
bool
diff --git a/arch/frv/boot/Makefile b/arch/frv/boot/Makefile
index 6ae3254da019..636d5bbcd53f 100644
--- a/arch/frv/boot/Makefile
+++ b/arch/frv/boot/Makefile
@@ -17,6 +17,8 @@ PARAMS_PHYS = 0x0207c000
INITRD_PHYS = 0x02180000
INITRD_VIRT = 0x02180000
+OBJCOPYFLAGS :=-O binary -R .note -R .note.gnu.build-id -R .comment
+
#
# If you don't define ZRELADDR above,
# then it defaults to ZTEXTADDR
@@ -32,18 +34,18 @@ Image: $(obj)/Image
targets: $(obj)/Image
$(obj)/Image: vmlinux FORCE
- $(OBJCOPY) -O binary -R .note -R .comment -S vmlinux $@
+ $(OBJCOPY) $(OBJCOPYFLAGS) -S vmlinux $@
#$(obj)/Image: $(CONFIGURE) $(SYSTEM)
-# $(OBJCOPY) -O binary -R .note -R .comment -g -S $(SYSTEM) $@
+# $(OBJCOPY) $(OBJCOPYFLAGS) -g -S $(SYSTEM) $@
bzImage: zImage
zImage: $(CONFIGURE) compressed/$(LINUX)
- $(OBJCOPY) -O binary -R .note -R .comment -S compressed/$(LINUX) $@
+ $(OBJCOPY) $(OBJCOPYFLAGS) -S compressed/$(LINUX) $@
bootpImage: bootp/bootp
- $(OBJCOPY) -O binary -R .note -R .comment -S bootp/bootp $@
+ $(OBJCOPY) $(OBJCOPYFLAGS) -S bootp/bootp $@
compressed/$(LINUX): $(LINUX) dep
@$(MAKE) -C compressed $(LINUX)
diff --git a/arch/frv/include/asm/unistd.h b/arch/frv/include/asm/unistd.h
index 266a5b25a0c1..2358634cacca 100644
--- a/arch/frv/include/asm/unistd.h
+++ b/arch/frv/include/asm/unistd.h
@@ -30,7 +30,6 @@
#define __ARCH_WANT_SYS_RT_SIGACTION
#define __ARCH_WANT_SYS_RT_SIGSUSPEND
#define __ARCH_WANT_SYS_EXECVE
-#define __ARCH_WANT_KERNEL_EXECVE
/*
* "Conditional" syscalls
diff --git a/arch/frv/kernel/entry.S b/arch/frv/kernel/entry.S
index ee0beb354e4d..dfcd263c0517 100644
--- a/arch/frv/kernel/entry.S
+++ b/arch/frv/kernel/entry.S
@@ -869,11 +869,6 @@ ret_from_kernel_thread:
call schedule_tail
calll.p @(gr21,gr0)
or gr20,gr20,gr8
- bra sys_exit
-
- .globl ret_from_kernel_execve
-ret_from_kernel_execve:
- ori gr28,0,sp
bra __syscall_exit
###################################################################################################
@@ -1080,27 +1075,10 @@ __entry_return_from_kernel_interrupt:
subicc gr5,#0,gr0,icc0
beq icc0,#0,__entry_return_direct
-__entry_preempt_need_resched:
- ldi @(gr15,#TI_FLAGS),gr4
- andicc gr4,#_TIF_NEED_RESCHED,gr0,icc0
- beq icc0,#1,__entry_return_direct
-
- setlos #PREEMPT_ACTIVE,gr5
- sti gr5,@(gr15,#TI_FLAGS)
-
- andi gr23,#~PSR_PIL,gr23
- movgs gr23,psr
-
- call schedule
- sti gr0,@(gr15,#TI_PRE_COUNT)
-
- movsg psr,gr23
- ori gr23,#PSR_PIL_14,gr23
- movgs gr23,psr
- bra __entry_preempt_need_resched
-#else
- bra __entry_return_direct
+ subcc gr0,gr0,gr0,icc2 /* set Z and clear C */
+ call preempt_schedule_irq
#endif
+ bra __entry_return_direct
###############################################################################
diff --git a/arch/frv/kernel/process.c b/arch/frv/kernel/process.c
index e1e3aa196aa4..7e33215f1d8f 100644
--- a/arch/frv/kernel/process.c
+++ b/arch/frv/kernel/process.c
@@ -181,6 +181,9 @@ int copy_thread(unsigned long clone_flags,
childregs = (struct pt_regs *)
(task_stack_page(p) + THREAD_SIZE - FRV_FRAME0_SIZE);
+ /* set up the userspace frame (the only place that the USP is stored) */
+ *childregs = *__kernel_frame0_ptr;
+
p->set_child_tid = p->clear_child_tid = NULL;
p->thread.frame = childregs;
@@ -191,10 +194,8 @@ int copy_thread(unsigned long clone_flags,
p->thread.frame0 = childregs;
if (unlikely(!regs)) {
- memset(childregs, 0, sizeof(struct pt_regs));
childregs->gr9 = usp; /* function */
childregs->gr8 = arg;
- childregs->psr = PSR_S;
p->thread.pc = (unsigned long) ret_from_kernel_thread;
save_user_regs(p->thread.user);
return 0;
diff --git a/arch/frv/mb93090-mb00/pci-dma-nommu.c b/arch/frv/mb93090-mb00/pci-dma-nommu.c
index e47857f889b6..b99c2a7cc7a4 100644
--- a/arch/frv/mb93090-mb00/pci-dma-nommu.c
+++ b/arch/frv/mb93090-mb00/pci-dma-nommu.c
@@ -11,6 +11,7 @@
#include <linux/types.h>
#include <linux/slab.h>
+#include <linux/export.h>
#include <linux/dma-mapping.h>
#include <linux/list.h>
#include <linux/pci.h>
diff --git a/arch/hexagon/Kconfig b/arch/hexagon/Kconfig
index 0744f7d7b1fd..e418803b6c8e 100644
--- a/arch/hexagon/Kconfig
+++ b/arch/hexagon/Kconfig
@@ -31,6 +31,8 @@ config HEXAGON
select GENERIC_CLOCKEVENTS
select GENERIC_CLOCKEVENTS_BROADCAST
select MODULES_USE_ELF_RELA
+ select GENERIC_KERNEL_THREAD
+ select GENERIC_KERNEL_EXECVE
---help---
Qualcomm Hexagon is a processor architecture designed for high
performance and low power across a wide variety of applications.
diff --git a/arch/hexagon/include/asm/processor.h b/arch/hexagon/include/asm/processor.h
index a03323ab9d44..6dd5d3706869 100644
--- a/arch/hexagon/include/asm/processor.h
+++ b/arch/hexagon/include/asm/processor.h
@@ -34,7 +34,6 @@
struct task_struct;
/* this is defined in arch/process.c */
-extern pid_t kernel_thread(int (*fn)(void *), void * arg, unsigned long flags);
extern unsigned long thread_saved_pc(struct task_struct *tsk);
extern void start_thread(struct pt_regs *, unsigned long, unsigned long);
diff --git a/arch/hexagon/include/uapi/asm/ptrace.h b/arch/hexagon/include/uapi/asm/ptrace.h
index 8ef784047a74..1ffce0c6ee07 100644
--- a/arch/hexagon/include/uapi/asm/ptrace.h
+++ b/arch/hexagon/include/uapi/asm/ptrace.h
@@ -32,4 +32,8 @@
extern int regs_query_register_offset(const char *name);
extern const char *regs_query_register_name(unsigned int offset);
+#define current_pt_regs() \
+ ((struct pt_regs *) \
+ ((unsigned long)current_thread_info() + THREAD_SIZE) - 1)
+
#endif
diff --git a/arch/hexagon/include/uapi/asm/unistd.h b/arch/hexagon/include/uapi/asm/unistd.h
index 81312d6a52e6..26b2e0f909c8 100644
--- a/arch/hexagon/include/uapi/asm/unistd.h
+++ b/arch/hexagon/include/uapi/asm/unistd.h
@@ -27,5 +27,6 @@
*/
#define sys_mmap2 sys_mmap_pgoff
+#define __ARCH_WANT_SYS_EXECVE
#include <asm-generic/unistd.h>
diff --git a/arch/hexagon/kernel/process.c b/arch/hexagon/kernel/process.c
index 9f6d7411b574..cfbc52bd5227 100644
--- a/arch/hexagon/kernel/process.c
+++ b/arch/hexagon/kernel/process.c
@@ -26,33 +26,6 @@
#include <linux/slab.h>
/*
- * Kernel thread creation. The desired kernel function is "wrapped"
- * in the kernel_thread_helper function, which does cleanup
- * afterwards.
- */
-static void __noreturn kernel_thread_helper(void *arg, int (*fn)(void *))
-{
- do_exit(fn(arg));
-}
-
-int kernel_thread(int (*fn)(void *), void *arg, unsigned long flags)
-{
- struct pt_regs regs;
-
- memset(&regs, 0, sizeof(regs));
- /*
- * Yes, we're exploting illicit knowledge of the ABI here.
- */
- regs.r00 = (unsigned long) arg;
- regs.r01 = (unsigned long) fn;
- pt_set_elr(&regs, (unsigned long)kernel_thread_helper);
- pt_set_kmode(&regs);
-
- return do_fork(flags|CLONE_VM|CLONE_UNTRACED, 0, &regs, 0, NULL, NULL);
-}
-EXPORT_SYMBOL(kernel_thread);
-
-/*
* Program thread launch. Often defined as a macro in processor.h,
* but we're shooting for a small footprint and it's not an inner-loop
* performance-critical operation.
@@ -114,7 +87,7 @@ unsigned long thread_saved_pc(struct task_struct *tsk)
* Copy architecture-specific thread state
*/
int copy_thread(unsigned long clone_flags, unsigned long usp,
- unsigned long unused, struct task_struct *p,
+ unsigned long arg, struct task_struct *p,
struct pt_regs *regs)
{
struct thread_info *ti = task_thread_info(p);
@@ -125,61 +98,50 @@ int copy_thread(unsigned long clone_flags, unsigned long usp,
childregs = (struct pt_regs *) (((unsigned long) ti + THREAD_SIZE) -
sizeof(*childregs));
- memcpy(childregs, regs, sizeof(*childregs));
ti->regs = childregs;
/*
* Establish kernel stack pointer and initial PC for new thread
+ * Note that unlike the usual situation, we do not copy the
+ * parent's callee-saved here; those are in pt_regs and whatever
+ * we leave here will be overridden on return to userland.
*/
ss = (struct hexagon_switch_stack *) ((unsigned long) childregs -
sizeof(*ss));
ss->lr = (unsigned long)ret_from_fork;
p->thread.switch_sp = ss;
-
- /* If User mode thread, set pt_reg stack pointer as per parameter */
- if (user_mode(childregs)) {
- pt_set_rte_sp(childregs, usp);
-
- /* Child sees zero return value */
- childregs->r00 = 0;
-
- /*
- * The clone syscall has the C signature:
- * int [r0] clone(int flags [r0],
- * void *child_frame [r1],
- * void *parent_tid [r2],
- * void *child_tid [r3],
- * void *thread_control_block [r4]);
- * ugp is used to provide TLS support.
- */
- if (clone_flags & CLONE_SETTLS)
- childregs->ugp = childregs->r04;
-
- /*
- * Parent sees new pid -- not necessary, not even possible at
- * this point in the fork process
- * Might also want to set things like ti->addr_limit
- */
- } else {
- /*
- * If kernel thread, resume stack is kernel stack base.
- * Note that this is pointer arithmetic on pt_regs *
- */
- pt_set_rte_sp(childregs, (unsigned long)(childregs + 1));
- /*
- * We need the current thread_info fast path pointer
- * set up in pt_regs. The register to be used is
- * parametric for assembler code, but the mechanism
- * doesn't drop neatly into C. Needs to be fixed.
- */
- childregs->THREADINFO_REG = (unsigned long) ti;
+ if (unlikely(p->flags & PF_KTHREAD)) {
+ memset(childregs, 0, sizeof(struct pt_regs));
+ /* r24 <- fn, r25 <- arg */
+ ss->r2524 = usp | ((u64)arg << 32);
+ pt_set_kmode(childregs);
+ return 0;
}
+ memcpy(childregs, regs, sizeof(*childregs));
+ ss->r2524 = 0;
+
+ pt_set_rte_sp(childregs, usp);
+
+ /* Child sees zero return value */
+ childregs->r00 = 0;
+
+ /*
+ * The clone syscall has the C signature:
+ * int [r0] clone(int flags [r0],
+ * void *child_frame [r1],
+ * void *parent_tid [r2],
+ * void *child_tid [r3],
+ * void *thread_control_block [r4]);
+ * ugp is used to provide TLS support.
+ */
+ if (clone_flags & CLONE_SETTLS)
+ childregs->ugp = childregs->r04;
/*
- * thread_info pointer is pulled out of task_struct "stack"
- * field on switch_to.
+ * Parent sees new pid -- not necessary, not even possible at
+ * this point in the fork process
+ * Might also want to set things like ti->addr_limit
*/
- p->stack = (void *)ti;
return 0;
}
diff --git a/arch/hexagon/kernel/signal.c b/arch/hexagon/kernel/signal.c
index 5047b8b879c0..fe0d1373165d 100644
--- a/arch/hexagon/kernel/signal.c
+++ b/arch/hexagon/kernel/signal.c
@@ -249,14 +249,14 @@ void do_notify_resume(struct pt_regs *regs, unsigned long thread_info_flags)
*/
asmlinkage int sys_sigaltstack(const stack_t __user *uss, stack_t __user *uoss)
{
- struct pt_regs *regs = current_thread_info()->regs;
+ struct pt_regs *regs = current_pt_regs();
return do_sigaltstack(uss, uoss, regs->r29);
}
asmlinkage int sys_rt_sigreturn(void)
{
- struct pt_regs *regs = current_thread_info()->regs;
+ struct pt_regs *regs = current_pt_regs();
struct rt_sigframe __user *frame;
sigset_t blocked;
diff --git a/arch/hexagon/kernel/syscall.c b/arch/hexagon/kernel/syscall.c
index 319fa6494f58..d2cc3270af3e 100644
--- a/arch/hexagon/kernel/syscall.c
+++ b/arch/hexagon/kernel/syscall.c
@@ -35,55 +35,13 @@
* See signal.c for signal-related system call wrappers.
*/
-asmlinkage int sys_execve(char __user *ufilename,
- const char __user *const __user *argv,
- const char __user *const __user *envp)
-{
- struct pt_regs *pregs = current_thread_info()->regs;
- struct filename *filename;
- int retval;
-
- filename = getname(ufilename);
- retval = PTR_ERR(filename);
- if (IS_ERR(filename))
- return retval;
-
- retval = do_execve(filename->name, argv, envp, pregs);
- putname(filename);
-
- return retval;
-}
-
asmlinkage int sys_clone(unsigned long clone_flags, unsigned long newsp,
unsigned long parent_tidp, unsigned long child_tidp)
{
- struct pt_regs *pregs = current_thread_info()->regs;
+ struct pt_regs *pregs = current_pt_regs();
if (!newsp)
newsp = pregs->SP;
return do_fork(clone_flags, newsp, pregs, 0, (int __user *)parent_tidp,
(int __user *)child_tidp);
}
-
-/*
- * Do a system call from the kernel, so as to have a proper pt_regs
- * and recycle the sys_execvpe infrustructure.
- */
-int kernel_execve(const char *filename,
- const char *const argv[], const char *const envp[])
-{
- register unsigned long __a0 asm("r0") = (unsigned long) filename;
- register unsigned long __a1 asm("r1") = (unsigned long) argv;
- register unsigned long __a2 asm("r2") = (unsigned long) envp;
- int retval;
-
- __asm__ volatile(
- " R6 = #%4;\n"
- " trap0(#1);\n"
- " %0 = R0;\n"
- : "=r" (retval)
- : "r" (__a0), "r" (__a1), "r" (__a2), "i" (__NR_execve)
- );
-
- return retval;
-}
diff --git a/arch/hexagon/kernel/vm_entry.S b/arch/hexagon/kernel/vm_entry.S
index cd71673ac259..425e50c694f7 100644
--- a/arch/hexagon/kernel/vm_entry.S
+++ b/arch/hexagon/kernel/vm_entry.S
@@ -266,4 +266,8 @@ _K_enter_machcheck:
.globl ret_from_fork
ret_from_fork:
call schedule_tail
+ P0 = cmp.eq(R24, #0);
+ if P0 jump return_from_syscall
+ R0 = R25;
+ callr R24
jump return_from_syscall
diff --git a/arch/ia64/Kconfig b/arch/ia64/Kconfig
index 3279646120e3..670600468128 100644
--- a/arch/ia64/Kconfig
+++ b/arch/ia64/Kconfig
@@ -42,6 +42,8 @@ config IA64
select GENERIC_TIME_VSYSCALL_OLD
select HAVE_MOD_ARCH_SPECIFIC
select MODULES_USE_ELF_RELA
+ select GENERIC_KERNEL_THREAD
+ select GENERIC_KERNEL_EXECVE
default y
help
The Itanium Processor Family is Intel's 64-bit successor to
diff --git a/arch/ia64/include/asm/processor.h b/arch/ia64/include/asm/processor.h
index 944152a50912..e0a899a1a8a6 100644
--- a/arch/ia64/include/asm/processor.h
+++ b/arch/ia64/include/asm/processor.h
@@ -340,22 +340,6 @@ struct task_struct;
*/
#define release_thread(dead_task)
-/*
- * This is the mechanism for creating a new kernel thread.
- *
- * NOTE 1: Only a kernel-only process (ie the swapper or direct
- * descendants who haven't done an "execve()") should use this: it
- * will work within a system call from a "real" process, but the
- * process memory space will not be free'd until both the parent and
- * the child have exited.
- *
- * NOTE 2: This MUST NOT be an inlined function. Otherwise, we get
- * into trouble in init/main.c when the child thread returns to
- * do_basic_setup() and the timing is such that free_initmem() has
- * been called already.
- */
-extern pid_t kernel_thread (int (*fn)(void *), void *arg, unsigned long flags);
-
/* Get wait channel for task P. */
extern unsigned long get_wchan (struct task_struct *p);
diff --git a/arch/ia64/include/asm/unistd.h b/arch/ia64/include/asm/unistd.h
index 8b3ff2f5b861..1574bca86138 100644
--- a/arch/ia64/include/asm/unistd.h
+++ b/arch/ia64/include/asm/unistd.h
@@ -29,6 +29,7 @@
#define __ARCH_WANT_SYS_RT_SIGACTION
#define __ARCH_WANT_SYS_RT_SIGSUSPEND
+#define __ARCH_WANT_SYS_EXECVE
#if !defined(__ASSEMBLY__) && !defined(ASSEMBLER)
diff --git a/arch/ia64/kernel/entry.S b/arch/ia64/kernel/entry.S
index 1ccbe12a4d84..940a67263629 100644
--- a/arch/ia64/kernel/entry.S
+++ b/arch/ia64/kernel/entry.S
@@ -61,14 +61,13 @@ ENTRY(ia64_execve)
* Allocate 8 input registers since ptrace() may clobber them
*/
.prologue ASM_UNW_PRLG_RP|ASM_UNW_PRLG_PFS, ASM_UNW_PRLG_GRSAVE(8)
- alloc loc1=ar.pfs,8,2,4,0
+ alloc loc1=ar.pfs,8,2,3,0
mov loc0=rp
.body
mov out0=in0 // filename
;; // stop bit between alloc and call
mov out1=in1 // argv
mov out2=in2 // envp
- add out3=16,sp // regs
br.call.sptk.many rp=sys_execve
.ret0:
cmp4.ge p6,p7=r8,r0
@@ -76,7 +75,6 @@ ENTRY(ia64_execve)
sxt4 r8=r8 // return 64-bit result
;;
stf.spill [sp]=f0
-(p6) cmp.ne pKStk,pUStk=r0,r0 // a successful execve() lands us in user-mode...
mov rp=loc0
(p6) mov ar.pfs=r0 // clear ar.pfs on success
(p7) br.ret.sptk.many rp
@@ -484,19 +482,6 @@ GLOBAL_ENTRY(prefetch_stack)
br.ret.sptk.many rp
END(prefetch_stack)
-GLOBAL_ENTRY(kernel_execve)
- rum psr.ac
- mov r15=__NR_execve // put syscall number in place
- break __BREAK_SYSCALL
- br.ret.sptk.many rp
-END(kernel_execve)
-
-GLOBAL_ENTRY(clone)
- mov r15=__NR_clone // put syscall number in place
- break __BREAK_SYSCALL
- br.ret.sptk.many rp
-END(clone)
-
/*
* Invoke a system call, but do some tracing before and after the call.
* We MUST preserve the current register frame throughout this routine
@@ -600,6 +585,27 @@ GLOBAL_ENTRY(ia64_strace_leave_kernel)
.ret4: br.cond.sptk ia64_leave_kernel
END(ia64_strace_leave_kernel)
+ENTRY(call_payload)
+ .prologue ASM_UNW_PRLG_RP|ASM_UNW_PRLG_PFS, ASM_UNW_PRLG_GRSAVE(0)
+ /* call the kernel_thread payload; fn is in r4, arg - in r5 */
+ alloc loc1=ar.pfs,0,3,1,0
+ mov loc0=rp
+ mov loc2=gp
+ mov out0=r5 // arg
+ ld8 r14 = [r4], 8 // fn.address
+ ;;
+ mov b6 = r14
+ ld8 gp = [r4] // fn.gp
+ ;;
+ br.call.sptk.many rp=b6 // fn(arg)
+.ret12: mov gp=loc2
+ mov rp=loc0
+ mov ar.pfs=loc1
+ /* ... and if it has returned, we are going to userland */
+ cmp.ne pKStk,pUStk=r0,r0
+ br.ret.sptk.many rp
+END(call_payload)
+
GLOBAL_ENTRY(ia64_ret_from_clone)
PT_REGS_UNWIND_INFO(0)
{ /*
@@ -616,6 +622,7 @@ GLOBAL_ENTRY(ia64_ret_from_clone)
br.call.sptk.many rp=ia64_invoke_schedule_tail
}
.ret8:
+(pKStk) br.call.sptk.many rp=call_payload
adds r2=TI_FLAGS+IA64_TASK_SIZE,r13
;;
ld4 r2=[r2]
diff --git a/arch/ia64/kernel/head.S b/arch/ia64/kernel/head.S
index 629a250f7c19..4738ff7bd66a 100644
--- a/arch/ia64/kernel/head.S
+++ b/arch/ia64/kernel/head.S
@@ -1093,19 +1093,6 @@ GLOBAL_ENTRY(cycle_to_cputime)
END(cycle_to_cputime)
#endif /* CONFIG_VIRT_CPU_ACCOUNTING */
-GLOBAL_ENTRY(start_kernel_thread)
- .prologue
- .save rp, r0 // this is the end of the call-chain
- .body
- alloc r2 = ar.pfs, 0, 0, 2, 0
- mov out0 = r9
- mov out1 = r11;;
- br.call.sptk.many rp = kernel_thread_helper;;
- mov out0 = r8
- br.call.sptk.many rp = sys_exit;;
-1: br.sptk.few 1b // not reached
-END(start_kernel_thread)
-
#ifdef CONFIG_IA64_BRL_EMU
/*
diff --git a/arch/ia64/kernel/process.c b/arch/ia64/kernel/process.c
index 35e106f2ed13..25543a295ad9 100644
--- a/arch/ia64/kernel/process.c
+++ b/arch/ia64/kernel/process.c
@@ -401,64 +401,15 @@ copy_thread(unsigned long clone_flags,
struct pt_regs *child_ptregs;
int retval = 0;
-#ifdef CONFIG_SMP
- /*
- * For SMP idle threads, fork_by_hand() calls do_fork with
- * NULL regs.
- */
- if (!regs)
- return 0;
-#endif
-
- stack = ((struct switch_stack *) regs) - 1;
-
child_ptregs = (struct pt_regs *) ((unsigned long) p + IA64_STK_OFFSET) - 1;
child_stack = (struct switch_stack *) child_ptregs - 1;
- /* copy parent's switch_stack & pt_regs to child: */
- memcpy(child_stack, stack, sizeof(*child_ptregs) + sizeof(*child_stack));
-
rbs = (unsigned long) current + IA64_RBS_OFFSET;
child_rbs = (unsigned long) p + IA64_RBS_OFFSET;
- rbs_size = stack->ar_bspstore - rbs;
-
- /* copy the parent's register backing store to the child: */
- memcpy((void *) child_rbs, (void *) rbs, rbs_size);
-
- if (likely(user_mode(child_ptregs))) {
- if (clone_flags & CLONE_SETTLS)
- child_ptregs->r13 = regs->r16; /* see sys_clone2() in entry.S */
- if (user_stack_base) {
- child_ptregs->r12 = user_stack_base + user_stack_size - 16;
- child_ptregs->ar_bspstore = user_stack_base;
- child_ptregs->ar_rnat = 0;
- child_ptregs->loadrs = 0;
- }
- } else {
- /*
- * Note: we simply preserve the relative position of
- * the stack pointer here. There is no need to
- * allocate a scratch area here, since that will have
- * been taken care of by the caller of sys_clone()
- * already.
- */
- child_ptregs->r12 = (unsigned long) child_ptregs - 16; /* kernel sp */
- child_ptregs->r13 = (unsigned long) p; /* set `current' pointer */
- }
- child_stack->ar_bspstore = child_rbs + rbs_size;
- child_stack->b0 = (unsigned long) &ia64_ret_from_clone;
/* copy parts of thread_struct: */
p->thread.ksp = (unsigned long) child_stack - 16;
- /* stop some PSR bits from being inherited.
- * the psr.up/psr.pp bits must be cleared on fork but inherited on execve()
- * therefore we must specify them explicitly here and not include them in
- * IA64_PSR_BITS_TO_CLEAR.
- */
- child_ptregs->cr_ipsr = ((child_ptregs->cr_ipsr | IA64_PSR_BITS_TO_SET)
- & ~(IA64_PSR_BITS_TO_CLEAR | IA64_PSR_PP | IA64_PSR_UP));
-
/*
* NOTE: The calling convention considers all floating point
* registers in the high partition (fph) to be scratch. Since
@@ -480,8 +431,66 @@ copy_thread(unsigned long clone_flags,
# define THREAD_FLAGS_TO_SET 0
p->thread.flags = ((current->thread.flags & ~THREAD_FLAGS_TO_CLEAR)
| THREAD_FLAGS_TO_SET);
+
ia64_drop_fpu(p); /* don't pick up stale state from a CPU's fph */
+ if (unlikely(p->flags & PF_KTHREAD)) {
+ if (unlikely(!user_stack_base)) {
+ /* fork_idle() called us */
+ return 0;
+ }
+ memset(child_stack, 0, sizeof(*child_ptregs) + sizeof(*child_stack));
+ child_stack->r4 = user_stack_base; /* payload */
+ child_stack->r5 = user_stack_size; /* argument */
+ /*
+ * Preserve PSR bits, except for bits 32-34 and 37-45,
+ * which we can't read.
+ */
+ child_ptregs->cr_ipsr = ia64_getreg(_IA64_REG_PSR) | IA64_PSR_BN;
+ /* mark as valid, empty frame */
+ child_ptregs->cr_ifs = 1UL << 63;
+ child_stack->ar_fpsr = child_ptregs->ar_fpsr
+ = ia64_getreg(_IA64_REG_AR_FPSR);
+ child_stack->pr = (1 << PRED_KERNEL_STACK);
+ child_stack->ar_bspstore = child_rbs;
+ child_stack->b0 = (unsigned long) &ia64_ret_from_clone;
+
+ /* stop some PSR bits from being inherited.
+ * the psr.up/psr.pp bits must be cleared on fork but inherited on execve()
+ * therefore we must specify them explicitly here and not include them in
+ * IA64_PSR_BITS_TO_CLEAR.
+ */
+ child_ptregs->cr_ipsr = ((child_ptregs->cr_ipsr | IA64_PSR_BITS_TO_SET)
+ & ~(IA64_PSR_BITS_TO_CLEAR | IA64_PSR_PP | IA64_PSR_UP));
+
+ return 0;
+ }
+ stack = ((struct switch_stack *) regs) - 1;
+ /* copy parent's switch_stack & pt_regs to child: */
+ memcpy(child_stack, stack, sizeof(*child_ptregs) + sizeof(*child_stack));
+
+ /* copy the parent's register backing store to the child: */
+ rbs_size = stack->ar_bspstore - rbs;
+ memcpy((void *) child_rbs, (void *) rbs, rbs_size);
+ if (clone_flags & CLONE_SETTLS)
+ child_ptregs->r13 = regs->r16; /* see sys_clone2() in entry.S */
+ if (user_stack_base) {
+ child_ptregs->r12 = user_stack_base + user_stack_size - 16;
+ child_ptregs->ar_bspstore = user_stack_base;
+ child_ptregs->ar_rnat = 0;
+ child_ptregs->loadrs = 0;
+ }
+ child_stack->ar_bspstore = child_rbs + rbs_size;
+ child_stack->b0 = (unsigned long) &ia64_ret_from_clone;
+
+ /* stop some PSR bits from being inherited.
+ * the psr.up/psr.pp bits must be cleared on fork but inherited on execve()
+ * therefore we must specify them explicitly here and not include them in
+ * IA64_PSR_BITS_TO_CLEAR.
+ */
+ child_ptregs->cr_ipsr = ((child_ptregs->cr_ipsr | IA64_PSR_BITS_TO_SET)
+ & ~(IA64_PSR_BITS_TO_CLEAR | IA64_PSR_PP | IA64_PSR_UP));
+
#ifdef CONFIG_PERFMON
if (current->thread.pfm_context)
pfm_inherit(p, child_ptregs);
@@ -608,57 +617,6 @@ dump_fpu (struct pt_regs *pt, elf_fpregset_t dst)
return 1; /* f0-f31 are always valid so we always return 1 */
}
-long
-sys_execve (const char __user *filename,
- const char __user *const __user *argv,
- const char __user *const __user *envp,
- struct pt_regs *regs)
-{
- struct filename *fname;
- int error;
-
- fname = getname(filename);
- error = PTR_ERR(fname);
- if (IS_ERR(fname))
- goto out;
- error = do_execve(fname->name, argv, envp, regs);
- putname(fname);
-out:
- return error;
-}
-
-pid_t
-kernel_thread (int (*fn)(void *), void *arg, unsigned long flags)
-{
- extern void start_kernel_thread (void);
- unsigned long *helper_fptr = (unsigned long *) &start_kernel_thread;
- struct {
- struct switch_stack sw;
- struct pt_regs pt;
- } regs;
-
- memset(&regs, 0, sizeof(regs));
- regs.pt.cr_iip = helper_fptr[0]; /* set entry point (IP) */
- regs.pt.r1 = helper_fptr[1]; /* set GP */
- regs.pt.r9 = (unsigned long) fn; /* 1st argument */
- regs.pt.r11 = (unsigned long) arg; /* 2nd argument */
- /* Preserve PSR bits, except for bits 32-34 and 37-45, which we can't read. */
- regs.pt.cr_ipsr = ia64_getreg(_IA64_REG_PSR) | IA64_PSR_BN;
- regs.pt.cr_ifs = 1UL << 63; /* mark as valid, empty frame */
- regs.sw.ar_fpsr = regs.pt.ar_fpsr = ia64_getreg(_IA64_REG_AR_FPSR);
- regs.sw.ar_bspstore = (unsigned long) current + IA64_RBS_OFFSET;
- regs.sw.pr = (1 << PRED_KERNEL_STACK);
- return do_fork(flags | CLONE_VM | CLONE_UNTRACED, 0, &regs.pt, 0, NULL, NULL);
-}
-EXPORT_SYMBOL(kernel_thread);
-
-/* This gets called from kernel_thread() via ia64_invoke_thread_helper(). */
-int
-kernel_thread_helper (int (*fn)(void *), void *arg)
-{
- return (*fn)(arg);
-}
-
/*
* Flush thread state. This is called when a thread does an execve().
*/
diff --git a/arch/m68k/Kconfig b/arch/m68k/Kconfig
index e7c161433eae..953a7ba5d050 100644
--- a/arch/m68k/Kconfig
+++ b/arch/m68k/Kconfig
@@ -16,6 +16,7 @@ config M68K
select ARCH_WANT_IPC_PARSE_VERSION
select ARCH_USES_GETTIMEOFFSET if MMU && !COLDFIRE
select GENERIC_KERNEL_THREAD
+ select GENERIC_KERNEL_EXECVE
select HAVE_MOD_ARCH_SPECIFIC
select MODULES_USE_ELF_REL
select MODULES_USE_ELF_RELA
diff --git a/arch/m68k/include/asm/unistd.h b/arch/m68k/include/asm/unistd.h
index 5fc7f7bec1c8..0aa165405966 100644
--- a/arch/m68k/include/asm/unistd.h
+++ b/arch/m68k/include/asm/unistd.h
@@ -32,7 +32,6 @@
#define __ARCH_WANT_SYS_RT_SIGACTION
#define __ARCH_WANT_SYS_RT_SIGSUSPEND
#define __ARCH_WANT_SYS_EXECVE
-#define __ARCH_WANT_KERNEL_EXECVE
/*
* "Conditional" syscalls
diff --git a/arch/m68k/kernel/entry.S b/arch/m68k/kernel/entry.S
index 946cb0187751..45b2f293f8cf 100644
--- a/arch/m68k/kernel/entry.S
+++ b/arch/m68k/kernel/entry.S
@@ -115,16 +115,9 @@ ENTRY(ret_from_kernel_thread)
| a3 contains the kernel thread payload, d7 - its argument
movel %d1,%sp@-
jsr schedule_tail
- GET_CURRENT(%d0)
movel %d7,(%sp)
jsr %a3@
addql #4,%sp
- movel %d0,(%sp)
- jra sys_exit
-
-ENTRY(ret_from_kernel_execve)
- movel 4(%sp), %sp
- GET_CURRENT(%d0)
jra ret_from_exception
#if defined(CONFIG_COLDFIRE) || !defined(CONFIG_MMU)
diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig
index dba9390d37cf..4183e62f178c 100644
--- a/arch/mips/Kconfig
+++ b/arch/mips/Kconfig
@@ -40,6 +40,8 @@ config MIPS
select HAVE_MOD_ARCH_SPECIFIC
select MODULES_USE_ELF_REL
select MODULES_USE_ELF_RELA if 64BIT
+ select GENERIC_KERNEL_THREAD
+ select GENERIC_KERNEL_EXECVE
menu "Machine selection"
diff --git a/arch/mips/include/asm/processor.h b/arch/mips/include/asm/processor.h
index 5e33fabe354d..d28c41e0887c 100644
--- a/arch/mips/include/asm/processor.h
+++ b/arch/mips/include/asm/processor.h
@@ -310,8 +310,6 @@ struct task_struct;
/* Free all resources held by a thread. */
#define release_thread(thread) do { } while(0)
-extern long kernel_thread(int (*fn)(void *), void * arg, unsigned long flags);
-
extern unsigned long thread_saved_pc(struct task_struct *tsk);
/*
diff --git a/arch/mips/include/asm/ptrace.h b/arch/mips/include/asm/ptrace.h
index 4f5da948a777..cec5e125f7e4 100644
--- a/arch/mips/include/asm/ptrace.h
+++ b/arch/mips/include/asm/ptrace.h
@@ -61,4 +61,10 @@ static inline void die_if_kernel(const char *str, struct pt_regs *regs)
die(str, regs);
}
+#define current_pt_regs() \
+({ \
+ unsigned long sp = (unsigned long)__builtin_frame_address(0); \
+ (struct pt_regs *)((sp | (THREAD_SIZE - 1)) + 1 - 32) - 1; \
+})
+
#endif /* _ASM_PTRACE_H */
diff --git a/arch/mips/include/asm/unistd.h b/arch/mips/include/asm/unistd.h
index 9e47cc11aa26..b306e2081cad 100644
--- a/arch/mips/include/asm/unistd.h
+++ b/arch/mips/include/asm/unistd.h
@@ -20,6 +20,7 @@
#define __ARCH_OMIT_COMPAT_SYS_GETDENTS64
#define __ARCH_WANT_OLD_READDIR
#define __ARCH_WANT_SYS_ALARM
+#define __ARCH_WANT_SYS_EXECVE
#define __ARCH_WANT_SYS_GETHOSTNAME
#define __ARCH_WANT_SYS_IPC
#define __ARCH_WANT_SYS_PAUSE
diff --git a/arch/mips/kernel/entry.S b/arch/mips/kernel/entry.S
index a6c133212003..3320cb4ac1d4 100644
--- a/arch/mips/kernel/entry.S
+++ b/arch/mips/kernel/entry.S
@@ -65,6 +65,12 @@ need_resched:
b need_resched
#endif
+FEXPORT(ret_from_kernel_thread)
+ jal schedule_tail # a0 = struct task_struct *prev
+ move a0, s1
+ jal s0
+ j syscall_exit
+
FEXPORT(ret_from_fork)
jal schedule_tail # a0 = struct task_struct *prev
diff --git a/arch/mips/kernel/linux32.c b/arch/mips/kernel/linux32.c
index 3a21acedf882..8796dbc7e358 100644
--- a/arch/mips/kernel/linux32.c
+++ b/arch/mips/kernel/linux32.c
@@ -3,7 +3,6 @@
*
* Copyright (C) 2000 Silicon Graphics, Inc.
* Written by Ulf Carlsson (ulfc@engr.sgi.com)
- * sys32_execve from ia64/ia32 code, Feb 2000, Kanoj Sarcar (kanoj@sgi.com)
*/
#include <linux/compiler.h>
#include <linux/mm.h>
@@ -77,26 +76,6 @@ out:
return error;
}
-/*
- * sys_execve() executes a new program.
- */
-asmlinkage int sys32_execve(nabi_no_regargs struct pt_regs regs)
-{
- int error;
- struct filename *filename;
-
- filename = getname(compat_ptr(regs.regs[4]));
- error = PTR_ERR(filename);
- if (IS_ERR(filename))
- goto out;
- error = compat_do_execve(filename->name, compat_ptr(regs.regs[5]),
- compat_ptr(regs.regs[6]), &regs);
- putname(filename);
-
-out:
- return error;
-}
-
#define RLIM_INFINITY32 0x7fffffff
#define RESOURCE32(x) ((x > RLIM_INFINITY32) ? RLIM_INFINITY32 : x)
diff --git a/arch/mips/kernel/mips_ksyms.c b/arch/mips/kernel/mips_ksyms.c
index 3fc1691110dc..2d9304c2b54c 100644
--- a/arch/mips/kernel/mips_ksyms.c
+++ b/arch/mips/kernel/mips_ksyms.c
@@ -32,8 +32,6 @@ EXPORT_SYMBOL(memset);
EXPORT_SYMBOL(memcpy);
EXPORT_SYMBOL(memmove);
-EXPORT_SYMBOL(kernel_thread);
-
/*
* Functions that operate on entire pages. Mostly used by memory management.
*/
diff --git a/arch/mips/kernel/process.c b/arch/mips/kernel/process.c
index e9a5fd7277f4..d13720ac656f 100644
--- a/arch/mips/kernel/process.c
+++ b/arch/mips/kernel/process.c
@@ -84,6 +84,7 @@ void __noreturn cpu_idle(void)
}
asmlinkage void ret_from_fork(void);
+asmlinkage void ret_from_kernel_thread(void);
void start_thread(struct pt_regs * regs, unsigned long pc, unsigned long sp)
{
@@ -113,7 +114,7 @@ void flush_thread(void)
}
int copy_thread(unsigned long clone_flags, unsigned long usp,
- unsigned long unused, struct task_struct *p, struct pt_regs *regs)
+ unsigned long arg, struct task_struct *p, struct pt_regs *regs)
{
struct thread_info *ti = task_thread_info(p);
struct pt_regs *childregs;
@@ -136,19 +137,30 @@ int copy_thread(unsigned long clone_flags, unsigned long usp,
childregs = (struct pt_regs *) childksp - 1;
/* Put the stack after the struct pt_regs. */
childksp = (unsigned long) childregs;
+ p->thread.cp0_status = read_c0_status() & ~(ST0_CU2|ST0_CU1);
+ if (unlikely(p->flags & PF_KTHREAD)) {
+ unsigned long status = p->thread.cp0_status;
+ memset(childregs, 0, sizeof(struct pt_regs));
+ ti->addr_limit = KERNEL_DS;
+ p->thread.reg16 = usp; /* fn */
+ p->thread.reg17 = arg;
+ p->thread.reg29 = childksp;
+ p->thread.reg31 = (unsigned long) ret_from_kernel_thread;
+#if defined(CONFIG_CPU_R3000) || defined(CONFIG_CPU_TX39XX)
+ status = (status & ~(ST0_KUP | ST0_IEP | ST0_IEC)) |
+ ((status & (ST0_KUC | ST0_IEC)) << 2);
+#else
+ status |= ST0_EXL;
+#endif
+ childregs->cp0_status = status;
+ return 0;
+ }
*childregs = *regs;
childregs->regs[7] = 0; /* Clear error flag */
-
childregs->regs[2] = 0; /* Child gets zero as return value */
+ childregs->regs[29] = usp;
+ ti->addr_limit = USER_DS;
- if (childregs->cp0_status & ST0_CU0) {
- childregs->regs[28] = (unsigned long) ti;
- childregs->regs[29] = childksp;
- ti->addr_limit = KERNEL_DS;
- } else {
- childregs->regs[29] = usp;
- ti->addr_limit = USER_DS;
- }
p->thread.reg29 = (unsigned long) childregs;
p->thread.reg31 = (unsigned long) ret_from_fork;
@@ -156,7 +168,6 @@ int copy_thread(unsigned long clone_flags, unsigned long usp,
* New tasks lose permission to use the fpu. This accelerates context
* switching for most programs since they don't use the fpu.
*/
- p->thread.cp0_status = read_c0_status() & ~(ST0_CU2|ST0_CU1);
childregs->cp0_status &= ~(ST0_CU2|ST0_CU1);
#ifdef CONFIG_MIPS_MT_SMTC
@@ -222,35 +233,6 @@ int dump_task_fpu(struct task_struct *t, elf_fpregset_t *fpr)
}
/*
- * Create a kernel thread
- */
-static void __noreturn kernel_thread_helper(void *arg, int (*fn)(void *))
-{
- do_exit(fn(arg));
-}
-
-long kernel_thread(int (*fn)(void *), void *arg, unsigned long flags)
-{
- struct pt_regs regs;
-
- memset(&regs, 0, sizeof(regs));
-
- regs.regs[4] = (unsigned long) arg;
- regs.regs[5] = (unsigned long) fn;
- regs.cp0_epc = (unsigned long) kernel_thread_helper;
- regs.cp0_status = read_c0_status();
-#if defined(CONFIG_CPU_R3000) || defined(CONFIG_CPU_TX39XX)
- regs.cp0_status = (regs.cp0_status & ~(ST0_KUP | ST0_IEP | ST0_IEC)) |
- ((regs.cp0_status & (ST0_KUC | ST0_IEC)) << 2);
-#else
- regs.cp0_status |= ST0_EXL;
-#endif
-
- /* Ok, create the new process.. */
- return do_fork(flags | CLONE_VM | CLONE_UNTRACED, 0, &regs, 0, NULL, NULL);
-}
-
-/*
*
*/
struct mips_frame_info {
diff --git a/arch/mips/kernel/scall64-n32.S b/arch/mips/kernel/scall64-n32.S
index f6ba8381ee01..d27ca340d46d 100644
--- a/arch/mips/kernel/scall64-n32.S
+++ b/arch/mips/kernel/scall64-n32.S
@@ -167,7 +167,7 @@ EXPORT(sysn32_call_table)
PTR sys_getsockopt
PTR sys_clone /* 6055 */
PTR sys_fork
- PTR sys32_execve
+ PTR compat_sys_execve
PTR sys_exit
PTR compat_sys_wait4
PTR sys_kill /* 6060 */
diff --git a/arch/mips/kernel/scall64-o32.S b/arch/mips/kernel/scall64-o32.S
index 53c2d7245764..9601be6afa3d 100644
--- a/arch/mips/kernel/scall64-o32.S
+++ b/arch/mips/kernel/scall64-o32.S
@@ -203,7 +203,7 @@ sys_call_table:
PTR sys_creat
PTR sys_link
PTR sys_unlink /* 4010 */
- PTR sys32_execve
+ PTR compat_sys_execve
PTR sys_chdir
PTR compat_sys_time
PTR sys_mknod
diff --git a/arch/mips/kernel/syscall.c b/arch/mips/kernel/syscall.c
index 2bd561bc05ae..c611e2df7767 100644
--- a/arch/mips/kernel/syscall.c
+++ b/arch/mips/kernel/syscall.c
@@ -127,28 +127,6 @@ _sys_clone(nabi_no_regargs struct pt_regs regs)
parent_tidptr, child_tidptr);
}
-/*
- * sys_execve() executes a new program.
- */
-asmlinkage int sys_execve(nabi_no_regargs struct pt_regs regs)
-{
- int error;
- struct filename *filename;
-
- filename = getname((const char __user *) (long)regs.regs[4]);
- error = PTR_ERR(filename);
- if (IS_ERR(filename))
- goto out;
- error = do_execve(filename->name,
- (const char __user *const __user *) (long)regs.regs[5],
- (const char __user *const __user *) (long)regs.regs[6],
- &regs);
- putname(filename);
-
-out:
- return error;
-}
-
SYSCALL_DEFINE1(set_thread_area, unsigned long, addr)
{
struct thread_info *ti = task_thread_info(current);
@@ -313,34 +291,3 @@ asmlinkage void bad_stack(void)
{
do_exit(SIGSEGV);
}
-
-/*
- * Do a system call from kernel instead of calling sys_execve so we
- * end up with proper pt_regs.
- */
-int kernel_execve(const char *filename,
- const char *const argv[],
- const char *const envp[])
-{
- register unsigned long __a0 asm("$4") = (unsigned long) filename;
- register unsigned long __a1 asm("$5") = (unsigned long) argv;
- register unsigned long __a2 asm("$6") = (unsigned long) envp;
- register unsigned long __a3 asm("$7");
- unsigned long __v0;
-
- __asm__ volatile (" \n"
- " .set noreorder \n"
- " li $2, %5 # __NR_execve \n"
- " syscall \n"
- " move %0, $2 \n"
- " .set reorder \n"
- : "=&r" (__v0), "=r" (__a3)
- : "r" (__a0), "r" (__a1), "r" (__a2), "i" (__NR_execve)
- : "$2", "$8", "$9", "$10", "$11", "$12", "$13", "$14", "$15", "$24",
- "memory");
-
- if (__a3 == 0)
- return __v0;
-
- return -__v0;
-}
diff --git a/arch/openrisc/Kconfig b/arch/openrisc/Kconfig
index 05f2ba41ff1a..e7f1a2993f78 100644
--- a/arch/openrisc/Kconfig
+++ b/arch/openrisc/Kconfig
@@ -22,6 +22,8 @@ config OPENRISC
select GENERIC_STRNCPY_FROM_USER
select GENERIC_STRNLEN_USER
select MODULES_USE_ELF_RELA
+ select GENERIC_KERNEL_THREAD
+ select GENERIC_KERNEL_EXECVE
config MMU
def_bool y
diff --git a/arch/openrisc/include/uapi/asm/unistd.h b/arch/openrisc/include/uapi/asm/unistd.h
index 437bdbb61b14..5db7bc0fa5a7 100644
--- a/arch/openrisc/include/uapi/asm/unistd.h
+++ b/arch/openrisc/include/uapi/asm/unistd.h
@@ -20,6 +20,8 @@
#define sys_mmap2 sys_mmap_pgoff
+#define __ARCH_WANT_SYS_EXECVE
+
#include <asm-generic/unistd.h>
#define __NR_or1k_atomic __NR_arch_specific_syscall
diff --git a/arch/openrisc/kernel/entry.S b/arch/openrisc/kernel/entry.S
index ddfcaa828b0e..c60a09df323f 100644
--- a/arch/openrisc/kernel/entry.S
+++ b/arch/openrisc/kernel/entry.S
@@ -894,6 +894,16 @@ ENTRY(ret_from_fork)
l.jal schedule_tail
l.nop
+ /* Check if we are a kernel thread */
+ l.sfeqi r20,0
+ l.bf 1f
+ l.nop
+
+ /* ...we are a kernel thread so invoke the requested callback */
+ l.jalr r20
+ l.or r3,r22,r0
+
+1:
/* _syscall_returns expect r11 to contain return value */
l.lwz r11,PT_GPR11(r1)
@@ -915,26 +925,6 @@ ENTRY(ret_from_fork)
l.j _syscall_return
l.nop
-/* Since syscalls don't save call-clobbered registers, the args to
- * kernel_thread_helper will need to be passed through callee-saved
- * registers and copied to the parameter registers when the thread
- * begins running.
- *
- * See arch/openrisc/kernel/process.c:
- * The args are passed as follows:
- * arg1 (r3) : passed in r20
- * arg2 (r4) : passed in r22
- */
-
-ENTRY(_kernel_thread_helper)
- l.or r3,r20,r0
- l.or r4,r22,r0
- l.movhi r31,hi(kernel_thread_helper)
- l.ori r31,r31,lo(kernel_thread_helper)
- l.jr r31
- l.nop
-
-
/* ========================================================[ switch ] === */
/*
@@ -1044,8 +1034,13 @@ ENTRY(_switch)
/* Unwind stack to pre-switch state */
l.addi r1,r1,(INT_FRAME_SIZE)
- /* Return via the link-register back to where we 'came from', where that can be
- * either schedule() or return_from_fork()... */
+ /* Return via the link-register back to where we 'came from', where
+ * that may be either schedule(), ret_from_fork(), or
+ * ret_from_kernel_thread(). If we are returning to a new thread,
+ * we are expected to have set up the arg to schedule_tail already,
+ * hence we do so here unconditionally:
+ */
+ l.lwz r3,TI_STACK(r3) /* Load 'prev' as schedule_tail arg */
l.jr r9
l.nop
@@ -1088,10 +1083,6 @@ ENTRY(sys_fork)
l.j _fork_save_extra_regs_and_call
l.addi r3,r1,0
-ENTRY(sys_execve)
- l.j _sys_execve
- l.addi r6,r1,0
-
ENTRY(sys_sigaltstack)
l.j _sys_sigaltstack
l.addi r5,r1,0
diff --git a/arch/openrisc/kernel/process.c b/arch/openrisc/kernel/process.c
index c35f3ab1a8d3..e0874b8e09e4 100644
--- a/arch/openrisc/kernel/process.c
+++ b/arch/openrisc/kernel/process.c
@@ -109,66 +109,82 @@ void release_thread(struct task_struct *dead_task)
*/
extern asmlinkage void ret_from_fork(void);
+/*
+ * copy_thread
+ * @clone_flags: flags
+ * @usp: user stack pointer or fn for kernel thread
+ * @arg: arg to fn for kernel thread; always NULL for userspace thread
+ * @p: the newly created task
+ * @regs: CPU context to copy for userspace thread; always NULL for kthread
+ *
+ * At the top of a newly initialized kernel stack are two stacked pt_reg
+ * structures. The first (topmost) is the userspace context of the thread.
+ * The second is the kernelspace context of the thread.
+ *
+ * A kernel thread will not be returning to userspace, so the topmost pt_regs
+ * struct can be uninitialized; it _does_ need to exist, though, because
+ * a kernel thread can become a userspace thread by doing a kernel_execve, in
+ * which case the topmost context will be initialized and used for 'returning'
+ * to userspace.
+ *
+ * The second pt_reg struct needs to be initialized to 'return' to
+ * ret_from_fork. A kernel thread will need to set r20 to the address of
+ * a function to call into (with arg in r22); userspace threads need to set
+ * r20 to NULL in which case ret_from_fork will just continue a return to
+ * userspace.
+ *
+ * A kernel thread 'fn' may return; this is effectively what happens when
+ * kernel_execve is called. In that case, the userspace pt_regs must have
+ * been initialized (which kernel_execve takes care of, see start_thread
+ * below); ret_from_fork will then continue its execution causing the
+ * 'kernel thread' to return to userspace as a userspace thread.
+ */
+
int
copy_thread(unsigned long clone_flags, unsigned long usp,
- unsigned long unused, struct task_struct *p, struct pt_regs *regs)
+ unsigned long arg, struct task_struct *p, struct pt_regs *regs)
{
- struct pt_regs *childregs;
+ struct pt_regs *userregs;
struct pt_regs *kregs;
unsigned long sp = (unsigned long)task_stack_page(p) + THREAD_SIZE;
- struct thread_info *ti;
unsigned long top_of_kernel_stack;
top_of_kernel_stack = sp;
p->set_child_tid = p->clear_child_tid = NULL;
- /* Copy registers */
- /* redzone */
- sp -= STACK_FRAME_OVERHEAD;
+ /* Locate userspace context on stack... */
+ sp -= STACK_FRAME_OVERHEAD; /* redzone */
sp -= sizeof(struct pt_regs);
- childregs = (struct pt_regs *)sp;
+ userregs = (struct pt_regs *) sp;
- /* Copy parent registers */
- *childregs = *regs;
+ /* ...and kernel context */
+ sp -= STACK_FRAME_OVERHEAD; /* redzone */
+ sp -= sizeof(struct pt_regs);
+ kregs = (struct pt_regs *)sp;
- if ((childregs->sr & SPR_SR_SM) == 1) {
- /* for kernel thread, set `current_thread_info'
- * and stackptr in new task
- */
- childregs->sp = (unsigned long)task_stack_page(p) + THREAD_SIZE;
- childregs->gpr[10] = (unsigned long)task_thread_info(p);
+ if (unlikely(p->flags & PF_KTHREAD)) {
+ memset(kregs, 0, sizeof(struct pt_regs));
+ kregs->gpr[20] = usp; /* fn, kernel thread */
+ kregs->gpr[22] = arg;
} else {
- childregs->sp = usp;
- }
-
- childregs->gpr[11] = 0; /* Result from fork() */
+ *userregs = *regs;
- /*
- * The way this works is that at some point in the future
- * some task will call _switch to switch to the new task.
- * That will pop off the stack frame created below and start
- * the new task running at ret_from_fork. The new task will
- * do some house keeping and then return from the fork or clone
- * system call, using the stack frame created above.
- */
- /* redzone */
- sp -= STACK_FRAME_OVERHEAD;
- sp -= sizeof(struct pt_regs);
- kregs = (struct pt_regs *)sp;
+ userregs->sp = usp;
+ userregs->gpr[11] = 0; /* Result from fork() */
- ti = task_thread_info(p);
- ti->ksp = sp;
+ kregs->gpr[20] = 0; /* Userspace thread */
+ }
- /* kregs->sp must store the location of the 'pre-switch' kernel stack
- * pointer... for a newly forked process, this is simply the top of
- * the kernel stack.
+ /*
+ * _switch wants the kernel stack page in pt_regs->sp so that it
+ * can restore it to thread_info->ksp... see _switch for details.
*/
kregs->sp = top_of_kernel_stack;
- kregs->gpr[3] = (unsigned long)current; /* arg to schedule_tail */
- kregs->gpr[10] = (unsigned long)task_thread_info(p);
kregs->gpr[9] = (unsigned long)ret_from_fork;
+ task_thread_info(p)->ksp = (unsigned long)kregs;
+
return 0;
}
@@ -177,16 +193,14 @@ copy_thread(unsigned long clone_flags, unsigned long usp,
*/
void start_thread(struct pt_regs *regs, unsigned long pc, unsigned long sp)
{
- unsigned long sr = regs->sr & ~SPR_SR_SM;
+ unsigned long sr = mfspr(SPR_SR) & ~SPR_SR_SM;
set_fs(USER_DS);
- memset(regs->gpr, 0, sizeof(regs->gpr));
+ memset(regs, 0, sizeof(struct pt_regs));
regs->pc = pc;
regs->sr = sr;
regs->sp = sp;
-
-/* printk("start thread, ksp = %lx\n", current_thread_info()->ksp);*/
}
/* Fill in the fpu structure for a core dump. */
@@ -237,74 +251,9 @@ void dump_elf_thread(elf_greg_t *dest, struct pt_regs* regs)
dest[35] = 0;
}
-extern void _kernel_thread_helper(void);
-
-void __noreturn kernel_thread_helper(int (*fn) (void *), void *arg)
-{
- do_exit(fn(arg));
-}
-
-/*
- * Create a kernel thread.
- */
-int kernel_thread(int (*fn) (void *), void *arg, unsigned long flags)
-{
- struct pt_regs regs;
-
- memset(&regs, 0, sizeof(regs));
-
- regs.gpr[20] = (unsigned long)fn;
- regs.gpr[22] = (unsigned long)arg;
- regs.sr = mfspr(SPR_SR);
- regs.pc = (unsigned long)_kernel_thread_helper;
-
- return do_fork(flags | CLONE_VM | CLONE_UNTRACED,
- 0, &regs, 0, NULL, NULL);
-}
-
-/*
- * sys_execve() executes a new program.
- */
-asmlinkage long _sys_execve(const char __user *name,
- const char __user * const __user *argv,
- const char __user * const __user *envp,
- struct pt_regs *regs)
-{
- int error;
- struct filename *filename;
-
- filename = getname(name);
- error = PTR_ERR(filename);
-
- if (IS_ERR(filename))
- goto out;
-
- error = do_execve(filename->name, argv, envp, regs);
- putname(filename);
-
-out:
- return error;
-}
-
unsigned long get_wchan(struct task_struct *p)
{
/* TODO */
return 0;
}
-
-int kernel_execve(const char *filename, char *const argv[], char *const envp[])
-{
- register long __res asm("r11") = __NR_execve;
- register long __a asm("r3") = (long)(filename);
- register long __b asm("r4") = (long)(argv);
- register long __c asm("r5") = (long)(envp);
- __asm__ volatile ("l.sys 1"
- : "=r" (__res), "=r"(__a), "=r"(__b), "=r"(__c)
- : "0"(__res), "1"(__a), "2"(__b), "3"(__c)
- : "r6", "r7", "r8", "r12", "r13", "r15",
- "r17", "r19", "r21", "r23", "r25", "r27",
- "r29", "r31");
- __asm__ volatile ("l.nop");
- return __res;
-}
diff --git a/arch/parisc/Kconfig b/arch/parisc/Kconfig
index 11def45b98c5..0aec70c35614 100644
--- a/arch/parisc/Kconfig
+++ b/arch/parisc/Kconfig
@@ -22,6 +22,8 @@ config PARISC
select GENERIC_STRNCPY_FROM_USER
select HAVE_MOD_ARCH_SPECIFIC
select MODULES_USE_ELF_RELA
+ select GENERIC_KERNEL_THREAD
+ select GENERIC_KERNEL_EXECVE
help
The PA-RISC microprocessor is designed by Hewlett-Packard and used
diff --git a/arch/parisc/include/asm/unistd.h b/arch/parisc/include/asm/unistd.h
index 541639c3f607..55512e26b0c2 100644
--- a/arch/parisc/include/asm/unistd.h
+++ b/arch/parisc/include/asm/unistd.h
@@ -163,6 +163,7 @@ type name(type1 arg1, type2 arg2, type3 arg3, type4 arg4, type5 arg5) \
#define __ARCH_WANT_SYS_RT_SIGACTION
#define __ARCH_WANT_SYS_RT_SIGSUSPEND
#define __ARCH_WANT_COMPAT_SYS_RT_SIGSUSPEND
+#define __ARCH_WANT_SYS_EXECVE
#endif /* __ASSEMBLY__ */
diff --git a/arch/parisc/kernel/entry.S b/arch/parisc/kernel/entry.S
index 18670a078849..c9a9abd4bc58 100644
--- a/arch/parisc/kernel/entry.S
+++ b/arch/parisc/kernel/entry.S
@@ -708,59 +708,9 @@ ENTRY(end_fault_vector)
.import do_cpu_irq_mask,code
/*
- * r26 = function to be called
- * r25 = argument to pass in
- * r24 = flags for do_fork()
- *
- * Kernel threads don't ever return, so they don't need
- * a true register context. We just save away the arguments
- * for copy_thread/ret_ to properly set up the child.
- */
-
-#define CLONE_VM 0x100 /* Must agree with <linux/sched.h> */
-#define CLONE_UNTRACED 0x00800000
-
- .import do_fork
-ENTRY(__kernel_thread)
- STREG %r2, -RP_OFFSET(%r30)
-
- copy %r30, %r1
- ldo PT_SZ_ALGN(%r30),%r30
-#ifdef CONFIG_64BIT
- /* Yo, function pointers in wide mode are little structs... -PB */
- ldd 24(%r26), %r2
- STREG %r2, PT_GR27(%r1) /* Store childs %dp */
- ldd 16(%r26), %r26
-
- STREG %r22, PT_GR22(%r1) /* save r22 (arg5) */
- copy %r0, %r22 /* user_tid */
-#endif
- STREG %r26, PT_GR26(%r1) /* Store function & argument for child */
- STREG %r25, PT_GR25(%r1)
- ldil L%CLONE_UNTRACED, %r26
- ldo CLONE_VM(%r26), %r26 /* Force CLONE_VM since only init_mm */
- or %r26, %r24, %r26 /* will have kernel mappings. */
- ldi 1, %r25 /* stack_start, signals kernel thread */
- stw %r0, -52(%r30) /* user_tid */
-#ifdef CONFIG_64BIT
- ldo -16(%r30),%r29 /* Reference param save area */
-#endif
- BL do_fork, %r2
- copy %r1, %r24 /* pt_regs */
-
- /* Parent Returns here */
-
- LDREG -PT_SZ_ALGN-RP_OFFSET(%r30), %r2
- ldo -PT_SZ_ALGN(%r30), %r30
- bv %r0(%r2)
- nop
-ENDPROC(__kernel_thread)
-
- /*
* Child Returns here
*
- * copy_thread moved args from temp save area set up above
- * into task save area.
+ * copy_thread moved args into task save area.
*/
ENTRY(ret_from_kernel_thread)
@@ -769,51 +719,17 @@ ENTRY(ret_from_kernel_thread)
BL schedule_tail, %r2
nop
- LDREG TI_TASK-THREAD_SZ_ALGN(%r30), %r1
+ LDREG TI_TASK-THREAD_SZ_ALGN-FRAME_SIZE(%r30), %r1
LDREG TASK_PT_GR25(%r1), %r26
#ifdef CONFIG_64BIT
LDREG TASK_PT_GR27(%r1), %r27
- LDREG TASK_PT_GR22(%r1), %r22
#endif
LDREG TASK_PT_GR26(%r1), %r1
ble 0(%sr7, %r1)
copy %r31, %r2
-
-#ifdef CONFIG_64BIT
- ldo -16(%r30),%r29 /* Reference param save area */
- loadgp /* Thread could have been in a module */
-#endif
-#ifndef CONFIG_64BIT
- b sys_exit
-#else
- load32 sys_exit, %r1
- bv %r0(%r1)
-#endif
- ldi 0, %r26
-ENDPROC(ret_from_kernel_thread)
-
- .import sys_execve, code
-ENTRY(__execve)
- copy %r2, %r15
- copy %r30, %r16
- ldo PT_SZ_ALGN(%r30), %r30
- STREG %r26, PT_GR26(%r16)
- STREG %r25, PT_GR25(%r16)
- STREG %r24, PT_GR24(%r16)
-#ifdef CONFIG_64BIT
- ldo -16(%r30),%r29 /* Reference param save area */
-#endif
- BL sys_execve, %r2
- copy %r16, %r26
-
- cmpib,=,n 0,%r28,intr_return /* forward */
-
- /* yes, this will trap and die. */
- copy %r15, %r2
- copy %r16, %r30
- bv %r0(%r2)
+ b finish_child_return
nop
-ENDPROC(__execve)
+ENDPROC(ret_from_kernel_thread)
/*
@@ -1776,49 +1692,27 @@ ENTRY(sys_fork_wrapper)
LDREG TI_TASK-THREAD_SZ_ALGN-FRAME_SIZE(%r30), %r1
ldo TASK_REGS(%r1),%r1
reg_save %r1
- mfctl %cr27, %r3
- STREG %r3, PT_CR27(%r1)
-
- STREG %r2,-RP_OFFSET(%r30)
- ldo FRAME_SIZE(%r30),%r30
-#ifdef CONFIG_64BIT
- ldo -16(%r30),%r29 /* Reference param save area */
-#endif
-
- /* These are call-clobbered registers and therefore
- also syscall-clobbered (we hope). */
- STREG %r2,PT_GR19(%r1) /* save for child */
- STREG %r30,PT_GR21(%r1)
+ mfctl %cr27, %r28
+ STREG %r28, PT_CR27(%r1)
LDREG PT_GR30(%r1),%r25
copy %r1,%r24
- BL sys_clone,%r2
+ b sys_clone
ldi SIGCHLD,%r26
-
- LDREG -RP_OFFSET-FRAME_SIZE(%r30),%r2
-wrapper_exit:
- ldo -FRAME_SIZE(%r30),%r30 /* get the stackframe */
- LDREG TI_TASK-THREAD_SZ_ALGN-FRAME_SIZE(%r30),%r1
- ldo TASK_REGS(%r1),%r1 /* get pt regs */
-
- LDREG PT_CR27(%r1), %r3
- mtctl %r3, %cr27
- reg_restore %r1
-
- /* strace expects syscall # to be preserved in r20 */
- ldi __NR_fork,%r20
- bv %r0(%r2)
- STREG %r20,PT_GR20(%r1)
ENDPROC(sys_fork_wrapper)
/* Set the return value for the child */
ENTRY(child_return)
BL schedule_tail, %r2
nop
+finish_child_return:
+ LDREG TI_TASK-THREAD_SZ_ALGN-FRAME_SIZE(%r30), %r1
+ ldo TASK_REGS(%r1),%r1 /* get pt regs */
- LDREG TI_TASK-THREAD_SZ_ALGN-FRAME_SIZE-FRAME_SIZE(%r30), %r1
- LDREG TASK_PT_GR19(%r1),%r2
- b wrapper_exit
+ LDREG PT_CR27(%r1), %r3
+ mtctl %r3, %cr27
+ reg_restore %r1
+ b syscall_exit
copy %r0,%r28
ENDPROC(child_return)
@@ -1827,23 +1721,10 @@ ENTRY(sys_clone_wrapper)
LDREG TI_TASK-THREAD_SZ_ALGN-FRAME_SIZE(%r30),%r1
ldo TASK_REGS(%r1),%r1 /* get pt regs */
reg_save %r1
- mfctl %cr27, %r3
- STREG %r3, PT_CR27(%r1)
-
- STREG %r2,-RP_OFFSET(%r30)
- ldo FRAME_SIZE(%r30),%r30
-#ifdef CONFIG_64BIT
- ldo -16(%r30),%r29 /* Reference param save area */
-#endif
-
- /* WARNING - Clobbers r19 and r21, userspace must save these! */
- STREG %r2,PT_GR19(%r1) /* save for child */
- STREG %r30,PT_GR21(%r1)
- BL sys_clone,%r2
+ mfctl %cr27, %r28
+ STREG %r28, PT_CR27(%r1)
+ b sys_clone
copy %r1,%r24
-
- b wrapper_exit
- LDREG -RP_OFFSET-FRAME_SIZE(%r30),%r2
ENDPROC(sys_clone_wrapper)
@@ -1851,72 +1732,14 @@ ENTRY(sys_vfork_wrapper)
LDREG TI_TASK-THREAD_SZ_ALGN-FRAME_SIZE(%r30),%r1
ldo TASK_REGS(%r1),%r1 /* get pt regs */
reg_save %r1
- mfctl %cr27, %r3
- STREG %r3, PT_CR27(%r1)
+ mfctl %cr27, %r28
+ STREG %r28, PT_CR27(%r1)
- STREG %r2,-RP_OFFSET(%r30)
- ldo FRAME_SIZE(%r30),%r30
-#ifdef CONFIG_64BIT
- ldo -16(%r30),%r29 /* Reference param save area */
-#endif
-
- STREG %r2,PT_GR19(%r1) /* save for child */
- STREG %r30,PT_GR21(%r1)
-
- BL sys_vfork,%r2
+ b sys_vfork
copy %r1,%r26
-
- b wrapper_exit
- LDREG -RP_OFFSET-FRAME_SIZE(%r30),%r2
ENDPROC(sys_vfork_wrapper)
- .macro execve_wrapper execve
- LDREG TI_TASK-THREAD_SZ_ALGN-FRAME_SIZE(%r30),%r1
- ldo TASK_REGS(%r1),%r1 /* get pt regs */
-
- /*
- * Do we need to save/restore r3-r18 here?
- * I don't think so. why would new thread need old
- * threads registers?
- */
-
- /* %arg0 - %arg3 are already saved for us. */
-
- STREG %r2,-RP_OFFSET(%r30)
- ldo FRAME_SIZE(%r30),%r30
-#ifdef CONFIG_64BIT
- ldo -16(%r30),%r29 /* Reference param save area */
-#endif
- BL \execve,%r2
- copy %r1,%arg0
-
- ldo -FRAME_SIZE(%r30),%r30
- LDREG -RP_OFFSET(%r30),%r2
-
- /* If exec succeeded we need to load the args */
-
- ldo -1024(%r0),%r1
- cmpb,>>= %r28,%r1,error_\execve
- copy %r2,%r19
-
-error_\execve:
- bv %r0(%r19)
- nop
- .endm
-
- .import sys_execve
-ENTRY(sys_execve_wrapper)
- execve_wrapper sys_execve
-ENDPROC(sys_execve_wrapper)
-
-#ifdef CONFIG_64BIT
- .import sys32_execve
-ENTRY(sys32_execve_wrapper)
- execve_wrapper sys32_execve
-ENDPROC(sys32_execve_wrapper)
-#endif
-
ENTRY(sys_rt_sigreturn_wrapper)
LDREG TI_TASK-THREAD_SZ_ALGN-FRAME_SIZE(%r30),%r26
ldo TASK_REGS(%r26),%r26 /* get pt regs */
diff --git a/arch/parisc/kernel/process.c b/arch/parisc/kernel/process.c
index cbc37216bf90..38db36f64307 100644
--- a/arch/parisc/kernel/process.c
+++ b/arch/parisc/kernel/process.c
@@ -52,6 +52,7 @@
#include <asm/io.h>
#include <asm/asm-offsets.h>
+#include <asm/assembly.h>
#include <asm/pdc.h>
#include <asm/pdc_chassis.h>
#include <asm/pgalloc.h>
@@ -165,23 +166,6 @@ void (*pm_power_off)(void) = machine_power_off;
EXPORT_SYMBOL(pm_power_off);
/*
- * Create a kernel thread
- */
-
-extern pid_t __kernel_thread(int (*fn)(void *), void *arg, unsigned long flags);
-pid_t kernel_thread(int (*fn)(void *), void *arg, unsigned long flags)
-{
-
- /*
- * FIXME: Once we are sure we don't need any debug here,
- * kernel_thread can become a #define.
- */
-
- return __kernel_thread(fn, arg, flags);
-}
-EXPORT_SYMBOL(kernel_thread);
-
-/*
* Free current thread data structures etc..
*/
void exit_thread(void)
@@ -256,8 +240,8 @@ sys_vfork(struct pt_regs *regs)
int
copy_thread(unsigned long clone_flags, unsigned long usp,
- unsigned long unused, /* in ia64 this is "user_stack_size" */
- struct task_struct * p, struct pt_regs * pregs)
+ unsigned long arg,
+ struct task_struct *p, struct pt_regs *pregs)
{
struct pt_regs * cregs = &(p->thread.regs);
void *stack = task_stack_page(p);
@@ -270,48 +254,32 @@ copy_thread(unsigned long clone_flags, unsigned long usp,
#ifdef CONFIG_HPUX
extern void * const hpux_child_return;
#endif
+ if (unlikely(p->flags & PF_KTHREAD)) {
+ memset(cregs, 0, sizeof(struct pt_regs));
+ if (!usp) /* idle thread */
+ return 0;
- *cregs = *pregs;
-
- /* Set the return value for the child. Note that this is not
- actually restored by the syscall exit path, but we put it
- here for consistency in case of signals. */
- cregs->gr[28] = 0; /* child */
-
- /*
- * We need to differentiate between a user fork and a
- * kernel fork. We can't use user_mode, because the
- * the syscall path doesn't save iaoq. Right now
- * We rely on the fact that kernel_thread passes
- * in zero for usp.
- */
- if (usp == 1) {
/* kernel thread */
- cregs->ksp = (unsigned long)stack + THREAD_SZ_ALGN;
/* Must exit via ret_from_kernel_thread in order
* to call schedule_tail()
*/
+ cregs->ksp = (unsigned long)stack + THREAD_SZ_ALGN + FRAME_SIZE;
cregs->kpc = (unsigned long) &ret_from_kernel_thread;
/*
* Copy function and argument to be called from
* ret_from_kernel_thread.
*/
#ifdef CONFIG_64BIT
- cregs->gr[27] = pregs->gr[27];
+ cregs->gr[27] = ((unsigned long *)usp)[3];
+ cregs->gr[26] = ((unsigned long *)usp)[2];
+#else
+ cregs->gr[26] = usp;
#endif
- cregs->gr[26] = pregs->gr[26];
- cregs->gr[25] = pregs->gr[25];
+ cregs->gr[25] = arg;
} else {
/* user thread */
- /*
- * Note that the fork wrappers are responsible
- * for setting gr[21].
- */
-
- /* Use same stack depth as parent */
- cregs->ksp = (unsigned long)stack
- + (pregs->gr[21] & (THREAD_SIZE - 1));
cregs->gr[30] = usp;
+ cregs->ksp = (unsigned long)stack + THREAD_SZ_ALGN + FRAME_SIZE;
if (personality(p->personality) == PER_HPUX) {
#ifdef CONFIG_HPUX
cregs->kpc = (unsigned long) &hpux_child_return;
@@ -323,8 +291,7 @@ copy_thread(unsigned long clone_flags, unsigned long usp,
}
/* Setup thread TLS area from the 4th parameter in clone */
if (clone_flags & CLONE_SETTLS)
- cregs->cr27 = pregs->gr[23];
-
+ cregs->cr27 = pregs->gr[23];
}
return 0;
@@ -335,39 +302,6 @@ unsigned long thread_saved_pc(struct task_struct *t)
return t->thread.regs.kpc;
}
-/*
- * sys_execve() executes a new program.
- */
-
-asmlinkage int sys_execve(struct pt_regs *regs)
-{
- int error;
- struct filename *filename;
-
- filename = getname((const char __user *) regs->gr[26]);
- error = PTR_ERR(filename);
- if (IS_ERR(filename))
- goto out;
- error = do_execve(filename->name,
- (const char __user *const __user *) regs->gr[25],
- (const char __user *const __user *) regs->gr[24],
- regs);
- putname(filename);
-out:
-
- return error;
-}
-
-extern int __execve(const char *filename,
- const char *const argv[],
- const char *const envp[], struct task_struct *task);
-int kernel_execve(const char *filename,
- const char *const argv[],
- const char *const envp[])
-{
- return __execve(filename, argv, envp, current);
-}
-
unsigned long
get_wchan(struct task_struct *p)
{
diff --git a/arch/parisc/kernel/sys_parisc32.c b/arch/parisc/kernel/sys_parisc32.c
index bf5b93a885d3..9cfdaa19ab63 100644
--- a/arch/parisc/kernel/sys_parisc32.c
+++ b/arch/parisc/kernel/sys_parisc32.c
@@ -53,28 +53,6 @@
#define DBG(x)
#endif
-/*
- * sys32_execve() executes a new program.
- */
-
-asmlinkage int sys32_execve(struct pt_regs *regs)
-{
- int error;
- struct filename *filename;
-
- DBG(("sys32_execve(%p) r26 = 0x%lx\n", regs, regs->gr[26]));
- filename = getname((const char __user *) regs->gr[26]);
- error = PTR_ERR(filename);
- if (IS_ERR(filename))
- goto out;
- error = compat_do_execve(filename->name, compat_ptr(regs->gr[25]),
- compat_ptr(regs->gr[24]), regs);
- putname(filename);
-out:
-
- return error;
-}
-
asmlinkage long sys32_unimplemented(int r26, int r25, int r24, int r23,
int r22, int r21, int r20)
{
diff --git a/arch/parisc/kernel/syscall_table.S b/arch/parisc/kernel/syscall_table.S
index 3735abd7f8f6..cb2da96d6ab9 100644
--- a/arch/parisc/kernel/syscall_table.S
+++ b/arch/parisc/kernel/syscall_table.S
@@ -66,7 +66,7 @@
ENTRY_SAME(creat)
ENTRY_SAME(link)
ENTRY_SAME(unlink) /* 10 */
- ENTRY_DIFF(execve_wrapper)
+ ENTRY_COMP(execve)
ENTRY_SAME(chdir)
/* See comments in kernel/time.c!!! Maybe we don't need this? */
ENTRY_COMP(time)
diff --git a/arch/s390/Kconfig b/arch/s390/Kconfig
index 5dba755a43e6..af431de6363c 100644
--- a/arch/s390/Kconfig
+++ b/arch/s390/Kconfig
@@ -137,6 +137,7 @@ config S390
select KTIME_SCALAR if 32BIT
select HAVE_ARCH_SECCOMP_FILTER
select GENERIC_KERNEL_THREAD
+ select GENERIC_KERNEL_EXECVE
select HAVE_MOD_ARCH_SPECIFIC
select MODULES_USE_ELF_RELA
diff --git a/arch/s390/include/asm/unistd.h b/arch/s390/include/asm/unistd.h
index bbbae41fa9a5..ccbcab7742cd 100644
--- a/arch/s390/include/asm/unistd.h
+++ b/arch/s390/include/asm/unistd.h
@@ -54,7 +54,6 @@
# define __ARCH_WANT_COMPAT_SYS_RT_SIGSUSPEND
# endif
#define __ARCH_WANT_SYS_EXECVE
-#define __ARCH_WANT_KERNEL_EXECVE
/*
* "Conditional" syscalls
diff --git a/arch/s390/kernel/entry.S b/arch/s390/kernel/entry.S
index ef46f66bc0d6..aa8f2ba6289b 100644
--- a/arch/s390/kernel/entry.S
+++ b/arch/s390/kernel/entry.S
@@ -330,40 +330,18 @@ ENTRY(ret_from_fork)
la %r11,STACK_FRAME_OVERHEAD(%r15)
l %r12,__LC_THREAD_INFO
l %r13,__LC_SVC_NEW_PSW+4
- tm __PT_PSW+1(%r11),0x01 # forking a kernel thread ?
- je 1f
l %r1,BASED(.Lschedule_tail)
basr %r14,%r1 # call schedule_tail
TRACE_IRQS_ON
ssm __LC_SVC_NEW_PSW # reenable interrupts
- j sysc_tracenogo
-
-1: # it's a kernel thread
- st %r15,__PT_R15(%r11) # store stack pointer for new kthread
- l %r1,BASED(.Lschedule_tail)
- basr %r14,%r1 # call schedule_tail
- TRACE_IRQS_ON
- ssm __LC_SVC_NEW_PSW # reenable interrupts
- lm %r9,%r11,__PT_R9(%r11) # load gprs
+ tm __PT_PSW+1(%r11),0x01 # forking a kernel thread ?
+ jne sysc_tracenogo
+ # it's a kernel thread
+ lm %r9,%r10,__PT_R9(%r11) # load gprs
ENTRY(kernel_thread_starter)
la %r2,0(%r10)
basr %r14,%r9
- la %r2,0
- br %r11 # do_exit
-
-#
-# kernel_execve function needs to deal with pt_regs that is not
-# at the usual place
-#
-ENTRY(ret_from_kernel_execve)
- ssm __LC_PGM_NEW_PSW # disable I/O and ext. interrupts
- lr %r15,%r2
- lr %r11,%r2
- ahi %r15,-STACK_FRAME_OVERHEAD
- xc __SF_BACKCHAIN(4,%r15),__SF_BACKCHAIN(%r15)
- l %r12,__LC_THREAD_INFO
- ssm __LC_SVC_NEW_PSW # reenable interrupts
- j sysc_return
+ j sysc_tracenogo
/*
* Program check handler routine
diff --git a/arch/s390/kernel/entry64.S b/arch/s390/kernel/entry64.S
index 07d8de353984..499e95e90f38 100644
--- a/arch/s390/kernel/entry64.S
+++ b/arch/s390/kernel/entry64.S
@@ -352,33 +352,17 @@ sysc_tracenogo:
ENTRY(ret_from_fork)
la %r11,STACK_FRAME_OVERHEAD(%r15)
lg %r12,__LC_THREAD_INFO
- tm __PT_PSW+1(%r11),0x01 # forking a kernel thread ?
- je 1f
brasl %r14,schedule_tail
TRACE_IRQS_ON
ssm __LC_SVC_NEW_PSW # reenable interrupts
- j sysc_tracenogo
-1: # it's a kernel thread
- stg %r15,__PT_R15(%r11) # store stack pointer for new kthread
- brasl %r14,schedule_tail
- TRACE_IRQS_ON
- ssm __LC_SVC_NEW_PSW # reenable interrupts
- lmg %r9,%r11,__PT_R9(%r11) # load gprs
+ tm __PT_PSW+1(%r11),0x01 # forking a kernel thread ?
+ jne sysc_tracenogo
+ # it's a kernel thread
+ lmg %r9,%r10,__PT_R9(%r11) # load gprs
ENTRY(kernel_thread_starter)
la %r2,0(%r10)
basr %r14,%r9
- la %r2,0
- br %r11 # do_exit
-
-ENTRY(ret_from_kernel_execve)
- ssm __LC_PGM_NEW_PSW # disable I/O and ext. interrupts
- lgr %r15,%r2
- lgr %r11,%r2
- aghi %r15,-STACK_FRAME_OVERHEAD
- xc __SF_BACKCHAIN(8,%r15),__SF_BACKCHAIN(%r15)
- lg %r12,__LC_THREAD_INFO
- ssm __LC_SVC_NEW_PSW # reenable interrupts
- j sysc_return
+ j sysc_tracenogo
/*
* Program check handler routine
diff --git a/arch/tile/Kconfig b/arch/tile/Kconfig
index 875d008828b8..ea7f61e8bc9e 100644
--- a/arch/tile/Kconfig
+++ b/arch/tile/Kconfig
@@ -21,6 +21,8 @@ config TILE
select ARCH_HAVE_NMI_SAFE_CMPXCHG
select GENERIC_CLOCKEVENTS
select MODULES_USE_ELF_RELA
+ select GENERIC_KERNEL_THREAD
+ select GENERIC_KERNEL_EXECVE
# FIXME: investigate whether we need/want these options.
# select HAVE_IOREMAP_PROT
diff --git a/arch/tile/include/asm/compat.h b/arch/tile/include/asm/compat.h
index 3063e6fc8daa..ca61fb4296b3 100644
--- a/arch/tile/include/asm/compat.h
+++ b/arch/tile/include/asm/compat.h
@@ -275,18 +275,14 @@ extern int compat_setup_rt_frame(int sig, struct k_sigaction *ka,
struct compat_sigaction;
struct compat_siginfo;
struct compat_sigaltstack;
-long compat_sys_execve(const char __user *path,
- compat_uptr_t __user *argv,
- compat_uptr_t __user *envp, struct pt_regs *);
long compat_sys_rt_sigaction(int sig, struct compat_sigaction __user *act,
struct compat_sigaction __user *oact,
size_t sigsetsize);
long compat_sys_rt_sigqueueinfo(int pid, int sig,
struct compat_siginfo __user *uinfo);
-long compat_sys_rt_sigreturn(struct pt_regs *);
+long compat_sys_rt_sigreturn(void);
long compat_sys_sigaltstack(const struct compat_sigaltstack __user *uss_ptr,
- struct compat_sigaltstack __user *uoss_ptr,
- struct pt_regs *);
+ struct compat_sigaltstack __user *uoss_ptr);
long compat_sys_truncate64(char __user *filename, u32 dummy, u32 low, u32 high);
long compat_sys_ftruncate64(unsigned int fd, u32 dummy, u32 low, u32 high);
long compat_sys_pread64(unsigned int fd, char __user *ubuf, size_t count,
@@ -303,12 +299,7 @@ long compat_sys_fallocate(int fd, int mode,
long compat_sys_sched_rr_get_interval(compat_pid_t pid,
struct compat_timespec __user *interval);
-/* These are the intvec_64.S trampolines. */
-long _compat_sys_execve(const char __user *path,
- const compat_uptr_t __user *argv,
- const compat_uptr_t __user *envp);
-long _compat_sys_sigaltstack(const struct compat_sigaltstack __user *uss_ptr,
- struct compat_sigaltstack __user *uoss_ptr);
+/* Assembly trampoline to avoid clobbering r0. */
long _compat_sys_rt_sigreturn(void);
#endif /* _ASM_TILE_COMPAT_H */
diff --git a/arch/tile/include/asm/elf.h b/arch/tile/include/asm/elf.h
index f8ccf08f6934..b73e1039c911 100644
--- a/arch/tile/include/asm/elf.h
+++ b/arch/tile/include/asm/elf.h
@@ -148,6 +148,7 @@ extern int arch_setup_additional_pages(struct linux_binprm *bprm,
#define compat_start_thread(regs, ip, usp) do { \
regs->pc = ptr_to_compat_reg((void *)(ip)); \
regs->sp = ptr_to_compat_reg((void *)(usp)); \
+ single_step_execve(); \
} while (0)
/*
diff --git a/arch/tile/include/asm/processor.h b/arch/tile/include/asm/processor.h
index 8c4dd9ff91eb..879073e76586 100644
--- a/arch/tile/include/asm/processor.h
+++ b/arch/tile/include/asm/processor.h
@@ -211,6 +211,7 @@ static inline void start_thread(struct pt_regs *regs,
{
regs->pc = pc;
regs->sp = usp;
+ single_step_execve();
}
/* Free all resources held by a thread. */
@@ -239,6 +240,9 @@ unsigned long get_wchan(struct task_struct *p);
#define KSTK_TOP(task) (task_ksp0(task) - STACK_TOP_DELTA)
#define task_pt_regs(task) \
((struct pt_regs *)(task_ksp0(task) - KSTK_PTREGS_GAP) - 1)
+#define current_pt_regs() \
+ ((struct pt_regs *)((stack_pointer | (THREAD_SIZE - 1)) - \
+ (KSTK_PTREGS_GAP - 1)) - 1)
#define task_sp(task) (task_pt_regs(task)->sp)
#define task_pc(task) (task_pt_regs(task)->pc)
/* Aliases for pc and sp (used in fs/proc/array.c) */
diff --git a/arch/tile/include/asm/switch_to.h b/arch/tile/include/asm/switch_to.h
index 1d48c5fee8b7..b8f888cbe6b0 100644
--- a/arch/tile/include/asm/switch_to.h
+++ b/arch/tile/include/asm/switch_to.h
@@ -68,7 +68,10 @@ extern unsigned long get_switch_to_pc(void);
/* Support function for forking a new task. */
void ret_from_fork(void);
-/* Called from ret_from_fork() when a new process starts up. */
+/* Support function for forking a new kernel thread. */
+void ret_from_kernel_thread(void *fn, void *arg);
+
+/* Called from ret_from_xxx() when a new process starts up. */
struct task_struct *sim_notify_fork(struct task_struct *prev);
#endif /* !__ASSEMBLY__ */
diff --git a/arch/tile/include/asm/syscalls.h b/arch/tile/include/asm/syscalls.h
index 06f0464cfed9..369696d63e7b 100644
--- a/arch/tile/include/asm/syscalls.h
+++ b/arch/tile/include/asm/syscalls.h
@@ -51,8 +51,7 @@ long sys_cacheflush(unsigned long addr, unsigned long len,
#ifndef __tilegx__
/* mm/fault.c */
-long sys_cmpxchg_badaddr(unsigned long address, struct pt_regs *);
-long _sys_cmpxchg_badaddr(unsigned long address);
+long sys_cmpxchg_badaddr(unsigned long address);
#endif
#ifdef CONFIG_COMPAT
@@ -63,14 +62,23 @@ long sys_truncate64(const char __user *path, loff_t length);
long sys_ftruncate64(unsigned int fd, loff_t length);
#endif
+/* Provide versions of standard syscalls that use current_pt_regs(). */
+long sys_clone(unsigned long clone_flags, unsigned long newsp,
+ void __user *parent_tid, void __user *child_tid);
+long sys_execve(const char __user *filename,
+ const char __user *const __user *argv,
+ const char __user *const __user *envp);
+long sys_rt_sigreturn(void);
+long sys_sigaltstack(const stack_t __user *, stack_t __user *);
+#define sys_clone sys_clone
+#define sys_execve sys_execve
+#define sys_rt_sigreturn sys_rt_sigreturn
+#define sys_sigaltstack sys_sigaltstack
+
/* These are the intvec*.S trampolines. */
-long _sys_sigaltstack(const stack_t __user *, stack_t __user *);
long _sys_rt_sigreturn(void);
long _sys_clone(unsigned long clone_flags, unsigned long newsp,
void __user *parent_tid, void __user *child_tid);
-long _sys_execve(const char __user *filename,
- const char __user *const __user *argv,
- const char __user *const __user *envp);
#include <asm-generic/syscalls.h>
diff --git a/arch/tile/include/asm/unistd.h b/arch/tile/include/asm/unistd.h
index 6e032a0a268e..dab827dc8acb 100644
--- a/arch/tile/include/asm/unistd.h
+++ b/arch/tile/include/asm/unistd.h
@@ -16,4 +16,5 @@
#define __ARCH_WANT_SYS_LLSEEK
#endif
#define __ARCH_WANT_SYS_NEWFSTATAT
+#define __ARCH_WANT_SYS_EXECVE
#include <uapi/asm/unistd.h>
diff --git a/arch/tile/kernel/compat.c b/arch/tile/kernel/compat.c
index d67459b9ac2a..a2e805569d5d 100644
--- a/arch/tile/kernel/compat.c
+++ b/arch/tile/kernel/compat.c
@@ -102,10 +102,9 @@ long compat_sys_sched_rr_get_interval(compat_pid_t pid,
#define compat_sys_fadvise64_64 sys32_fadvise64_64
#define compat_sys_readahead sys32_readahead
-/* Call the trampolines to manage pt_regs where necessary. */
-#define compat_sys_execve _compat_sys_execve
-#define compat_sys_sigaltstack _compat_sys_sigaltstack
+/* Call the assembly trampolines where necessary. */
#define compat_sys_rt_sigreturn _compat_sys_rt_sigreturn
+#undef sys_clone
#define sys_clone _sys_clone
/*
diff --git a/arch/tile/kernel/compat_signal.c b/arch/tile/kernel/compat_signal.c
index 08b4fe1717bb..210a9bbae963 100644
--- a/arch/tile/kernel/compat_signal.c
+++ b/arch/tile/kernel/compat_signal.c
@@ -197,8 +197,7 @@ int copy_siginfo_from_user32(siginfo_t *to, struct compat_siginfo __user *from)
}
long compat_sys_sigaltstack(const struct compat_sigaltstack __user *uss_ptr,
- struct compat_sigaltstack __user *uoss_ptr,
- struct pt_regs *regs)
+ struct compat_sigaltstack __user *uoss_ptr)
{
stack_t uss, uoss;
int ret;
@@ -219,7 +218,7 @@ long compat_sys_sigaltstack(const struct compat_sigaltstack __user *uss_ptr,
set_fs(KERNEL_DS);
ret = do_sigaltstack(uss_ptr ? (stack_t __user __force *)&uss : NULL,
(stack_t __user __force *)&uoss,
- (unsigned long)compat_ptr(regs->sp));
+ (unsigned long)compat_ptr(current_pt_regs()->sp));
set_fs(seg);
if (ret >= 0 && uoss_ptr) {
if (!access_ok(VERIFY_WRITE, uoss_ptr, sizeof(*uoss_ptr)) ||
@@ -232,8 +231,9 @@ long compat_sys_sigaltstack(const struct compat_sigaltstack __user *uss_ptr,
}
/* The assembly shim for this function arranges to ignore the return value. */
-long compat_sys_rt_sigreturn(struct pt_regs *regs)
+long compat_sys_rt_sigreturn(void)
{
+ struct pt_regs *regs = current_pt_regs();
struct compat_rt_sigframe __user *frame =
(struct compat_rt_sigframe __user *) compat_ptr(regs->sp);
sigset_t set;
@@ -248,7 +248,7 @@ long compat_sys_rt_sigreturn(struct pt_regs *regs)
if (restore_sigcontext(regs, &frame->uc.uc_mcontext))
goto badframe;
- if (compat_sys_sigaltstack(&frame->uc.uc_stack, NULL, regs) != 0)
+ if (compat_sys_sigaltstack(&frame->uc.uc_stack, NULL) != 0)
goto badframe;
return 0;
diff --git a/arch/tile/kernel/entry.S b/arch/tile/kernel/entry.S
index c31637baff28..f116cb0bce20 100644
--- a/arch/tile/kernel/entry.S
+++ b/arch/tile/kernel/entry.S
@@ -28,17 +28,6 @@ STD_ENTRY(current_text_addr)
STD_ENDPROC(current_text_addr)
/*
- * Implement execve(). The i386 code has a note that forking from kernel
- * space results in no copy on write until the execve, so we should be
- * careful not to write to the stack here.
- */
-STD_ENTRY(kernel_execve)
- moveli TREG_SYSCALL_NR_NAME, __NR_execve
- swint1
- jrp lr
- STD_ENDPROC(kernel_execve)
-
-/*
* We don't run this function directly, but instead copy it to a page
* we map into every user process. See vdso_setup().
*
diff --git a/arch/tile/kernel/intvec_32.S b/arch/tile/kernel/intvec_32.S
index 6943515100f8..f212bf7cea86 100644
--- a/arch/tile/kernel/intvec_32.S
+++ b/arch/tile/kernel/intvec_32.S
@@ -1291,6 +1291,21 @@ STD_ENTRY(ret_from_fork)
}
STD_ENDPROC(ret_from_fork)
+STD_ENTRY(ret_from_kernel_thread)
+ jal sim_notify_fork
+ jal schedule_tail
+ FEEDBACK_REENTER(ret_from_fork)
+ {
+ move r0, r31
+ jalr r30
+ }
+ FEEDBACK_REENTER(ret_from_kernel_thread)
+ {
+ movei r30, 0 /* not an NMI */
+ j .Lresume_userspace /* jump into middle of interrupt_return */
+ }
+ STD_ENDPROC(ret_from_kernel_thread)
+
/*
* Code for ill interrupt.
*/
@@ -1437,15 +1452,6 @@ STD_ENTRY_LOCAL(bad_intr)
panic "Unhandled interrupt %#x: PC %#lx"
STD_ENDPROC(bad_intr)
-/* Put address of pt_regs in reg and jump. */
-#define PTREGS_SYSCALL(x, reg) \
- STD_ENTRY(_##x); \
- { \
- PTREGS_PTR(reg, PTREGS_OFFSET_BASE); \
- j x \
- }; \
- STD_ENDPROC(_##x)
-
/*
* Special-case sigreturn to not write r0 to the stack on return.
* This is technically more efficient, but it also avoids difficulties
@@ -1461,12 +1467,9 @@ STD_ENTRY_LOCAL(bad_intr)
}; \
STD_ENDPROC(_##x)
-PTREGS_SYSCALL(sys_execve, r3)
-PTREGS_SYSCALL(sys_sigaltstack, r2)
PTREGS_SYSCALL_SIGRETURN(sys_rt_sigreturn, r0)
-PTREGS_SYSCALL(sys_cmpxchg_badaddr, r1)
-/* Save additional callee-saves to pt_regs, put address in r4 and jump. */
+/* Save additional callee-saves to pt_regs and jump to standard function. */
STD_ENTRY(_sys_clone)
push_extra_callee_saves r4
j sys_clone
diff --git a/arch/tile/kernel/intvec_64.S b/arch/tile/kernel/intvec_64.S
index 7c06d597ffd0..54bc9a6678e8 100644
--- a/arch/tile/kernel/intvec_64.S
+++ b/arch/tile/kernel/intvec_64.S
@@ -1150,6 +1150,21 @@ STD_ENTRY(ret_from_fork)
}
STD_ENDPROC(ret_from_fork)
+STD_ENTRY(ret_from_kernel_thread)
+ jal sim_notify_fork
+ jal schedule_tail
+ FEEDBACK_REENTER(ret_from_fork)
+ {
+ move r0, r31
+ jalr r30
+ }
+ FEEDBACK_REENTER(ret_from_kernel_thread)
+ {
+ movei r30, 0 /* not an NMI */
+ j .Lresume_userspace /* jump into middle of interrupt_return */
+ }
+ STD_ENDPROC(ret_from_kernel_thread)
+
/* Various stub interrupt handlers and syscall handlers */
STD_ENTRY_LOCAL(_kernel_double_fault)
@@ -1166,15 +1181,6 @@ STD_ENTRY_LOCAL(bad_intr)
panic "Unhandled interrupt %#x: PC %#lx"
STD_ENDPROC(bad_intr)
-/* Put address of pt_regs in reg and jump. */
-#define PTREGS_SYSCALL(x, reg) \
- STD_ENTRY(_##x); \
- { \
- PTREGS_PTR(reg, PTREGS_OFFSET_BASE); \
- j x \
- }; \
- STD_ENDPROC(_##x)
-
/*
* Special-case sigreturn to not write r0 to the stack on return.
* This is technically more efficient, but it also avoids difficulties
@@ -1190,16 +1196,12 @@ STD_ENTRY_LOCAL(bad_intr)
}; \
STD_ENDPROC(_##x)
-PTREGS_SYSCALL(sys_execve, r3)
-PTREGS_SYSCALL(sys_sigaltstack, r2)
PTREGS_SYSCALL_SIGRETURN(sys_rt_sigreturn, r0)
#ifdef CONFIG_COMPAT
-PTREGS_SYSCALL(compat_sys_execve, r3)
-PTREGS_SYSCALL(compat_sys_sigaltstack, r2)
PTREGS_SYSCALL_SIGRETURN(compat_sys_rt_sigreturn, r0)
#endif
-/* Save additional callee-saves to pt_regs, put address in r4 and jump. */
+/* Save additional callee-saves to pt_regs and jump to standard function. */
STD_ENTRY(_sys_clone)
push_extra_callee_saves r4
j sys_clone
diff --git a/arch/tile/kernel/process.c b/arch/tile/kernel/process.c
index 307d010696c9..1c20029d2f5a 100644
--- a/arch/tile/kernel/process.c
+++ b/arch/tile/kernel/process.c
@@ -157,24 +157,44 @@ void arch_release_thread_info(struct thread_info *info)
static void save_arch_state(struct thread_struct *t);
int copy_thread(unsigned long clone_flags, unsigned long sp,
- unsigned long stack_size,
- struct task_struct *p, struct pt_regs *regs)
+ unsigned long arg,
+ struct task_struct *p, struct pt_regs *unused)
{
- struct pt_regs *childregs;
+ struct pt_regs *childregs = task_pt_regs(p);
unsigned long ksp;
+ unsigned long *callee_regs;
/*
- * When creating a new kernel thread we pass sp as zero.
- * Assign it to a reasonable value now that we have the stack.
+ * Set up the stack and stack pointer appropriately for the
+ * new child to find itself woken up in __switch_to().
+ * The callee-saved registers must be on the stack to be read;
+ * the new task will then jump to assembly support to handle
+ * calling schedule_tail(), etc., and (for userspace tasks)
+ * returning to the context set up in the pt_regs.
*/
- if (sp == 0 && regs->ex1 == PL_ICS_EX1(KERNEL_PL, 0))
- sp = KSTK_TOP(p);
+ ksp = (unsigned long) childregs;
+ ksp -= C_ABI_SAVE_AREA_SIZE; /* interrupt-entry save area */
+ ((long *)ksp)[0] = ((long *)ksp)[1] = 0;
+ ksp -= CALLEE_SAVED_REGS_COUNT * sizeof(unsigned long);
+ callee_regs = (unsigned long *)ksp;
+ ksp -= C_ABI_SAVE_AREA_SIZE; /* __switch_to() save area */
+ ((long *)ksp)[0] = ((long *)ksp)[1] = 0;
+ p->thread.ksp = ksp;
- /*
- * Do not clone step state from the parent; each thread
- * must make its own lazily.
- */
- task_thread_info(p)->step_state = NULL;
+ /* Record the pid of the task that created this one. */
+ p->thread.creator_pid = current->pid;
+
+ if (unlikely(p->flags & PF_KTHREAD)) {
+ /* kernel thread */
+ memset(childregs, 0, sizeof(struct pt_regs));
+ memset(&callee_regs[2], 0,
+ (CALLEE_SAVED_REGS_COUNT - 2) * sizeof(unsigned long));
+ callee_regs[0] = sp; /* r30 = function */
+ callee_regs[1] = arg; /* r31 = arg */
+ childregs->ex1 = PL_ICS_EX1(KERNEL_PL, 0);
+ p->thread.pc = (unsigned long) ret_from_kernel_thread;
+ return 0;
+ }
/*
* Start new thread in ret_from_fork so it schedules properly
@@ -182,46 +202,33 @@ int copy_thread(unsigned long clone_flags, unsigned long sp,
*/
p->thread.pc = (unsigned long) ret_from_fork;
- /* Save user stack top pointer so we can ID the stack vm area later. */
- p->thread.usp0 = sp;
-
- /* Record the pid of the process that created this one. */
- p->thread.creator_pid = current->pid;
+ /*
+ * Do not clone step state from the parent; each thread
+ * must make its own lazily.
+ */
+ task_thread_info(p)->step_state = NULL;
/*
* Copy the registers onto the kernel stack so the
* return-from-interrupt code will reload it into registers.
*/
- childregs = task_pt_regs(p);
- *childregs = *regs;
+ *childregs = *current_pt_regs();
childregs->regs[0] = 0; /* return value is zero */
- childregs->sp = sp; /* override with new user stack pointer */
+ if (sp)
+ childregs->sp = sp; /* override with new user stack pointer */
+ memcpy(callee_regs, &childregs->regs[CALLEE_SAVED_FIRST_REG],
+ CALLEE_SAVED_REGS_COUNT * sizeof(unsigned long));
+
+ /* Save user stack top pointer so we can ID the stack vm area later. */
+ p->thread.usp0 = childregs->sp;
/*
* If CLONE_SETTLS is set, set "tp" in the new task to "r4",
* which is passed in as arg #5 to sys_clone().
*/
if (clone_flags & CLONE_SETTLS)
- childregs->tp = regs->regs[4];
+ childregs->tp = childregs->regs[4];
- /*
- * Copy the callee-saved registers from the passed pt_regs struct
- * into the context-switch callee-saved registers area.
- * This way when we start the interrupt-return sequence, the
- * callee-save registers will be correctly in registers, which
- * is how we assume the compiler leaves them as we start doing
- * the normal return-from-interrupt path after calling C code.
- * Zero out the C ABI save area to mark the top of the stack.
- */
- ksp = (unsigned long) childregs;
- ksp -= C_ABI_SAVE_AREA_SIZE; /* interrupt-entry save area */
- ((long *)ksp)[0] = ((long *)ksp)[1] = 0;
- ksp -= CALLEE_SAVED_REGS_COUNT * sizeof(unsigned long);
- memcpy((void *)ksp, &regs->regs[CALLEE_SAVED_FIRST_REG],
- CALLEE_SAVED_REGS_COUNT * sizeof(unsigned long));
- ksp -= C_ABI_SAVE_AREA_SIZE; /* __switch_to() save area */
- ((long *)ksp)[0] = ((long *)ksp)[1] = 0;
- p->thread.ksp = ksp;
#if CHIP_HAS_TILE_DMA()
/*
@@ -578,61 +585,13 @@ int do_work_pending(struct pt_regs *regs, u32 thread_info_flags)
}
/* Note there is an implicit fifth argument if (clone_flags & CLONE_SETTLS). */
-SYSCALL_DEFINE5(clone, unsigned long, clone_flags, unsigned long, newsp,
- void __user *, parent_tidptr, void __user *, child_tidptr,
- struct pt_regs *, regs)
+SYSCALL_DEFINE4(clone, unsigned long, clone_flags, unsigned long, newsp,
+ void __user *, parent_tidptr, void __user *, child_tidptr)
{
- if (!newsp)
- newsp = regs->sp;
- return do_fork(clone_flags, newsp, regs, 0,
+ return do_fork(clone_flags, newsp, current_pt_regs(), 0,
parent_tidptr, child_tidptr);
}
-/*
- * sys_execve() executes a new program.
- */
-SYSCALL_DEFINE4(execve, const char __user *, path,
- const char __user *const __user *, argv,
- const char __user *const __user *, envp,
- struct pt_regs *, regs)
-{
- long error;
- struct filename *filename;
-
- filename = getname(path);
- error = PTR_ERR(filename);
- if (IS_ERR(filename))
- goto out;
- error = do_execve(filename->name, argv, envp, regs);
- putname(filename);
- if (error == 0)
- single_step_execve();
-out:
- return error;
-}
-
-#ifdef CONFIG_COMPAT
-long compat_sys_execve(const char __user *path,
- compat_uptr_t __user *argv,
- compat_uptr_t __user *envp,
- struct pt_regs *regs)
-{
- long error;
- struct filename *filename;
-
- filename = getname(path);
- error = PTR_ERR(filename);
- if (IS_ERR(filename))
- goto out;
- error = compat_do_execve(filename->name, argv, envp, regs);
- putname(filename);
- if (error == 0)
- single_step_execve();
-out:
- return error;
-}
-#endif
-
unsigned long get_wchan(struct task_struct *p)
{
struct KBacktraceIterator kbt;
@@ -650,37 +609,6 @@ unsigned long get_wchan(struct task_struct *p)
return 0;
}
-/*
- * We pass in lr as zero (cleared in kernel_thread) and the caller
- * part of the backtrace ABI on the stack also zeroed (in copy_thread)
- * so that backtraces will stop with this function.
- * Note that we don't use r0, since copy_thread() clears it.
- */
-static void start_kernel_thread(int dummy, int (*fn)(int), int arg)
-{
- do_exit(fn(arg));
-}
-
-/*
- * Create a kernel thread
- */
-int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags)
-{
- struct pt_regs regs;
-
- memset(&regs, 0, sizeof(regs));
- regs.ex1 = PL_ICS_EX1(KERNEL_PL, 0); /* run at kernel PL, no ICS */
- regs.pc = (long) start_kernel_thread;
- regs.flags = PT_FLAGS_CALLER_SAVES; /* need to restore r1 and r2 */
- regs.regs[1] = (long) fn; /* function pointer */
- regs.regs[2] = (long) arg; /* parameter register */
-
- /* Ok, create the new process.. */
- return do_fork(flags | CLONE_VM | CLONE_UNTRACED, 0, &regs,
- 0, NULL, NULL);
-}
-EXPORT_SYMBOL(kernel_thread);
-
/* Flush thread state. */
void flush_thread(void)
{
diff --git a/arch/tile/kernel/signal.c b/arch/tile/kernel/signal.c
index 67efb656d104..657a7ace4ab4 100644
--- a/arch/tile/kernel/signal.c
+++ b/arch/tile/kernel/signal.c
@@ -37,10 +37,10 @@
#define DEBUG_SIG 0
-SYSCALL_DEFINE3(sigaltstack, const stack_t __user *, uss,
- stack_t __user *, uoss, struct pt_regs *, regs)
+SYSCALL_DEFINE2(sigaltstack, const stack_t __user *, uss,
+ stack_t __user *, uoss)
{
- return do_sigaltstack(uss, uoss, regs->sp);
+ return do_sigaltstack(uss, uoss, current_pt_regs()->sp);
}
@@ -83,8 +83,9 @@ void signal_fault(const char *type, struct pt_regs *regs,
}
/* The assembly shim for this function arranges to ignore the return value. */
-SYSCALL_DEFINE1(rt_sigreturn, struct pt_regs *, regs)
+SYSCALL_DEFINE0(rt_sigreturn)
{
+ struct pt_regs *regs = current_pt_regs();
struct rt_sigframe __user *frame =
(struct rt_sigframe __user *)(regs->sp);
sigset_t set;
diff --git a/arch/tile/kernel/sys.c b/arch/tile/kernel/sys.c
index b08095b402d6..02ff5c0ef775 100644
--- a/arch/tile/kernel/sys.c
+++ b/arch/tile/kernel/sys.c
@@ -106,14 +106,11 @@ SYSCALL_DEFINE6(mmap, unsigned long, addr, unsigned long, len,
#define sys_readahead sys32_readahead
#endif
-/* Call the trampolines to manage pt_regs where necessary. */
-#define sys_execve _sys_execve
-#define sys_sigaltstack _sys_sigaltstack
+/* Call the assembly trampolines where necessary. */
+#undef sys_rt_sigreturn
#define sys_rt_sigreturn _sys_rt_sigreturn
+#undef sys_clone
#define sys_clone _sys_clone
-#ifndef __tilegx__
-#define sys_cmpxchg_badaddr _sys_cmpxchg_badaddr
-#endif
/*
* Note that we can't include <linux/unistd.h> here since the header
diff --git a/arch/tile/mm/fault.c b/arch/tile/mm/fault.c
index fe811fa5f1b9..3d2b81c163a6 100644
--- a/arch/tile/mm/fault.c
+++ b/arch/tile/mm/fault.c
@@ -70,9 +70,10 @@ static noinline void force_sig_info_fault(const char *type, int si_signo,
* Synthesize the fault a PL0 process would get by doing a word-load of
* an unaligned address or a high kernel address.
*/
-SYSCALL_DEFINE2(cmpxchg_badaddr, unsigned long, address,
- struct pt_regs *, regs)
+SYSCALL_DEFINE1(cmpxchg_badaddr, unsigned long, address)
{
+ struct pt_regs *regs = current_pt_regs();
+
if (address >= PAGE_OFFSET)
force_sig_info_fault("atomic segfault", SIGSEGV, SEGV_MAPERR,
address, INT_DTLB_MISS, current, regs);
diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
index 1eefebe5d727..224a7e78cb6c 100644
--- a/arch/x86/kvm/x86.c
+++ b/arch/x86/kvm/x86.c
@@ -3779,7 +3779,7 @@ static int write_exit_mmio(struct kvm_vcpu *vcpu, gpa_t gpa,
{
struct kvm_mmio_fragment *frag = &vcpu->mmio_fragments[0];
- memcpy(vcpu->run->mmio.data, frag->data, frag->len);
+ memcpy(vcpu->run->mmio.data, frag->data, min(8u, frag->len));
return X86EMUL_CONTINUE;
}
@@ -3832,18 +3832,11 @@ mmio:
bytes -= handled;
val += handled;
- while (bytes) {
- unsigned now = min(bytes, 8U);
-
- frag = &vcpu->mmio_fragments[vcpu->mmio_nr_fragments++];
- frag->gpa = gpa;
- frag->data = val;
- frag->len = now;
-
- gpa += now;
- val += now;
- bytes -= now;
- }
+ WARN_ON(vcpu->mmio_nr_fragments >= KVM_MAX_MMIO_FRAGMENTS);
+ frag = &vcpu->mmio_fragments[vcpu->mmio_nr_fragments++];
+ frag->gpa = gpa;
+ frag->data = val;
+ frag->len = bytes;
return X86EMUL_CONTINUE;
}
@@ -3890,7 +3883,7 @@ int emulator_read_write(struct x86_emulate_ctxt *ctxt, unsigned long addr,
vcpu->mmio_needed = 1;
vcpu->mmio_cur_fragment = 0;
- vcpu->run->mmio.len = vcpu->mmio_fragments[0].len;
+ vcpu->run->mmio.len = min(8u, vcpu->mmio_fragments[0].len);
vcpu->run->mmio.is_write = vcpu->mmio_is_write = ops->write;
vcpu->run->exit_reason = KVM_EXIT_MMIO;
vcpu->run->mmio.phys_addr = gpa;
@@ -5522,28 +5515,44 @@ static int complete_emulated_pio(struct kvm_vcpu *vcpu)
*
* read:
* for each fragment
- * write gpa, len
- * exit
- * copy data
+ * for each mmio piece in the fragment
+ * write gpa, len
+ * exit
+ * copy data
* execute insn
*
* write:
* for each fragment
- * write gpa, len
- * copy data
- * exit
+ * for each mmio piece in the fragment
+ * write gpa, len
+ * copy data
+ * exit
*/
static int complete_emulated_mmio(struct kvm_vcpu *vcpu)
{
struct kvm_run *run = vcpu->run;
struct kvm_mmio_fragment *frag;
+ unsigned len;
BUG_ON(!vcpu->mmio_needed);
/* Complete previous fragment */
- frag = &vcpu->mmio_fragments[vcpu->mmio_cur_fragment++];
+ frag = &vcpu->mmio_fragments[vcpu->mmio_cur_fragment];
+ len = min(8u, frag->len);
if (!vcpu->mmio_is_write)
- memcpy(frag->data, run->mmio.data, frag->len);
+ memcpy(frag->data, run->mmio.data, len);
+
+ if (frag->len <= 8) {
+ /* Switch to the next fragment. */
+ frag++;
+ vcpu->mmio_cur_fragment++;
+ } else {
+ /* Go forward to the next mmio piece. */
+ frag->data += len;
+ frag->gpa += len;
+ frag->len -= len;
+ }
+
if (vcpu->mmio_cur_fragment == vcpu->mmio_nr_fragments) {
vcpu->mmio_needed = 0;
if (vcpu->mmio_is_write)
@@ -5551,13 +5560,12 @@ static int complete_emulated_mmio(struct kvm_vcpu *vcpu)
vcpu->mmio_read_completed = 1;
return complete_emulated_io(vcpu);
}
- /* Initiate next fragment */
- ++frag;
+
run->exit_reason = KVM_EXIT_MMIO;
run->mmio.phys_addr = frag->gpa;
if (vcpu->mmio_is_write)
- memcpy(run->mmio.data, frag->data, frag->len);
- run->mmio.len = frag->len;
+ memcpy(run->mmio.data, frag->data, min(8u, frag->len));
+ run->mmio.len = min(8u, frag->len);
run->mmio.is_write = vcpu->mmio_is_write;
vcpu->arch.complete_userspace_io = complete_emulated_mmio;
return 0;
diff --git a/arch/xtensa/Kconfig b/arch/xtensa/Kconfig
index cdcb48adee4c..0d1f36a22c98 100644
--- a/arch/xtensa/Kconfig
+++ b/arch/xtensa/Kconfig
@@ -13,6 +13,8 @@ config XTENSA
select GENERIC_CPU_DEVICES
select MODULES_USE_ELF_RELA
select GENERIC_PCI_IOMAP
+ select GENERIC_KERNEL_THREAD
+ select GENERIC_KERNEL_EXECVE
select ARCH_WANT_OPTIONAL_GPIOLIB
help
Xtensa processors are 32-bit RISC machines designed by Tensilica
diff --git a/arch/xtensa/include/asm/io.h b/arch/xtensa/include/asm/io.h
index e6be5b9091c2..700c2e6f2d25 100644
--- a/arch/xtensa/include/asm/io.h
+++ b/arch/xtensa/include/asm/io.h
@@ -62,6 +62,10 @@ static inline void __iomem *ioremap(unsigned long offset, unsigned long size)
static inline void iounmap(volatile void __iomem *addr)
{
}
+
+#define virt_to_bus virt_to_phys
+#define bus_to_virt phys_to_virt
+
#endif /* CONFIG_MMU */
/*
diff --git a/arch/xtensa/include/asm/processor.h b/arch/xtensa/include/asm/processor.h
index 5c371d8d4528..2d630e7399ca 100644
--- a/arch/xtensa/include/asm/processor.h
+++ b/arch/xtensa/include/asm/processor.h
@@ -152,6 +152,7 @@ struct thread_struct {
/* Clearing a0 terminates the backtrace. */
#define start_thread(regs, new_pc, new_sp) \
+ memset(regs, 0, sizeof(*regs)); \
regs->pc = new_pc; \
regs->ps = USER_PS_VALUE; \
regs->areg[1] = new_sp; \
@@ -168,9 +169,6 @@ struct mm_struct;
/* Free all resources held by a thread. */
#define release_thread(thread) do { } while(0)
-/* Create a kernel thread without removing it from tasklists */
-extern int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags);
-
/* Copy and release all segment info associated with a VM */
#define copy_segments(p, mm) do { } while(0)
#define release_segments(mm) do { } while(0)
diff --git a/arch/xtensa/include/asm/syscall.h b/arch/xtensa/include/asm/syscall.h
index c1dacca312f3..124aeee0d381 100644
--- a/arch/xtensa/include/asm/syscall.h
+++ b/arch/xtensa/include/asm/syscall.h
@@ -10,7 +10,7 @@
struct pt_regs;
struct sigaction;
-asmlinkage long xtensa_execve(char*, char**, char**, struct pt_regs*);
+asmlinkage long sys_execve(char*, char**, char**, struct pt_regs*);
asmlinkage long xtensa_clone(unsigned long, unsigned long, struct pt_regs*);
asmlinkage long xtensa_ptrace(long, long, long, long);
asmlinkage long xtensa_sigreturn(struct pt_regs*);
diff --git a/arch/xtensa/include/asm/unistd.h b/arch/xtensa/include/asm/unistd.h
index 9ef1c31d2c83..f4e6eaa40d1c 100644
--- a/arch/xtensa/include/asm/unistd.h
+++ b/arch/xtensa/include/asm/unistd.h
@@ -1,16 +1,9 @@
-/*
- * include/asm-xtensa/unistd.h
- *
- * This file is subject to the terms and conditions of the GNU General Public
- * License. See the file "COPYING" in the main directory of this archive
- * for more details.
- *
- * Copyright (C) 2001 - 2005 Tensilica Inc.
- */
+#ifndef _XTENSA_UNISTD_H
+#define _XTENSA_UNISTD_H
+#define __ARCH_WANT_SYS_EXECVE
#include <uapi/asm/unistd.h>
-
/*
* "Conditional" syscalls
*
@@ -37,3 +30,5 @@
#define __IGNORE_mmap /* use mmap2 */
#define __IGNORE_vfork /* use clone */
#define __IGNORE_fadvise64 /* use fadvise64_64 */
+
+#endif /* _XTENSA_UNISTD_H */
diff --git a/arch/xtensa/include/uapi/asm/unistd.h b/arch/xtensa/include/uapi/asm/unistd.h
index 479abaea5aae..9f36d0e3e0ac 100644
--- a/arch/xtensa/include/uapi/asm/unistd.h
+++ b/arch/xtensa/include/uapi/asm/unistd.h
@@ -1,14 +1,4 @@
-/*
- * include/asm-xtensa/unistd.h
- *
- * This file is subject to the terms and conditions of the GNU General Public
- * License. See the file "COPYING" in the main directory of this archive
- * for more details.
- *
- * Copyright (C) 2001 - 2012 Tensilica Inc.
- */
-
-#ifndef _UAPI_XTENSA_UNISTD_H
+#if !defined(_UAPI_XTENSA_UNISTD_H) || defined(__SYSCALL)
#define _UAPI_XTENSA_UNISTD_H
#ifndef __SYSCALL
@@ -272,7 +262,7 @@ __SYSCALL(115, sys_sendmmsg, 4)
#define __NR_clone 116
__SYSCALL(116, xtensa_clone, 5)
#define __NR_execve 117
-__SYSCALL(117, xtensa_execve, 3)
+__SYSCALL(117, sys_execve, 3)
#define __NR_exit 118
__SYSCALL(118, sys_exit, 1)
#define __NR_exit_group 119
@@ -759,4 +749,6 @@ __SYSCALL(331, sys_kcmp, 5)
#define SYS_XTENSA_COUNT 5 /* count */
+#undef __SYSCALL
+
#endif /* _UAPI_XTENSA_UNISTD_H */
diff --git a/arch/xtensa/kernel/entry.S b/arch/xtensa/kernel/entry.S
index 18453067c258..90bfc1dbc13d 100644
--- a/arch/xtensa/kernel/entry.S
+++ b/arch/xtensa/kernel/entry.S
@@ -1833,50 +1833,6 @@ ENTRY(system_call)
/*
- * Create a kernel thread
- *
- * int kernel_thread(int (*fn)(void *), void *arg, unsigned long flags)
- * a2 a2 a3 a4
- */
-
-ENTRY(kernel_thread)
- entry a1, 16
-
- mov a5, a2 # preserve fn over syscall
- mov a7, a3 # preserve args over syscall
-
- movi a3, _CLONE_VM | _CLONE_UNTRACED
- movi a2, __NR_clone
- or a6, a4, a3 # arg0: flags
- mov a3, a1 # arg1: sp
- syscall
-
- beq a3, a1, 1f # branch if parent
- mov a6, a7 # args
- callx4 a5 # fn(args)
-
- movi a2, __NR_exit
- syscall # return value of fn(args) still in a6
-
-1: retw
-
-/*
- * Do a system call from kernel instead of calling sys_execve, so we end up
- * with proper pt_regs.
- *
- * int kernel_execve(const char *fname, char *const argv[], charg *const envp[])
- * a2 a2 a3 a4
- */
-
-ENTRY(kernel_execve)
- entry a1, 16
- mov a6, a2 # arg0 is in a6
- movi a2, __NR_execve
- syscall
-
- retw
-
-/*
* Task switch.
*
* struct task* _switch_to (struct task* prev, struct task* next)
@@ -1958,3 +1914,16 @@ ENTRY(ret_from_fork)
j common_exception_return
+/*
+ * Kernel thread creation helper
+ * On entry, set up by copy_thread: a2 = thread_fn, a3 = thread_fn arg
+ * left from _switch_to: a6 = prev
+ */
+ENTRY(ret_from_kernel_thread)
+
+ call4 schedule_tail
+ mov a6, a3
+ callx4 a2
+ j common_exception_return
+
+ENDPROC(ret_from_kernel_thread)
diff --git a/arch/xtensa/kernel/process.c b/arch/xtensa/kernel/process.c
index 1908f6642d31..09ae7bfab9a7 100644
--- a/arch/xtensa/kernel/process.c
+++ b/arch/xtensa/kernel/process.c
@@ -45,6 +45,7 @@
#include <asm/regs.h>
extern void ret_from_fork(void);
+extern void ret_from_kernel_thread(void);
struct task_struct *current_set[NR_CPUS] = {&init_task, };
@@ -158,18 +159,30 @@ int arch_dup_task_struct(struct task_struct *dst, struct task_struct *src)
/*
* Copy thread.
*
+ * There are two modes in which this function is called:
+ * 1) Userspace thread creation,
+ * regs != NULL, usp_thread_fn is userspace stack pointer.
+ * It is expected to copy parent regs (in case CLONE_VM is not set
+ * in the clone_flags) and set up passed usp in the childregs.
+ * 2) Kernel thread creation,
+ * regs == NULL, usp_thread_fn is the function to run in the new thread
+ * and thread_fn_arg is its parameter.
+ * childregs are not used for the kernel threads.
+ *
* The stack layout for the new thread looks like this:
*
- * +------------------------+ <- sp in childregs (= tos)
+ * +------------------------+
* | childregs |
* +------------------------+ <- thread.sp = sp in dummy-frame
* | dummy-frame | (saved in dummy-frame spill-area)
* +------------------------+
*
- * We create a dummy frame to return to ret_from_fork:
- * a0 points to ret_from_fork (simulating a call4)
+ * We create a dummy frame to return to either ret_from_fork or
+ * ret_from_kernel_thread:
+ * a0 points to ret_from_fork/ret_from_kernel_thread (simulating a call4)
* sp points to itself (thread.sp)
- * a2, a3 are unused.
+ * a2, a3 are unused for userspace threads,
+ * a2 points to thread_fn, a3 holds thread_fn arg for kernel threads.
*
* Note: This is a pristine frame, so we don't need any spill region on top of
* childregs.
@@ -185,43 +198,63 @@ int arch_dup_task_struct(struct task_struct *dst, struct task_struct *src)
* involved. Much simpler to just not copy those live frames across.
*/
-int copy_thread(unsigned long clone_flags, unsigned long usp,
- unsigned long unused,
- struct task_struct * p, struct pt_regs * regs)
+int copy_thread(unsigned long clone_flags, unsigned long usp_thread_fn,
+ unsigned long thread_fn_arg,
+ struct task_struct *p, struct pt_regs *unused)
{
- struct pt_regs *childregs;
- unsigned long tos;
- int user_mode = user_mode(regs);
+ struct pt_regs *childregs = task_pt_regs(p);
#if (XTENSA_HAVE_COPROCESSORS || XTENSA_HAVE_IO_PORTS)
struct thread_info *ti;
#endif
- /* Set up new TSS. */
- tos = (unsigned long)task_stack_page(p) + THREAD_SIZE;
- if (user_mode)
- childregs = (struct pt_regs*)(tos - PT_USER_SIZE);
- else
- childregs = (struct pt_regs*)tos - 1;
-
- /* This does not copy all the regs. In a bout of brilliance or madness,
- ARs beyond a0-a15 exist past the end of the struct. */
- *childregs = *regs;
-
/* Create a call4 dummy-frame: a0 = 0, a1 = childregs. */
*((int*)childregs - 3) = (unsigned long)childregs;
*((int*)childregs - 4) = 0;
- childregs->areg[2] = 0;
- p->set_child_tid = p->clear_child_tid = NULL;
- p->thread.ra = MAKE_RA_FOR_CALL((unsigned long)ret_from_fork, 0x1);
p->thread.sp = (unsigned long)childregs;
- if (user_mode(regs)) {
+ if (!(p->flags & PF_KTHREAD)) {
+ struct pt_regs *regs = current_pt_regs();
+ unsigned long usp = usp_thread_fn ?
+ usp_thread_fn : regs->areg[1];
+ p->thread.ra = MAKE_RA_FOR_CALL(
+ (unsigned long)ret_from_fork, 0x1);
+
+ /* This does not copy all the regs.
+ * In a bout of brilliance or madness,
+ * ARs beyond a0-a15 exist past the end of the struct.
+ */
+ *childregs = *regs;
childregs->areg[1] = usp;
+ childregs->areg[2] = 0;
+
+ /* When sharing memory with the parent thread, the child
+ usually starts on a pristine stack, so we have to reset
+ windowbase, windowstart and wmask.
+ (Note that such a new thread is required to always create
+ an initial call4 frame)
+ The exception is vfork, where the new thread continues to
+ run on the parent's stack until it calls execve. This could
+ be a call8 or call12, which requires a legal stack frame
+ of the previous caller for the overflow handlers to work.
+ (Note that it's always legal to overflow live registers).
+ In this case, ensure to spill at least the stack pointer
+ of that frame. */
+
if (clone_flags & CLONE_VM) {
- childregs->wmask = 1; /* can't share live windows */
+ /* check that caller window is live and same stack */
+ int len = childregs->wmask & ~0xf;
+ if (regs->areg[1] == usp && len != 0) {
+ int callinc = (regs->areg[0] >> 30) & 3;
+ int caller_ars = XCHAL_NUM_AREGS - callinc * 4;
+ put_user(regs->areg[caller_ars+1],
+ (unsigned __user*)(usp - 12));
+ }
+ childregs->wmask = 1;
+ childregs->windowstart = 1;
+ childregs->windowbase = 0;
} else {
int len = childregs->wmask & ~0xf;
memcpy(&childregs->areg[XCHAL_NUM_AREGS - len/4],
@@ -230,11 +263,19 @@ int copy_thread(unsigned long clone_flags, unsigned long usp,
// FIXME: we need to set THREADPTR in thread_info...
if (clone_flags & CLONE_SETTLS)
childregs->areg[2] = childregs->areg[6];
-
} else {
- /* In kernel space, we start a new thread with a new stack. */
- childregs->wmask = 1;
- childregs->areg[1] = tos;
+ p->thread.ra = MAKE_RA_FOR_CALL(
+ (unsigned long)ret_from_kernel_thread, 1);
+
+ /* pass parameters to ret_from_kernel_thread:
+ * a2 = thread_fn, a3 = thread_fn arg
+ */
+ *((int *)childregs - 1) = thread_fn_arg;
+ *((int *)childregs - 2) = usp_thread_fn;
+
+ /* Childregs are only used when we're going to userspace
+ * in which case start_thread will set them up.
+ */
}
#if (XTENSA_HAVE_COPROCESSORS || XTENSA_HAVE_IO_PORTS)
@@ -330,32 +371,5 @@ long xtensa_clone(unsigned long clone_flags, unsigned long newsp,
void __user *child_tid, long a5,
struct pt_regs *regs)
{
- if (!newsp)
- newsp = regs->areg[1];
return do_fork(clone_flags, newsp, regs, 0, parent_tid, child_tid);
}
-
-/*
- * xtensa_execve() executes a new program.
- */
-
-asmlinkage
-long xtensa_execve(const char __user *name,
- const char __user *const __user *argv,
- const char __user *const __user *envp,
- long a3, long a4, long a5,
- struct pt_regs *regs)
-{
- long error;
- struct filename *filename;
-
- filename = getname(name);
- error = PTR_ERR(filename);
- if (IS_ERR(filename))
- goto out;
- error = do_execve(filename->name, argv, envp, regs);
- putname(filename);
-out:
- return error;
-}
-
diff --git a/arch/xtensa/kernel/syscall.c b/arch/xtensa/kernel/syscall.c
index a5c01e74d5d5..5702065f472a 100644
--- a/arch/xtensa/kernel/syscall.c
+++ b/arch/xtensa/kernel/syscall.c
@@ -32,10 +32,8 @@ typedef void (*syscall_t)(void);
syscall_t sys_call_table[__NR_syscall_count] /* FIXME __cacheline_aligned */= {
[0 ... __NR_syscall_count - 1] = (syscall_t)&sys_ni_syscall,
-#undef __SYSCALL
#define __SYSCALL(nr,symbol,nargs) [ nr ] = (syscall_t)symbol,
-#undef __KERNEL_SYSCALLS__
-#include <asm/unistd.h>
+#include <uapi/asm/unistd.h>
};
asmlinkage long xtensa_shmat(int shmid, char __user *shmaddr, int shmflg)
@@ -49,7 +47,8 @@ asmlinkage long xtensa_shmat(int shmid, char __user *shmaddr, int shmflg)
return (long)ret;
}
-asmlinkage long xtensa_fadvise64_64(int fd, int advice, unsigned long long offset, unsigned long long len)
+asmlinkage long xtensa_fadvise64_64(int fd, int advice,
+ unsigned long long offset, unsigned long long len)
{
return sys_fadvise64_64(fd, offset, len, advice);
}
diff --git a/arch/xtensa/kernel/xtensa_ksyms.c b/arch/xtensa/kernel/xtensa_ksyms.c
index a8b9f1fd1e17..afe058b24e6e 100644
--- a/arch/xtensa/kernel/xtensa_ksyms.c
+++ b/arch/xtensa/kernel/xtensa_ksyms.c
@@ -43,7 +43,6 @@ EXPORT_SYMBOL(__strncpy_user);
EXPORT_SYMBOL(clear_page);
EXPORT_SYMBOL(copy_page);
-EXPORT_SYMBOL(kernel_thread);
EXPORT_SYMBOL(empty_zero_page);
/*
diff --git a/block/Kconfig b/block/Kconfig
index 09acf1b39905..a7e40a7c8214 100644
--- a/block/Kconfig
+++ b/block/Kconfig
@@ -89,7 +89,7 @@ config BLK_DEV_INTEGRITY
config BLK_DEV_THROTTLING
bool "Block layer bio throttling support"
- depends on BLK_CGROUP=y && EXPERIMENTAL
+ depends on BLK_CGROUP=y
default n
---help---
Block layer bio throttling support. It can be used to limit
diff --git a/block/blk-cgroup.c b/block/blk-cgroup.c
index cafcd7431189..d0b770391ad4 100644
--- a/block/blk-cgroup.c
+++ b/block/blk-cgroup.c
@@ -285,6 +285,13 @@ static void blkg_destroy_all(struct request_queue *q)
blkg_destroy(blkg);
spin_unlock(&blkcg->lock);
}
+
+ /*
+ * root blkg is destroyed. Just clear the pointer since
+ * root_rl does not take reference on root blkg.
+ */
+ q->root_blkg = NULL;
+ q->root_rl.blkg = NULL;
}
static void blkg_rcu_free(struct rcu_head *rcu_head)
@@ -326,6 +333,9 @@ struct request_list *__blk_queue_next_rl(struct request_list *rl,
*/
if (rl == &q->root_rl) {
ent = &q->blkg_list;
+ /* There are no more block groups, hence no request lists */
+ if (list_empty(ent))
+ return NULL;
} else {
blkg = container_of(rl, struct blkcg_gq, rl);
ent = &blkg->q_node;
diff --git a/block/blk-core.c b/block/blk-core.c
index a33870b1847b..3c95c4d6e31a 100644
--- a/block/blk-core.c
+++ b/block/blk-core.c
@@ -2868,7 +2868,8 @@ static int plug_rq_cmp(void *priv, struct list_head *a, struct list_head *b)
struct request *rqa = container_of(a, struct request, queuelist);
struct request *rqb = container_of(b, struct request, queuelist);
- return !(rqa->q <= rqb->q);
+ return !(rqa->q < rqb->q ||
+ (rqa->q == rqb->q && blk_rq_pos(rqa) < blk_rq_pos(rqb)));
}
/*
diff --git a/drivers/acpi/glue.c b/drivers/acpi/glue.c
index d1a2d74033e9..08373086cd7e 100644
--- a/drivers/acpi/glue.c
+++ b/drivers/acpi/glue.c
@@ -159,6 +159,7 @@ static int acpi_bind_one(struct device *dev, acpi_handle handle)
if (physical_node->node_id >= ACPI_MAX_PHYSICAL_NODE) {
retval = -ENOSPC;
mutex_unlock(&acpi_dev->physical_node_lock);
+ kfree(physical_node);
goto err;
}
diff --git a/drivers/acpi/processor_driver.c b/drivers/acpi/processor_driver.c
index e78c2a52ea46..bd4e5dca3ff7 100644
--- a/drivers/acpi/processor_driver.c
+++ b/drivers/acpi/processor_driver.c
@@ -409,6 +409,7 @@ static void acpi_processor_notify(struct acpi_device *device, u32 event)
acpi_bus_generate_proc_event(device, event, 0);
acpi_bus_generate_netlink_event(device->pnp.device_class,
dev_name(&device->dev), event, 0);
+ break;
default:
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
"Unsupported event [0x%x]\n", event));
diff --git a/drivers/base/power/domain.c b/drivers/base/power/domain.c
index c22b869245d9..96b71b6536d6 100644
--- a/drivers/base/power/domain.c
+++ b/drivers/base/power/domain.c
@@ -1862,7 +1862,7 @@ int pm_genpd_attach_cpuidle(struct generic_pm_domain *genpd, int state)
cpuidle_drv = cpuidle_driver_ref();
if (!cpuidle_drv) {
ret = -ENODEV;
- goto out;
+ goto err_drv;
}
if (cpuidle_drv->state_count <= state) {
ret = -EINVAL;
@@ -1884,6 +1884,9 @@ int pm_genpd_attach_cpuidle(struct generic_pm_domain *genpd, int state)
err:
cpuidle_driver_unref();
+
+ err_drv:
+ kfree(cpu_data);
goto out;
}
diff --git a/drivers/bcma/main.c b/drivers/bcma/main.c
index 432aeeedfd5e..d865470bc951 100644
--- a/drivers/bcma/main.c
+++ b/drivers/bcma/main.c
@@ -158,9 +158,10 @@ static int bcma_register_cores(struct bcma_bus *bus)
static void bcma_unregister_cores(struct bcma_bus *bus)
{
- struct bcma_device *core;
+ struct bcma_device *core, *tmp;
- list_for_each_entry(core, &bus->cores, list) {
+ list_for_each_entry_safe(core, tmp, &bus->cores, list) {
+ list_del(&core->list);
if (core->dev_registered)
device_unregister(&core->dev);
}
diff --git a/drivers/block/Kconfig b/drivers/block/Kconfig
index f529407db93f..824e09c4d0d7 100644
--- a/drivers/block/Kconfig
+++ b/drivers/block/Kconfig
@@ -131,6 +131,7 @@ config BLK_CPQ_DA
config BLK_CPQ_CISS_DA
tristate "Compaq Smart Array 5xxx support"
depends on PCI
+ select CHECK_SIGNATURE
help
This is the driver for Compaq Smart Array 5xxx controllers.
Everyone using these boards should say Y here.
@@ -166,8 +167,8 @@ config BLK_DEV_DAC960
module will be called DAC960.
config BLK_DEV_UMEM
- tristate "Micro Memory MM5415 Battery Backed RAM support (EXPERIMENTAL)"
- depends on PCI && EXPERIMENTAL
+ tristate "Micro Memory MM5415 Battery Backed RAM support"
+ depends on PCI
---help---
Saying Y here will include support for the MM5415 family of
battery backed (Non-volatile) RAM cards.
@@ -430,8 +431,8 @@ config CDROM_PKTCDVD_BUFFERS
a disc is opened for writing.
config CDROM_PKTCDVD_WCACHE
- bool "Enable write caching (EXPERIMENTAL)"
- depends on CDROM_PKTCDVD && EXPERIMENTAL
+ bool "Enable write caching"
+ depends on CDROM_PKTCDVD
help
If enabled, write caching will be set for the CD-R/W device. For now
this option is dangerous unless the CD-RW media is known good, as we
@@ -508,8 +509,8 @@ config XEN_BLKDEV_BACKEND
config VIRTIO_BLK
- tristate "Virtio block driver (EXPERIMENTAL)"
- depends on EXPERIMENTAL && VIRTIO
+ tristate "Virtio block driver"
+ depends on VIRTIO
---help---
This is the virtual block driver for virtio. It can be used with
lguest or QEMU based VMMs (like KVM or Xen). Say Y or M.
@@ -528,7 +529,7 @@ config BLK_DEV_HD
config BLK_DEV_RBD
tristate "Rados block device (RBD)"
- depends on INET && EXPERIMENTAL && BLOCK
+ depends on INET && BLOCK
select CEPH_LIB
select LIBCRC32C
select CRYPTO_AES
diff --git a/drivers/block/cciss.c b/drivers/block/cciss.c
index b0f553b26d0f..ca83f96756ad 100644
--- a/drivers/block/cciss.c
+++ b/drivers/block/cciss.c
@@ -5205,7 +5205,6 @@ static void cciss_shutdown(struct pci_dev *pdev)
return;
}
/* write all data in the battery backed cache to disk */
- memset(flush_buf, 0, 4);
return_code = sendcmd_withirq(h, CCISS_CACHE_FLUSH, flush_buf,
4, 0, CTLR_LUNID, TYPE_CMD);
kfree(flush_buf);
diff --git a/drivers/block/floppy.c b/drivers/block/floppy.c
index 17c675c52295..1c49d7173966 100644
--- a/drivers/block/floppy.c
+++ b/drivers/block/floppy.c
@@ -4109,12 +4109,19 @@ static struct platform_driver floppy_driver = {
static struct platform_device floppy_device[N_DRIVE];
+static bool floppy_available(int drive)
+{
+ if (!(allowed_drive_mask & (1 << drive)))
+ return false;
+ if (fdc_state[FDC(drive)].version == FDC_NONE)
+ return false;
+ return true;
+}
+
static struct kobject *floppy_find(dev_t dev, int *part, void *data)
{
int drive = (*part & 3) | ((*part & 0x80) >> 5);
- if (drive >= N_DRIVE ||
- !(allowed_drive_mask & (1 << drive)) ||
- fdc_state[FDC(drive)].version == FDC_NONE)
+ if (drive >= N_DRIVE || !floppy_available(drive))
return NULL;
if (((*part >> 2) & 0x1f) >= ARRAY_SIZE(floppy_type))
return NULL;
@@ -4124,8 +4131,7 @@ static struct kobject *floppy_find(dev_t dev, int *part, void *data)
static int __init do_floppy_init(void)
{
- int i, unit, drive;
- int err, dr;
+ int i, unit, drive, err;
set_debugt();
interruptjiffies = resultjiffies = jiffies;
@@ -4137,34 +4143,32 @@ static int __init do_floppy_init(void)
raw_cmd = NULL;
- for (dr = 0; dr < N_DRIVE; dr++) {
- disks[dr] = alloc_disk(1);
- if (!disks[dr]) {
- err = -ENOMEM;
- goto out_put_disk;
- }
+ floppy_wq = alloc_ordered_workqueue("floppy", 0);
+ if (!floppy_wq)
+ return -ENOMEM;
- floppy_wq = alloc_ordered_workqueue("floppy", 0);
- if (!floppy_wq) {
+ for (drive = 0; drive < N_DRIVE; drive++) {
+ disks[drive] = alloc_disk(1);
+ if (!disks[drive]) {
err = -ENOMEM;
goto out_put_disk;
}
- disks[dr]->queue = blk_init_queue(do_fd_request, &floppy_lock);
- if (!disks[dr]->queue) {
+ disks[drive]->queue = blk_init_queue(do_fd_request, &floppy_lock);
+ if (!disks[drive]->queue) {
err = -ENOMEM;
- goto out_destroy_workq;
+ goto out_put_disk;
}
- blk_queue_max_hw_sectors(disks[dr]->queue, 64);
- disks[dr]->major = FLOPPY_MAJOR;
- disks[dr]->first_minor = TOMINOR(dr);
- disks[dr]->fops = &floppy_fops;
- sprintf(disks[dr]->disk_name, "fd%d", dr);
+ blk_queue_max_hw_sectors(disks[drive]->queue, 64);
+ disks[drive]->major = FLOPPY_MAJOR;
+ disks[drive]->first_minor = TOMINOR(drive);
+ disks[drive]->fops = &floppy_fops;
+ sprintf(disks[drive]->disk_name, "fd%d", drive);
- init_timer(&motor_off_timer[dr]);
- motor_off_timer[dr].data = dr;
- motor_off_timer[dr].function = motor_off_callback;
+ init_timer(&motor_off_timer[drive]);
+ motor_off_timer[drive].data = drive;
+ motor_off_timer[drive].function = motor_off_callback;
}
err = register_blkdev(FLOPPY_MAJOR, "fd");
@@ -4282,9 +4286,7 @@ static int __init do_floppy_init(void)
}
for (drive = 0; drive < N_DRIVE; drive++) {
- if (!(allowed_drive_mask & (1 << drive)))
- continue;
- if (fdc_state[FDC(drive)].version == FDC_NONE)
+ if (!floppy_available(drive))
continue;
floppy_device[drive].name = floppy_device_name;
@@ -4293,7 +4295,7 @@ static int __init do_floppy_init(void)
err = platform_device_register(&floppy_device[drive]);
if (err)
- goto out_release_dma;
+ goto out_remove_drives;
err = device_create_file(&floppy_device[drive].dev,
&dev_attr_cmos);
@@ -4311,29 +4313,34 @@ static int __init do_floppy_init(void)
out_unreg_platform_dev:
platform_device_unregister(&floppy_device[drive]);
+out_remove_drives:
+ while (drive--) {
+ if (floppy_available(drive)) {
+ del_gendisk(disks[drive]);
+ device_remove_file(&floppy_device[drive].dev, &dev_attr_cmos);
+ platform_device_unregister(&floppy_device[drive]);
+ }
+ }
out_release_dma:
if (atomic_read(&usage_count))
floppy_release_irq_and_dma();
out_unreg_region:
blk_unregister_region(MKDEV(FLOPPY_MAJOR, 0), 256);
platform_driver_unregister(&floppy_driver);
-out_destroy_workq:
- destroy_workqueue(floppy_wq);
out_unreg_blkdev:
unregister_blkdev(FLOPPY_MAJOR, "fd");
out_put_disk:
- while (dr--) {
- del_timer_sync(&motor_off_timer[dr]);
- if (disks[dr]->queue) {
- blk_cleanup_queue(disks[dr]->queue);
- /*
- * put_disk() is not paired with add_disk() and
- * will put queue reference one extra time. fix it.
- */
- disks[dr]->queue = NULL;
+ for (drive = 0; drive < N_DRIVE; drive++) {
+ if (!disks[drive])
+ break;
+ if (disks[drive]->queue) {
+ del_timer_sync(&motor_off_timer[drive]);
+ blk_cleanup_queue(disks[drive]->queue);
+ disks[drive]->queue = NULL;
}
- put_disk(disks[dr]);
+ put_disk(disks[drive]);
}
+ destroy_workqueue(floppy_wq);
return err;
}
@@ -4551,8 +4558,7 @@ static void __exit floppy_module_exit(void)
for (drive = 0; drive < N_DRIVE; drive++) {
del_timer_sync(&motor_off_timer[drive]);
- if ((allowed_drive_mask & (1 << drive)) &&
- fdc_state[FDC(drive)].version != FDC_NONE) {
+ if (floppy_available(drive)) {
del_gendisk(disks[drive]);
device_remove_file(&floppy_device[drive].dev, &dev_attr_cmos);
platform_device_unregister(&floppy_device[drive]);
diff --git a/drivers/block/loop.c b/drivers/block/loop.c
index e9d594fd12cb..54046e51160a 100644
--- a/drivers/block/loop.c
+++ b/drivers/block/loop.c
@@ -976,8 +976,21 @@ static int loop_clr_fd(struct loop_device *lo)
if (lo->lo_state != Lo_bound)
return -ENXIO;
- if (lo->lo_refcnt > 1) /* we needed one fd for the ioctl */
- return -EBUSY;
+ /*
+ * If we've explicitly asked to tear down the loop device,
+ * and it has an elevated reference count, set it for auto-teardown when
+ * the last reference goes away. This stops $!~#$@ udev from
+ * preventing teardown because it decided that it needs to run blkid on
+ * the loopback device whenever they appear. xfstests is notorious for
+ * failing tests because blkid via udev races with a losetup
+ * <dev>/do something like mkfs/losetup -d <dev> causing the losetup -d
+ * command to fail with EBUSY.
+ */
+ if (lo->lo_refcnt > 1) {
+ lo->lo_flags |= LO_FLAGS_AUTOCLEAR;
+ mutex_unlock(&lo->lo_ctl_mutex);
+ return 0;
+ }
if (filp == NULL)
return -EINVAL;
diff --git a/drivers/block/mtip32xx/mtip32xx.c b/drivers/block/mtip32xx/mtip32xx.c
index f946d31d6917..adc6f36564cf 100644
--- a/drivers/block/mtip32xx/mtip32xx.c
+++ b/drivers/block/mtip32xx/mtip32xx.c
@@ -2035,8 +2035,9 @@ static unsigned int implicit_sector(unsigned char command,
}
return rv;
}
-
-static void mtip_set_timeout(struct host_to_dev_fis *fis, unsigned int *timeout)
+static void mtip_set_timeout(struct driver_data *dd,
+ struct host_to_dev_fis *fis,
+ unsigned int *timeout, u8 erasemode)
{
switch (fis->command) {
case ATA_CMD_DOWNLOAD_MICRO:
@@ -2044,7 +2045,10 @@ static void mtip_set_timeout(struct host_to_dev_fis *fis, unsigned int *timeout)
break;
case ATA_CMD_SEC_ERASE_UNIT:
case 0xFC:
- *timeout = 240000; /* 4 minutes */
+ if (erasemode)
+ *timeout = ((*(dd->port->identify + 90) * 2) * 60000);
+ else
+ *timeout = ((*(dd->port->identify + 89) * 2) * 60000);
break;
case ATA_CMD_STANDBYNOW1:
*timeout = 120000; /* 2 minutes */
@@ -2087,6 +2091,7 @@ static int exec_drive_taskfile(struct driver_data *dd,
unsigned int transfer_size;
unsigned long task_file_data;
int intotal = outtotal + req_task->out_size;
+ int erasemode = 0;
taskout = req_task->out_size;
taskin = req_task->in_size;
@@ -2212,7 +2217,13 @@ static int exec_drive_taskfile(struct driver_data *dd,
fis.lba_hi,
fis.device);
- mtip_set_timeout(&fis, &timeout);
+ /* check for erase mode support during secure erase.*/
+ if ((fis.command == ATA_CMD_SEC_ERASE_UNIT)
+ && (outbuf[0] & MTIP_SEC_ERASE_MODE)) {
+ erasemode = 1;
+ }
+
+ mtip_set_timeout(dd, &fis, &timeout, erasemode);
/* Determine the correct transfer size.*/
if (force_single_sector)
diff --git a/drivers/block/mtip32xx/mtip32xx.h b/drivers/block/mtip32xx/mtip32xx.h
index 18627a1d04c5..5f4a917bd8bb 100644
--- a/drivers/block/mtip32xx/mtip32xx.h
+++ b/drivers/block/mtip32xx/mtip32xx.h
@@ -33,6 +33,9 @@
/* offset of Device Control register in PCIe extended capabilites space */
#define PCIE_CONFIG_EXT_DEVICE_CONTROL_OFFSET 0x48
+/* check for erase mode support during secure erase */
+#define MTIP_SEC_ERASE_MODE 0x3
+
/* # of times to retry timed out/failed IOs */
#define MTIP_MAX_RETRIES 2
diff --git a/drivers/block/xen-blkback/common.h b/drivers/block/xen-blkback/common.h
index 9ad3b5ec1dc1..9a54623e52d7 100644
--- a/drivers/block/xen-blkback/common.h
+++ b/drivers/block/xen-blkback/common.h
@@ -158,8 +158,8 @@ struct xen_vbd {
struct block_device *bdev;
/* Cached size parameter. */
sector_t size;
- bool flush_support;
- bool discard_secure;
+ unsigned int flush_support:1;
+ unsigned int discard_secure:1;
};
struct backend_info;
diff --git a/drivers/block/xen-blkback/xenbus.c b/drivers/block/xen-blkback/xenbus.c
index 4f66171c6683..f58434c2617c 100644
--- a/drivers/block/xen-blkback/xenbus.c
+++ b/drivers/block/xen-blkback/xenbus.c
@@ -105,11 +105,10 @@ static struct xen_blkif *xen_blkif_alloc(domid_t domid)
{
struct xen_blkif *blkif;
- blkif = kmem_cache_alloc(xen_blkif_cachep, GFP_KERNEL);
+ blkif = kmem_cache_zalloc(xen_blkif_cachep, GFP_KERNEL);
if (!blkif)
return ERR_PTR(-ENOMEM);
- memset(blkif, 0, sizeof(*blkif));
blkif->domid = domid;
spin_lock_init(&blkif->blk_ring_lock);
atomic_set(&blkif->refcnt, 1);
@@ -196,7 +195,7 @@ static void xen_blkif_disconnect(struct xen_blkif *blkif)
}
}
-void xen_blkif_free(struct xen_blkif *blkif)
+static void xen_blkif_free(struct xen_blkif *blkif)
{
if (!atomic_dec_and_test(&blkif->refcnt))
BUG();
@@ -257,7 +256,7 @@ static struct attribute_group xen_vbdstat_group = {
VBD_SHOW(physical_device, "%x:%x\n", be->major, be->minor);
VBD_SHOW(mode, "%s\n", be->mode);
-int xenvbd_sysfs_addif(struct xenbus_device *dev)
+static int xenvbd_sysfs_addif(struct xenbus_device *dev)
{
int error;
@@ -281,7 +280,7 @@ fail1: device_remove_file(&dev->dev, &dev_attr_physical_device);
return error;
}
-void xenvbd_sysfs_delif(struct xenbus_device *dev)
+static void xenvbd_sysfs_delif(struct xenbus_device *dev)
{
sysfs_remove_group(&dev->dev.kobj, &xen_vbdstat_group);
device_remove_file(&dev->dev, &dev_attr_mode);
diff --git a/drivers/cpufreq/cpufreq_stats.c b/drivers/cpufreq/cpufreq_stats.c
index b40ee1403be9..399831690fed 100644
--- a/drivers/cpufreq/cpufreq_stats.c
+++ b/drivers/cpufreq/cpufreq_stats.c
@@ -328,6 +328,7 @@ static int __cpuinit cpufreq_stat_cpu_callback(struct notifier_block *nfb,
cpufreq_update_policy(cpu);
break;
case CPU_DOWN_PREPARE:
+ case CPU_DOWN_PREPARE_FROZEN:
cpufreq_stats_free_sysfs(cpu);
break;
case CPU_DEAD:
diff --git a/drivers/cpufreq/powernow-k8.c b/drivers/cpufreq/powernow-k8.c
index 129e80bfff22..c16a3a593ba4 100644
--- a/drivers/cpufreq/powernow-k8.c
+++ b/drivers/cpufreq/powernow-k8.c
@@ -1052,14 +1052,7 @@ static int powernowk8_target(struct cpufreq_policy *pol,
struct powernowk8_target_arg pta = { .pol = pol, .targfreq = targfreq,
.relation = relation };
- /*
- * Must run on @pol->cpu. cpufreq core is responsible for ensuring
- * that we're bound to the current CPU and pol->cpu stays online.
- */
- if (smp_processor_id() == pol->cpu)
- return powernowk8_target_fn(&pta);
- else
- return work_on_cpu(pol->cpu, powernowk8_target_fn, &pta);
+ return work_on_cpu(pol->cpu, powernowk8_target_fn, &pta);
}
/* Driver entry point to verify the policy and range of frequencies */
diff --git a/drivers/dma/imx-dma.c b/drivers/dma/imx-dma.c
index f11b5b2b1a1c..7d9554cc4976 100644
--- a/drivers/dma/imx-dma.c
+++ b/drivers/dma/imx-dma.c
@@ -474,8 +474,10 @@ static int imxdma_xfer_desc(struct imxdma_desc *d)
slot = i;
break;
}
- if (slot < 0)
+ if (slot < 0) {
+ spin_unlock_irqrestore(&imxdma->lock, flags);
return -EBUSY;
+ }
imxdma->slots_2d[slot].xsr = d->x;
imxdma->slots_2d[slot].ysr = d->y;
diff --git a/drivers/dma/sirf-dma.c b/drivers/dma/sirf-dma.c
index 64385cde044b..d451caace806 100644
--- a/drivers/dma/sirf-dma.c
+++ b/drivers/dma/sirf-dma.c
@@ -109,7 +109,7 @@ static void sirfsoc_dma_execute(struct sirfsoc_dma_chan *schan)
sdesc = list_first_entry(&schan->queued, struct sirfsoc_dma_desc,
node);
/* Move the first queued descriptor to active list */
- list_move_tail(&schan->queued, &schan->active);
+ list_move_tail(&sdesc->node, &schan->active);
/* Start the DMA transfer */
writel_relaxed(sdesc->width, sdma->base + SIRFSOC_DMA_WIDTH_0 +
@@ -428,7 +428,7 @@ static struct dma_async_tx_descriptor *sirfsoc_dma_prep_interleaved(
unsigned long iflags;
int ret;
- if ((xt->dir != DMA_MEM_TO_DEV) || (xt->dir != DMA_DEV_TO_MEM)) {
+ if ((xt->dir != DMA_MEM_TO_DEV) && (xt->dir != DMA_DEV_TO_MEM)) {
ret = -EINVAL;
goto err_dir;
}
diff --git a/drivers/gpio/gpio-74x164.c b/drivers/gpio/gpio-74x164.c
index ed3e55161bdc..f05e54258ffb 100644
--- a/drivers/gpio/gpio-74x164.c
+++ b/drivers/gpio/gpio-74x164.c
@@ -153,7 +153,7 @@ static int __devinit gen_74x164_probe(struct spi_device *spi)
}
chip->gpio_chip.ngpio = GEN_74X164_NUMBER_GPIOS * chip->registers;
- chip->buffer = devm_kzalloc(&spi->dev, chip->gpio_chip.ngpio, GFP_KERNEL);
+ chip->buffer = devm_kzalloc(&spi->dev, chip->registers, GFP_KERNEL);
if (!chip->buffer) {
ret = -ENOMEM;
goto exit_destroy;
diff --git a/drivers/gpio/gpio-mvebu.c b/drivers/gpio/gpio-mvebu.c
index 7a874129e5d8..cf7afb9eb61a 100644
--- a/drivers/gpio/gpio-mvebu.c
+++ b/drivers/gpio/gpio-mvebu.c
@@ -244,6 +244,8 @@ static int mvebu_gpio_direction_output(struct gpio_chip *chip, unsigned pin,
if (ret)
return ret;
+ mvebu_gpio_set(chip, pin, value);
+
spin_lock_irqsave(&mvchip->lock, flags);
u = readl_relaxed(mvebu_gpioreg_io_conf(mvchip));
u &= ~(1 << pin);
@@ -644,7 +646,7 @@ static int __devinit mvebu_gpio_probe(struct platform_device *pdev)
ct->handler = handle_edge_irq;
ct->chip.name = mvchip->chip.label;
- irq_setup_generic_chip(gc, IRQ_MSK(ngpios), IRQ_GC_INIT_MASK_CACHE,
+ irq_setup_generic_chip(gc, IRQ_MSK(ngpios), 0,
IRQ_NOREQUEST, IRQ_LEVEL | IRQ_NOPROBE);
/* Setup irq domain on top of the generic chip. */
diff --git a/drivers/gpio/gpio-omap.c b/drivers/gpio/gpio-omap.c
index 94cbc842fbc3..d335af1d4d85 100644
--- a/drivers/gpio/gpio-omap.c
+++ b/drivers/gpio/gpio-omap.c
@@ -251,6 +251,40 @@ static void _set_gpio_debounce(struct gpio_bank *bank, unsigned gpio,
}
}
+/**
+ * _clear_gpio_debounce - clear debounce settings for a gpio
+ * @bank: the gpio bank we're acting upon
+ * @gpio: the gpio number on this @gpio
+ *
+ * If a gpio is using debounce, then clear the debounce enable bit and if
+ * this is the only gpio in this bank using debounce, then clear the debounce
+ * time too. The debounce clock will also be disabled when calling this function
+ * if this is the only gpio in the bank using debounce.
+ */
+static void _clear_gpio_debounce(struct gpio_bank *bank, unsigned gpio)
+{
+ u32 gpio_bit = GPIO_BIT(bank, gpio);
+
+ if (!bank->dbck_flag)
+ return;
+
+ if (!(bank->dbck_enable_mask & gpio_bit))
+ return;
+
+ bank->dbck_enable_mask &= ~gpio_bit;
+ bank->context.debounce_en &= ~gpio_bit;
+ __raw_writel(bank->context.debounce_en,
+ bank->base + bank->regs->debounce_en);
+
+ if (!bank->dbck_enable_mask) {
+ bank->context.debounce = 0;
+ __raw_writel(bank->context.debounce, bank->base +
+ bank->regs->debounce);
+ clk_disable(bank->dbck);
+ bank->dbck_enabled = false;
+ }
+}
+
static inline void set_gpio_trigger(struct gpio_bank *bank, int gpio,
unsigned trigger)
{
@@ -539,6 +573,7 @@ static void _reset_gpio(struct gpio_bank *bank, int gpio)
_set_gpio_irqenable(bank, gpio, 0);
_clear_gpio_irqstatus(bank, gpio);
_set_gpio_triggering(bank, GPIO_INDEX(bank, gpio), IRQ_TYPE_NONE);
+ _clear_gpio_debounce(bank, gpio);
}
/* Use disable_irq_wake() and enable_irq_wake() functions from drivers */
diff --git a/drivers/gpio/gpio-timberdale.c b/drivers/gpio/gpio-timberdale.c
index 031c6adf5b65..1a3e2b9b4772 100644
--- a/drivers/gpio/gpio-timberdale.c
+++ b/drivers/gpio/gpio-timberdale.c
@@ -116,7 +116,7 @@ static void timbgpio_irq_disable(struct irq_data *d)
unsigned long flags;
spin_lock_irqsave(&tgpio->lock, flags);
- tgpio->last_ier &= ~(1 << offset);
+ tgpio->last_ier &= ~(1UL << offset);
iowrite32(tgpio->last_ier, tgpio->membase + TGPIO_IER);
spin_unlock_irqrestore(&tgpio->lock, flags);
}
@@ -128,7 +128,7 @@ static void timbgpio_irq_enable(struct irq_data *d)
unsigned long flags;
spin_lock_irqsave(&tgpio->lock, flags);
- tgpio->last_ier |= 1 << offset;
+ tgpio->last_ier |= 1UL << offset;
iowrite32(tgpio->last_ier, tgpio->membase + TGPIO_IER);
spin_unlock_irqrestore(&tgpio->lock, flags);
}
diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c
index 5d6c71edc739..1c8d9e3380e1 100644
--- a/drivers/gpio/gpiolib.c
+++ b/drivers/gpio/gpiolib.c
@@ -623,9 +623,11 @@ static ssize_t export_store(struct class *class,
*/
status = gpio_request(gpio, "sysfs");
- if (status < 0)
+ if (status < 0) {
+ if (status == -EPROBE_DEFER)
+ status = -ENODEV;
goto done;
-
+ }
status = gpio_export(gpio, true);
if (status < 0)
gpio_free(gpio);
@@ -1191,8 +1193,10 @@ int gpio_request(unsigned gpio, const char *label)
spin_lock_irqsave(&gpio_lock, flags);
- if (!gpio_is_valid(gpio))
+ if (!gpio_is_valid(gpio)) {
+ status = -EINVAL;
goto done;
+ }
desc = &gpio_desc[gpio];
chip = desc->chip;
if (chip == NULL)
diff --git a/drivers/gpu/drm/nouveau/core/core/mm.c b/drivers/gpu/drm/nouveau/core/core/mm.c
index 4d6206448670..a6d3cd6490f7 100644
--- a/drivers/gpu/drm/nouveau/core/core/mm.c
+++ b/drivers/gpu/drm/nouveau/core/core/mm.c
@@ -218,13 +218,16 @@ nouveau_mm_init(struct nouveau_mm *mm, u32 offset, u32 length, u32 block)
node = kzalloc(sizeof(*node), GFP_KERNEL);
if (!node)
return -ENOMEM;
- node->offset = roundup(offset, mm->block_size);
- node->length = rounddown(offset + length, mm->block_size) - node->offset;
+
+ if (length) {
+ node->offset = roundup(offset, mm->block_size);
+ node->length = rounddown(offset + length, mm->block_size);
+ node->length -= node->offset;
+ }
list_add_tail(&node->nl_entry, &mm->nodes);
list_add_tail(&node->fl_entry, &mm->free);
mm->heap_nodes++;
- mm->heap_size += length;
return 0;
}
diff --git a/drivers/gpu/drm/nouveau/core/include/core/mm.h b/drivers/gpu/drm/nouveau/core/include/core/mm.h
index 9ee9bf4028ca..975137ba34a6 100644
--- a/drivers/gpu/drm/nouveau/core/include/core/mm.h
+++ b/drivers/gpu/drm/nouveau/core/include/core/mm.h
@@ -19,7 +19,6 @@ struct nouveau_mm {
u32 block_size;
int heap_nodes;
- u32 heap_size;
};
int nouveau_mm_init(struct nouveau_mm *, u32 offset, u32 length, u32 block);
diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/nv50.c b/drivers/gpu/drm/nouveau/core/subdev/fb/nv50.c
index 27fb1af7a779..5f570806143a 100644
--- a/drivers/gpu/drm/nouveau/core/subdev/fb/nv50.c
+++ b/drivers/gpu/drm/nouveau/core/subdev/fb/nv50.c
@@ -219,13 +219,11 @@ nv50_fb_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
((priv->base.ram.size & 0x000000ff) << 32);
tags = nv_rd32(priv, 0x100320);
- if (tags) {
- ret = nouveau_mm_init(&priv->base.tags, 0, tags, 1);
- if (ret)
- return ret;
+ ret = nouveau_mm_init(&priv->base.tags, 0, tags, 1);
+ if (ret)
+ return ret;
- nv_debug(priv, "%d compression tags\n", tags);
- }
+ nv_debug(priv, "%d compression tags\n", tags);
size = (priv->base.ram.size >> 12) - rsvd_head - rsvd_tail;
switch (device->chipset) {
diff --git a/drivers/gpu/drm/nouveau/core/subdev/i2c/base.c b/drivers/gpu/drm/nouveau/core/subdev/i2c/base.c
index 3d2c88310f98..dbfc2abf0cfe 100644
--- a/drivers/gpu/drm/nouveau/core/subdev/i2c/base.c
+++ b/drivers/gpu/drm/nouveau/core/subdev/i2c/base.c
@@ -292,7 +292,7 @@ nouveau_i2c_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
case DCB_I2C_NVIO_BIT:
port->drive = info.drive & 0x0f;
if (device->card_type < NV_D0) {
- if (info.drive >= ARRAY_SIZE(nv50_i2c_port))
+ if (port->drive >= ARRAY_SIZE(nv50_i2c_port))
break;
port->drive = nv50_i2c_port[port->drive];
port->sense = port->drive;
diff --git a/drivers/gpu/drm/nouveau/nouveau_display.c b/drivers/gpu/drm/nouveau/nouveau_display.c
index d2f8ffeed742..86124b131f4f 100644
--- a/drivers/gpu/drm/nouveau/nouveau_display.c
+++ b/drivers/gpu/drm/nouveau/nouveau_display.c
@@ -290,6 +290,7 @@ nouveau_display_create(struct drm_device *dev)
struct nouveau_drm *drm = nouveau_drm(dev);
struct nouveau_disp *pdisp = nouveau_disp(drm->device);
struct nouveau_display *disp;
+ u32 pclass = dev->pdev->class >> 8;
int ret, gen;
disp = drm->display = kzalloc(sizeof(*disp), GFP_KERNEL);
@@ -360,23 +361,27 @@ nouveau_display_create(struct drm_device *dev)
drm_kms_helper_poll_init(dev);
drm_kms_helper_poll_disable(dev);
- if (nv_device(drm->device)->card_type < NV_50)
- ret = nv04_display_create(dev);
- else
- if (nv_device(drm->device)->card_type < NV_D0)
- ret = nv50_display_create(dev);
- else
- ret = nvd0_display_create(dev);
- if (ret)
- goto disp_create_err;
-
- if (dev->mode_config.num_crtc) {
- ret = drm_vblank_init(dev, dev->mode_config.num_crtc);
+ if (nouveau_modeset == 1 ||
+ (nouveau_modeset < 0 && pclass == PCI_CLASS_DISPLAY_VGA)) {
+ if (nv_device(drm->device)->card_type < NV_50)
+ ret = nv04_display_create(dev);
+ else
+ if (nv_device(drm->device)->card_type < NV_D0)
+ ret = nv50_display_create(dev);
+ else
+ ret = nvd0_display_create(dev);
if (ret)
- goto vblank_err;
+ goto disp_create_err;
+
+ if (dev->mode_config.num_crtc) {
+ ret = drm_vblank_init(dev, dev->mode_config.num_crtc);
+ if (ret)
+ goto vblank_err;
+ }
+
+ nouveau_backlight_init(dev);
}
- nouveau_backlight_init(dev);
return 0;
vblank_err:
@@ -395,7 +400,8 @@ nouveau_display_destroy(struct drm_device *dev)
nouveau_backlight_exit(dev);
drm_vblank_cleanup(dev);
- disp->dtor(dev);
+ if (disp->dtor)
+ disp->dtor(dev);
drm_kms_helper_poll_fini(dev);
drm_mode_config_cleanup(dev);
diff --git a/drivers/gpu/drm/nouveau/nouveau_drm.c b/drivers/gpu/drm/nouveau/nouveau_drm.c
index ccae8c26ae2b..0910125cbbc3 100644
--- a/drivers/gpu/drm/nouveau/nouveau_drm.c
+++ b/drivers/gpu/drm/nouveau/nouveau_drm.c
@@ -63,8 +63,9 @@ MODULE_PARM_DESC(noaccel, "disable kernel/abi16 acceleration");
static int nouveau_noaccel = 0;
module_param_named(noaccel, nouveau_noaccel, int, 0400);
-MODULE_PARM_DESC(modeset, "enable driver");
-static int nouveau_modeset = -1;
+MODULE_PARM_DESC(modeset, "enable driver (default: auto, "
+ "0 = disabled, 1 = enabled, 2 = headless)");
+int nouveau_modeset = -1;
module_param_named(modeset, nouveau_modeset, int, 0400);
static struct drm_driver driver;
@@ -363,7 +364,8 @@ nouveau_drm_unload(struct drm_device *dev)
nouveau_pm_fini(dev);
- nouveau_display_fini(dev);
+ if (dev->mode_config.num_crtc)
+ nouveau_display_fini(dev);
nouveau_display_destroy(dev);
nouveau_irq_fini(dev);
@@ -403,13 +405,15 @@ nouveau_drm_suspend(struct pci_dev *pdev, pm_message_t pm_state)
pm_state.event == PM_EVENT_PRETHAW)
return 0;
- NV_INFO(drm, "suspending fbcon...\n");
- nouveau_fbcon_set_suspend(dev, 1);
+ if (dev->mode_config.num_crtc) {
+ NV_INFO(drm, "suspending fbcon...\n");
+ nouveau_fbcon_set_suspend(dev, 1);
- NV_INFO(drm, "suspending display...\n");
- ret = nouveau_display_suspend(dev);
- if (ret)
- return ret;
+ NV_INFO(drm, "suspending display...\n");
+ ret = nouveau_display_suspend(dev);
+ if (ret)
+ return ret;
+ }
NV_INFO(drm, "evicting buffers...\n");
ttm_bo_evict_mm(&drm->ttm.bdev, TTM_PL_VRAM);
@@ -445,8 +449,10 @@ fail_client:
nouveau_client_init(&cli->base);
}
- NV_INFO(drm, "resuming display...\n");
- nouveau_display_resume(dev);
+ if (dev->mode_config.num_crtc) {
+ NV_INFO(drm, "resuming display...\n");
+ nouveau_display_resume(dev);
+ }
return ret;
}
@@ -486,8 +492,10 @@ nouveau_drm_resume(struct pci_dev *pdev)
nouveau_irq_postinstall(dev);
nouveau_pm_resume(dev);
- NV_INFO(drm, "resuming display...\n");
- nouveau_display_resume(dev);
+ if (dev->mode_config.num_crtc) {
+ NV_INFO(drm, "resuming display...\n");
+ nouveau_display_resume(dev);
+ }
return 0;
}
@@ -662,9 +670,7 @@ nouveau_drm_init(void)
#ifdef CONFIG_VGA_CONSOLE
if (vgacon_text_force())
nouveau_modeset = 0;
- else
#endif
- nouveau_modeset = 1;
}
if (!nouveau_modeset)
diff --git a/drivers/gpu/drm/nouveau/nouveau_drm.h b/drivers/gpu/drm/nouveau/nouveau_drm.h
index 819471217546..a10169927086 100644
--- a/drivers/gpu/drm/nouveau/nouveau_drm.h
+++ b/drivers/gpu/drm/nouveau/nouveau_drm.h
@@ -141,4 +141,6 @@ int nouveau_drm_resume(struct pci_dev *);
nv_info((cli), fmt, ##args); \
} while (0)
+extern int nouveau_modeset;
+
#endif
diff --git a/drivers/gpu/drm/nouveau/nouveau_irq.c b/drivers/gpu/drm/nouveau/nouveau_irq.c
index 9ca8afdb5549..1d8cb506a28a 100644
--- a/drivers/gpu/drm/nouveau/nouveau_irq.c
+++ b/drivers/gpu/drm/nouveau/nouveau_irq.c
@@ -61,13 +61,15 @@ nouveau_irq_handler(DRM_IRQ_ARGS)
nv_subdev(pmc)->intr(nv_subdev(pmc));
- if (device->card_type >= NV_D0) {
- if (nv_rd32(device, 0x000100) & 0x04000000)
- nvd0_display_intr(dev);
- } else
- if (device->card_type >= NV_50) {
- if (nv_rd32(device, 0x000100) & 0x04000000)
- nv50_display_intr(dev);
+ if (dev->mode_config.num_crtc) {
+ if (device->card_type >= NV_D0) {
+ if (nv_rd32(device, 0x000100) & 0x04000000)
+ nvd0_display_intr(dev);
+ } else
+ if (device->card_type >= NV_50) {
+ if (nv_rd32(device, 0x000100) & 0x04000000)
+ nv50_display_intr(dev);
+ }
}
return IRQ_HANDLED;
diff --git a/drivers/gpu/drm/nouveau/nv04_dac.c b/drivers/gpu/drm/nouveau/nv04_dac.c
index 347a3bd78d04..64f7020fb605 100644
--- a/drivers/gpu/drm/nouveau/nv04_dac.c
+++ b/drivers/gpu/drm/nouveau/nv04_dac.c
@@ -220,7 +220,7 @@ out:
NVWriteVgaCrtc(dev, 0, NV_CIO_CR_MODE_INDEX, saved_cr_mode);
if (blue == 0x18) {
- NV_INFO(drm, "Load detected on head A\n");
+ NV_DEBUG(drm, "Load detected on head A\n");
return connector_status_connected;
}
@@ -338,8 +338,8 @@ nv17_dac_detect(struct drm_encoder *encoder, struct drm_connector *connector)
if (nv17_dac_sample_load(encoder) &
NV_PRAMDAC_TEST_CONTROL_SENSEB_ALLHI) {
- NV_INFO(drm, "Load detected on output %c\n",
- '@' + ffs(dcb->or));
+ NV_DEBUG(drm, "Load detected on output %c\n",
+ '@' + ffs(dcb->or));
return connector_status_connected;
} else {
return connector_status_disconnected;
@@ -413,9 +413,9 @@ static void nv04_dac_commit(struct drm_encoder *encoder)
helper->dpms(encoder, DRM_MODE_DPMS_ON);
- NV_INFO(drm, "Output %s is running on CRTC %d using output %c\n",
- drm_get_connector_name(&nouveau_encoder_connector_get(nv_encoder)->base),
- nv_crtc->index, '@' + ffs(nv_encoder->dcb->or));
+ NV_DEBUG(drm, "Output %s is running on CRTC %d using output %c\n",
+ drm_get_connector_name(&nouveau_encoder_connector_get(nv_encoder)->base),
+ nv_crtc->index, '@' + ffs(nv_encoder->dcb->or));
}
void nv04_dac_update_dacclk(struct drm_encoder *encoder, bool enable)
@@ -461,8 +461,8 @@ static void nv04_dac_dpms(struct drm_encoder *encoder, int mode)
return;
nv_encoder->last_dpms = mode;
- NV_INFO(drm, "Setting dpms mode %d on vga encoder (output %d)\n",
- mode, nv_encoder->dcb->index);
+ NV_DEBUG(drm, "Setting dpms mode %d on vga encoder (output %d)\n",
+ mode, nv_encoder->dcb->index);
nv04_dac_update_dacclk(encoder, mode == DRM_MODE_DPMS_ON);
}
diff --git a/drivers/gpu/drm/nouveau/nv04_dfp.c b/drivers/gpu/drm/nouveau/nv04_dfp.c
index da55d7642c8c..184cdf806761 100644
--- a/drivers/gpu/drm/nouveau/nv04_dfp.c
+++ b/drivers/gpu/drm/nouveau/nv04_dfp.c
@@ -476,9 +476,9 @@ static void nv04_dfp_commit(struct drm_encoder *encoder)
helper->dpms(encoder, DRM_MODE_DPMS_ON);
- NV_INFO(drm, "Output %s is running on CRTC %d using output %c\n",
- drm_get_connector_name(&nouveau_encoder_connector_get(nv_encoder)->base),
- nv_crtc->index, '@' + ffs(nv_encoder->dcb->or));
+ NV_DEBUG(drm, "Output %s is running on CRTC %d using output %c\n",
+ drm_get_connector_name(&nouveau_encoder_connector_get(nv_encoder)->base),
+ nv_crtc->index, '@' + ffs(nv_encoder->dcb->or));
}
static void nv04_dfp_update_backlight(struct drm_encoder *encoder, int mode)
@@ -520,8 +520,8 @@ static void nv04_lvds_dpms(struct drm_encoder *encoder, int mode)
return;
nv_encoder->last_dpms = mode;
- NV_INFO(drm, "Setting dpms mode %d on lvds encoder (output %d)\n",
- mode, nv_encoder->dcb->index);
+ NV_DEBUG(drm, "Setting dpms mode %d on lvds encoder (output %d)\n",
+ mode, nv_encoder->dcb->index);
if (was_powersaving && is_powersaving_dpms(mode))
return;
@@ -565,8 +565,8 @@ static void nv04_tmds_dpms(struct drm_encoder *encoder, int mode)
return;
nv_encoder->last_dpms = mode;
- NV_INFO(drm, "Setting dpms mode %d on tmds encoder (output %d)\n",
- mode, nv_encoder->dcb->index);
+ NV_DEBUG(drm, "Setting dpms mode %d on tmds encoder (output %d)\n",
+ mode, nv_encoder->dcb->index);
nv04_dfp_update_backlight(encoder, mode);
nv04_dfp_update_fp_control(encoder, mode);
diff --git a/drivers/gpu/drm/nouveau/nv04_tv.c b/drivers/gpu/drm/nouveau/nv04_tv.c
index 099fbeda6e2e..62e826a139b3 100644
--- a/drivers/gpu/drm/nouveau/nv04_tv.c
+++ b/drivers/gpu/drm/nouveau/nv04_tv.c
@@ -75,8 +75,8 @@ static void nv04_tv_dpms(struct drm_encoder *encoder, int mode)
struct nv04_mode_state *state = &nv04_display(dev)->mode_reg;
uint8_t crtc1A;
- NV_INFO(drm, "Setting dpms mode %d on TV encoder (output %d)\n",
- mode, nv_encoder->dcb->index);
+ NV_DEBUG(drm, "Setting dpms mode %d on TV encoder (output %d)\n",
+ mode, nv_encoder->dcb->index);
state->pllsel &= ~(PLLSEL_TV_CRTC1_MASK | PLLSEL_TV_CRTC2_MASK);
@@ -167,9 +167,8 @@ static void nv04_tv_commit(struct drm_encoder *encoder)
helper->dpms(encoder, DRM_MODE_DPMS_ON);
- NV_INFO(drm, "Output %s is running on CRTC %d using output %c\n",
- drm_get_connector_name(&nouveau_encoder_connector_get(nv_encoder)->base), nv_crtc->index,
- '@' + ffs(nv_encoder->dcb->or));
+ NV_DEBUG(drm, "Output %s is running on CRTC %d using output %c\n",
+ drm_get_connector_name(&nouveau_encoder_connector_get(nv_encoder)->base), nv_crtc->index, '@' + ffs(nv_encoder->dcb->or));
}
static void nv04_tv_destroy(struct drm_encoder *encoder)
diff --git a/drivers/hid/hid-apple.c b/drivers/hid/hid-apple.c
index 06ebdbb6ea02..fd7722aecf77 100644
--- a/drivers/hid/hid-apple.c
+++ b/drivers/hid/hid-apple.c
@@ -522,6 +522,12 @@ static const struct hid_device_id apple_devices[] = {
.driver_data = APPLE_HAS_FN | APPLE_ISO_KEYBOARD },
{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING7_JIS),
.driver_data = APPLE_HAS_FN | APPLE_RDESC_JIS },
+ { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING7A_ANSI),
+ .driver_data = APPLE_HAS_FN },
+ { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING7A_ISO),
+ .driver_data = APPLE_HAS_FN | APPLE_ISO_KEYBOARD },
+ { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING7A_JIS),
+ .driver_data = APPLE_HAS_FN | APPLE_RDESC_JIS },
{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_ANSI),
.driver_data = APPLE_NUMLOCK_EMULATION | APPLE_HAS_FN },
{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_ISO),
diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c
index bd3971bf31bf..f4109fd657ff 100644
--- a/drivers/hid/hid-core.c
+++ b/drivers/hid/hid-core.c
@@ -1532,6 +1532,9 @@ static const struct hid_device_id hid_have_special_driver[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING7_ANSI) },
{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING7_ISO) },
{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING7_JIS) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING7A_ANSI) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING7A_ISO) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING7A_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) },
@@ -2139,6 +2142,9 @@ static const struct hid_device_id hid_mouse_ignore_list[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING7_ANSI) },
{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING7_ISO) },
{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING7_JIS) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING7A_ANSI) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING7A_ISO) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING7A_JIS) },
{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_FOUNTAIN_TP_ONLY) },
{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER1_TP_ONLY) },
{ }
diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h
index 269b50912a4a..9d7a42857ea1 100644
--- a/drivers/hid/hid-ids.h
+++ b/drivers/hid/hid-ids.h
@@ -118,6 +118,9 @@
#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 USB_DEVICE_ID_APPLE_WELLSPRING7A_ANSI 0x0259
+#define USB_DEVICE_ID_APPLE_WELLSPRING7A_ISO 0x025a
+#define USB_DEVICE_ID_APPLE_WELLSPRING7A_JIS 0x025b
#define USB_DEVICE_ID_APPLE_WELLSPRING6A_ANSI 0x0249
#define USB_DEVICE_ID_APPLE_WELLSPRING6A_ISO 0x024a
#define USB_DEVICE_ID_APPLE_WELLSPRING6A_JIS 0x024b
diff --git a/drivers/hid/hid-microsoft.c b/drivers/hid/hid-microsoft.c
index 3acdcfcc17df..f676c01bb471 100644
--- a/drivers/hid/hid-microsoft.c
+++ b/drivers/hid/hid-microsoft.c
@@ -28,22 +28,30 @@
#define MS_RDESC 0x08
#define MS_NOGET 0x10
#define MS_DUPLICATE_USAGES 0x20
+#define MS_RDESC_3K 0x40
-/*
- * Microsoft Wireless Desktop Receiver (Model 1028) has
- * 'Usage Min/Max' where it ought to have 'Physical Min/Max'
- */
static __u8 *ms_report_fixup(struct hid_device *hdev, __u8 *rdesc,
unsigned int *rsize)
{
unsigned long quirks = (unsigned long)hid_get_drvdata(hdev);
+ /*
+ * Microsoft Wireless Desktop Receiver (Model 1028) has
+ * 'Usage Min/Max' where it ought to have 'Physical Min/Max'
+ */
if ((quirks & MS_RDESC) && *rsize == 571 && rdesc[557] == 0x19 &&
rdesc[559] == 0x29) {
hid_info(hdev, "fixing up Microsoft Wireless Receiver Model 1028 report descriptor\n");
rdesc[557] = 0x35;
rdesc[559] = 0x45;
}
+ /* the same as above (s/usage/physical/) */
+ if ((quirks & MS_RDESC_3K) && *rsize == 106 &&
+ !memcmp((char []){ 0x19, 0x00, 0x29, 0xff },
+ &rdesc[94], 4)) {
+ rdesc[94] = 0x35;
+ rdesc[96] = 0x45;
+ }
return rdesc;
}
@@ -192,7 +200,7 @@ static const struct hid_device_id ms_devices[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_PRESENTER_8K_USB),
.driver_data = MS_PRESENTER },
{ HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_DIGITAL_MEDIA_3K),
- .driver_data = MS_ERGONOMY },
+ .driver_data = MS_ERGONOMY | MS_RDESC_3K },
{ HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_WIRELESS_OPTICAL_DESKTOP_3_0),
.driver_data = MS_NOGET },
{ HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_COMFORT_MOUSE_4500),
diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c
index 3eb02b94fc87..7867d69f0efe 100644
--- a/drivers/hid/hid-multitouch.c
+++ b/drivers/hid/hid-multitouch.c
@@ -210,8 +210,7 @@ static struct mt_class mt_classes[] = {
},
{ .name = MT_CLS_GENERALTOUCH_PWT_TENFINGERS,
.quirks = MT_QUIRK_NOT_SEEN_MEANS_UP |
- MT_QUIRK_SLOT_IS_CONTACTNUMBER,
- .maxcontacts = 10
+ MT_QUIRK_SLOT_IS_CONTACTNUMBER
},
{ .name = MT_CLS_FLATFROG,
@@ -421,11 +420,11 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi,
* contact max are global to the report */
td->last_field_index = field->index;
return -1;
- }
case HID_DG_TOUCH:
/* Legacy devices use TIPSWITCH and not TOUCH.
* Let's just ignore this field. */
return -1;
+ }
/* let hid-input decide for the others */
return 0;
diff --git a/drivers/i2c/Makefile b/drivers/i2c/Makefile
index beee6b2d361d..1722f50f2473 100644
--- a/drivers/i2c/Makefile
+++ b/drivers/i2c/Makefile
@@ -8,6 +8,7 @@ obj-$(CONFIG_I2C_SMBUS) += i2c-smbus.o
obj-$(CONFIG_I2C_CHARDEV) += i2c-dev.o
obj-$(CONFIG_I2C_MUX) += i2c-mux.o
obj-y += algos/ busses/ muxes/
+obj-$(CONFIG_I2C_STUB) += i2c-stub.o
ccflags-$(CONFIG_I2C_DEBUG_CORE) := -DDEBUG
CFLAGS_i2c-core.o := -Wno-deprecated-declarations
diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig
index 65dd599a0262..e9df4612b7eb 100644
--- a/drivers/i2c/busses/Kconfig
+++ b/drivers/i2c/busses/Kconfig
@@ -81,7 +81,6 @@ config I2C_I801
tristate "Intel 82801 (ICH/PCH)"
depends on PCI
select CHECK_SIGNATURE if X86 && DMI
- select GPIOLIB if I2C_MUX
help
If you say yes to this option, support will be included for the Intel
801 family of mainboard I2C interfaces. Specifically, the following
diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile
index 2d33d62952c1..395b516ffa08 100644
--- a/drivers/i2c/busses/Makefile
+++ b/drivers/i2c/busses/Makefile
@@ -85,7 +85,6 @@ obj-$(CONFIG_I2C_ACORN) += i2c-acorn.o
obj-$(CONFIG_I2C_ELEKTOR) += i2c-elektor.o
obj-$(CONFIG_I2C_PCA_ISA) += i2c-pca-isa.o
obj-$(CONFIG_I2C_SIBYTE) += i2c-sibyte.o
-obj-$(CONFIG_I2C_STUB) += i2c-stub.o
obj-$(CONFIG_SCx200_ACB) += scx200_acb.o
obj-$(CONFIG_SCx200_I2C) += scx200_i2c.o
diff --git a/drivers/i2c/busses/i2c-i801.c b/drivers/i2c/busses/i2c-i801.c
index 37793156bd93..6abc00d59881 100644
--- a/drivers/i2c/busses/i2c-i801.c
+++ b/drivers/i2c/busses/i2c-i801.c
@@ -82,7 +82,8 @@
#include <linux/wait.h>
#include <linux/err.h>
-#if defined CONFIG_I2C_MUX || defined CONFIG_I2C_MUX_MODULE
+#if (defined CONFIG_I2C_MUX_GPIO || defined CONFIG_I2C_MUX_GPIO_MODULE) && \
+ defined CONFIG_DMI
#include <linux/gpio.h>
#include <linux/i2c-mux-gpio.h>
#include <linux/platform_device.h>
@@ -192,7 +193,8 @@ struct i801_priv {
int len;
u8 *data;
-#if defined CONFIG_I2C_MUX || defined CONFIG_I2C_MUX_MODULE
+#if (defined CONFIG_I2C_MUX_GPIO || defined CONFIG_I2C_MUX_GPIO_MODULE) && \
+ defined CONFIG_DMI
const struct i801_mux_config *mux_drvdata;
struct platform_device *mux_pdev;
#endif
@@ -921,7 +923,8 @@ static void __init input_apanel_init(void) {}
static void __devinit i801_probe_optional_slaves(struct i801_priv *priv) {}
#endif /* CONFIG_X86 && CONFIG_DMI */
-#if defined CONFIG_I2C_MUX || defined CONFIG_I2C_MUX_MODULE
+#if (defined CONFIG_I2C_MUX_GPIO || defined CONFIG_I2C_MUX_GPIO_MODULE) && \
+ defined CONFIG_DMI
static struct i801_mux_config i801_mux_config_asus_z8_d12 = {
.gpio_chip = "gpio_ich",
.values = { 0x02, 0x03 },
@@ -1059,7 +1062,7 @@ static unsigned int __devinit i801_get_adapter_class(struct i801_priv *priv)
id = dmi_first_match(mux_dmi_table);
if (id) {
- /* Remove from branch classes from trunk */
+ /* Remove branch classes from trunk */
mux_config = id->driver_data;
for (i = 0; i < mux_config->n_values; i++)
class &= ~mux_config->classes[i];
diff --git a/drivers/i2c/busses/i2c-stub.c b/drivers/i2c/i2c-stub.c
index b1b3447942c9..d0a9c590c3cd 100644
--- a/drivers/i2c/busses/i2c-stub.c
+++ b/drivers/i2c/i2c-stub.c
@@ -2,7 +2,7 @@
i2c-stub.c - I2C/SMBus chip emulator
Copyright (c) 2004 Mark M. Hoffman <mhoffman@lightlink.com>
- Copyright (C) 2007 Jean Delvare <khali@linux-fr.org>
+ Copyright (C) 2007, 2012 Jean Delvare <khali@linux-fr.org>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -51,8 +51,8 @@ struct stub_chip {
static struct stub_chip *stub_chips;
/* Return negative errno on error. */
-static s32 stub_xfer(struct i2c_adapter * adap, u16 addr, unsigned short flags,
- char read_write, u8 command, int size, union i2c_smbus_data * data)
+static s32 stub_xfer(struct i2c_adapter *adap, u16 addr, unsigned short flags,
+ char read_write, u8 command, int size, union i2c_smbus_data *data)
{
s32 ret;
int i, len;
@@ -78,14 +78,14 @@ static s32 stub_xfer(struct i2c_adapter * adap, u16 addr, unsigned short flags,
case I2C_SMBUS_BYTE:
if (read_write == I2C_SMBUS_WRITE) {
chip->pointer = command;
- dev_dbg(&adap->dev, "smbus byte - addr 0x%02x, "
- "wrote 0x%02x.\n",
- addr, command);
+ dev_dbg(&adap->dev,
+ "smbus byte - addr 0x%02x, wrote 0x%02x.\n",
+ addr, command);
} else {
data->byte = chip->words[chip->pointer++] & 0xff;
- dev_dbg(&adap->dev, "smbus byte - addr 0x%02x, "
- "read 0x%02x.\n",
- addr, data->byte);
+ dev_dbg(&adap->dev,
+ "smbus byte - addr 0x%02x, read 0x%02x.\n",
+ addr, data->byte);
}
ret = 0;
@@ -95,14 +95,14 @@ static s32 stub_xfer(struct i2c_adapter * adap, u16 addr, unsigned short flags,
if (read_write == I2C_SMBUS_WRITE) {
chip->words[command] &= 0xff00;
chip->words[command] |= data->byte;
- dev_dbg(&adap->dev, "smbus byte data - addr 0x%02x, "
- "wrote 0x%02x at 0x%02x.\n",
- addr, data->byte, command);
+ dev_dbg(&adap->dev,
+ "smbus byte data - addr 0x%02x, wrote 0x%02x at 0x%02x.\n",
+ addr, data->byte, command);
} else {
data->byte = chip->words[command] & 0xff;
- dev_dbg(&adap->dev, "smbus byte data - addr 0x%02x, "
- "read 0x%02x at 0x%02x.\n",
- addr, data->byte, command);
+ dev_dbg(&adap->dev,
+ "smbus byte data - addr 0x%02x, read 0x%02x at 0x%02x.\n",
+ addr, data->byte, command);
}
chip->pointer = command + 1;
@@ -112,14 +112,14 @@ static s32 stub_xfer(struct i2c_adapter * adap, u16 addr, unsigned short flags,
case I2C_SMBUS_WORD_DATA:
if (read_write == I2C_SMBUS_WRITE) {
chip->words[command] = data->word;
- dev_dbg(&adap->dev, "smbus word data - addr 0x%02x, "
- "wrote 0x%04x at 0x%02x.\n",
- addr, data->word, command);
+ dev_dbg(&adap->dev,
+ "smbus word data - addr 0x%02x, wrote 0x%04x at 0x%02x.\n",
+ addr, data->word, command);
} else {
data->word = chip->words[command];
- dev_dbg(&adap->dev, "smbus word data - addr 0x%02x, "
- "read 0x%04x at 0x%02x.\n",
- addr, data->word, command);
+ dev_dbg(&adap->dev,
+ "smbus word data - addr 0x%02x, read 0x%04x at 0x%02x.\n",
+ addr, data->word, command);
}
ret = 0;
@@ -132,17 +132,17 @@ static s32 stub_xfer(struct i2c_adapter * adap, u16 addr, unsigned short flags,
chip->words[command + i] &= 0xff00;
chip->words[command + i] |= data->block[1 + i];
}
- dev_dbg(&adap->dev, "i2c block data - addr 0x%02x, "
- "wrote %d bytes at 0x%02x.\n",
- addr, len, command);
+ dev_dbg(&adap->dev,
+ "i2c block data - addr 0x%02x, wrote %d bytes at 0x%02x.\n",
+ addr, len, command);
} else {
for (i = 0; i < len; i++) {
data->block[1 + i] =
chip->words[command + i] & 0xff;
}
- dev_dbg(&adap->dev, "i2c block data - addr 0x%02x, "
- "read %d bytes at 0x%02x.\n",
- addr, len, command);
+ dev_dbg(&adap->dev,
+ "i2c block data - addr 0x%02x, read %d bytes at 0x%02x.\n",
+ addr, len, command);
}
ret = 0;
@@ -179,25 +179,24 @@ static int __init i2c_stub_init(void)
int i, ret;
if (!chip_addr[0]) {
- printk(KERN_ERR "i2c-stub: Please specify a chip address\n");
+ pr_err("i2c-stub: Please specify a chip address\n");
return -ENODEV;
}
for (i = 0; i < MAX_CHIPS && chip_addr[i]; i++) {
if (chip_addr[i] < 0x03 || chip_addr[i] > 0x77) {
- printk(KERN_ERR "i2c-stub: Invalid chip address "
- "0x%02x\n", chip_addr[i]);
+ pr_err("i2c-stub: Invalid chip address 0x%02x\n",
+ chip_addr[i]);
return -EINVAL;
}
- printk(KERN_INFO "i2c-stub: Virtual chip at 0x%02x\n",
- chip_addr[i]);
+ pr_info("i2c-stub: Virtual chip at 0x%02x\n", chip_addr[i]);
}
/* Allocate memory for all chips at once */
stub_chips = kzalloc(i * sizeof(struct stub_chip), GFP_KERNEL);
if (!stub_chips) {
- printk(KERN_ERR "i2c-stub: Out of memory\n");
+ pr_err("i2c-stub: Out of memory\n");
return -ENOMEM;
}
@@ -219,4 +218,3 @@ MODULE_LICENSE("GPL");
module_init(i2c_stub_init);
module_exit(i2c_stub_exit);
-
diff --git a/drivers/infiniband/hw/cxgb4/mem.c b/drivers/infiniband/hw/cxgb4/mem.c
index 57e07c61ace2..afd81790ab3c 100644
--- a/drivers/infiniband/hw/cxgb4/mem.c
+++ b/drivers/infiniband/hw/cxgb4/mem.c
@@ -468,7 +468,7 @@ struct ib_mr *c4iw_register_phys_mem(struct ib_pd *pd,
ret = alloc_pbl(mhp, npages);
if (ret) {
kfree(page_list);
- goto err_pbl;
+ goto err;
}
ret = write_pbl(&mhp->rhp->rdev, page_list, mhp->attr.pbl_addr,
diff --git a/drivers/infiniband/hw/mlx4/alias_GUID.c b/drivers/infiniband/hw/mlx4/alias_GUID.c
index d2fb38d43571..2f215b93db6b 100644
--- a/drivers/infiniband/hw/mlx4/alias_GUID.c
+++ b/drivers/infiniband/hw/mlx4/alias_GUID.c
@@ -107,7 +107,7 @@ static __be64 get_cached_alias_guid(struct mlx4_ib_dev *dev, int port, int index
{
if (index >= NUM_ALIAS_GUID_PER_PORT) {
pr_err("%s: ERROR: asked for index:%d\n", __func__, index);
- return (__force __be64) ((u64) 0xFFFFFFFFFFFFFFFFUL);
+ return (__force __be64) -1;
}
return *(__be64 *)&dev->sriov.demux[port - 1].guid_cache[index];
}
diff --git a/drivers/infiniband/hw/mlx4/mad.c b/drivers/infiniband/hw/mlx4/mad.c
index 21a794152d15..0a903c129f0a 100644
--- a/drivers/infiniband/hw/mlx4/mad.c
+++ b/drivers/infiniband/hw/mlx4/mad.c
@@ -409,38 +409,45 @@ int mlx4_ib_find_real_gid(struct ib_device *ibdev, u8 port, __be64 guid)
}
-static int get_pkey_phys_indices(struct mlx4_ib_dev *ibdev, u8 port, u8 ph_pkey_ix,
- u8 *full_pk_ix, u8 *partial_pk_ix,
- int *is_full_member)
+static int find_slave_port_pkey_ix(struct mlx4_ib_dev *dev, int slave,
+ u8 port, u16 pkey, u16 *ix)
{
- u16 search_pkey;
- int fm;
- int err = 0;
- u16 pk;
+ int i, ret;
+ u8 unassigned_pkey_ix, pkey_ix, partial_ix = 0xFF;
+ u16 slot_pkey;
- err = ib_get_cached_pkey(&ibdev->ib_dev, port, ph_pkey_ix, &search_pkey);
- if (err)
- return err;
+ if (slave == mlx4_master_func_num(dev->dev))
+ return ib_find_cached_pkey(&dev->ib_dev, port, pkey, ix);
- fm = (search_pkey & 0x8000) ? 1 : 0;
- if (fm) {
- *full_pk_ix = ph_pkey_ix;
- search_pkey &= 0x7FFF;
- } else {
- *partial_pk_ix = ph_pkey_ix;
- search_pkey |= 0x8000;
- }
+ unassigned_pkey_ix = dev->dev->phys_caps.pkey_phys_table_len[port] - 1;
- if (ib_find_exact_cached_pkey(&ibdev->ib_dev, port, search_pkey, &pk))
- pk = 0xFFFF;
+ for (i = 0; i < dev->dev->caps.pkey_table_len[port]; i++) {
+ if (dev->pkeys.virt2phys_pkey[slave][port - 1][i] == unassigned_pkey_ix)
+ continue;
- if (fm)
- *partial_pk_ix = (pk & 0xFF);
- else
- *full_pk_ix = (pk & 0xFF);
+ pkey_ix = dev->pkeys.virt2phys_pkey[slave][port - 1][i];
- *is_full_member = fm;
- return err;
+ ret = ib_get_cached_pkey(&dev->ib_dev, port, pkey_ix, &slot_pkey);
+ if (ret)
+ continue;
+ if ((slot_pkey & 0x7FFF) == (pkey & 0x7FFF)) {
+ if (slot_pkey & 0x8000) {
+ *ix = (u16) pkey_ix;
+ return 0;
+ } else {
+ /* take first partial pkey index found */
+ if (partial_ix == 0xFF)
+ partial_ix = pkey_ix;
+ }
+ }
+ }
+
+ if (partial_ix < 0xFF) {
+ *ix = (u16) partial_ix;
+ return 0;
+ }
+
+ return -EINVAL;
}
int mlx4_ib_send_to_slave(struct mlx4_ib_dev *dev, int slave, u8 port,
@@ -458,10 +465,8 @@ int mlx4_ib_send_to_slave(struct mlx4_ib_dev *dev, int slave, u8 port,
unsigned tun_tx_ix = 0;
int dqpn;
int ret = 0;
- int i;
- int is_full_member = 0;
u16 tun_pkey_ix;
- u8 ph_pkey_ix, full_pk_ix = 0, partial_pk_ix = 0;
+ u16 cached_pkey;
if (dest_qpt > IB_QPT_GSI)
return -EINVAL;
@@ -481,27 +486,17 @@ int mlx4_ib_send_to_slave(struct mlx4_ib_dev *dev, int slave, u8 port,
else
tun_qp = &tun_ctx->qp[1];
- /* compute pkey index for slave */
- /* get physical pkey -- virtualized Dom0 pkey to phys*/
+ /* compute P_Key index to put in tunnel header for slave */
if (dest_qpt) {
- ph_pkey_ix =
- dev->pkeys.virt2phys_pkey[mlx4_master_func_num(dev->dev)][port - 1][wc->pkey_index];
-
- /* now, translate this to the slave pkey index */
- ret = get_pkey_phys_indices(dev, port, ph_pkey_ix, &full_pk_ix,
- &partial_pk_ix, &is_full_member);
+ u16 pkey_ix;
+ ret = ib_get_cached_pkey(&dev->ib_dev, port, wc->pkey_index, &cached_pkey);
if (ret)
return -EINVAL;
- for (i = 0; i < dev->dev->caps.pkey_table_len[port]; i++) {
- if ((dev->pkeys.virt2phys_pkey[slave][port - 1][i] == full_pk_ix) ||
- (is_full_member &&
- (dev->pkeys.virt2phys_pkey[slave][port - 1][i] == partial_pk_ix)))
- break;
- }
- if (i == dev->dev->caps.pkey_table_len[port])
+ ret = find_slave_port_pkey_ix(dev, slave, port, cached_pkey, &pkey_ix);
+ if (ret)
return -EINVAL;
- tun_pkey_ix = i;
+ tun_pkey_ix = pkey_ix;
} else
tun_pkey_ix = dev->pkeys.virt2phys_pkey[slave][port - 1][0];
diff --git a/drivers/infiniband/hw/mlx4/mcg.c b/drivers/infiniband/hw/mlx4/mcg.c
index 3c3b54c3fdd9..25b2cdff00f8 100644
--- a/drivers/infiniband/hw/mlx4/mcg.c
+++ b/drivers/infiniband/hw/mlx4/mcg.c
@@ -233,7 +233,8 @@ static int send_mad_to_slave(int slave, struct mlx4_ib_demux_ctx *ctx,
ib_query_ah(dev->sm_ah[ctx->port - 1], &ah_attr);
- wc.pkey_index = 0;
+ if (ib_find_cached_pkey(&dev->ib_dev, ctx->port, IB_DEFAULT_PKEY_FULL, &wc.pkey_index))
+ return -EINVAL;
wc.sl = 0;
wc.dlid_path_bits = 0;
wc.port_num = ctx->port;
@@ -1074,10 +1075,6 @@ static void _mlx4_ib_mcg_port_cleanup(struct mlx4_ib_demux_ctx *ctx, int destroy
unsigned long end;
int count;
- if (ctx->flushing)
- return;
-
- ctx->flushing = 1;
for (i = 0; i < MAX_VFS; ++i)
clean_vf_mcast(ctx, i);
@@ -1107,9 +1104,6 @@ static void _mlx4_ib_mcg_port_cleanup(struct mlx4_ib_demux_ctx *ctx, int destroy
force_clean_group(group);
}
mutex_unlock(&ctx->mcg_table_lock);
-
- if (!destroy_wq)
- ctx->flushing = 0;
}
struct clean_work {
@@ -1123,6 +1117,7 @@ static void mcg_clean_task(struct work_struct *work)
struct clean_work *cw = container_of(work, struct clean_work, work);
_mlx4_ib_mcg_port_cleanup(cw->ctx, cw->destroy_wq);
+ cw->ctx->flushing = 0;
kfree(cw);
}
@@ -1130,13 +1125,20 @@ void mlx4_ib_mcg_port_cleanup(struct mlx4_ib_demux_ctx *ctx, int destroy_wq)
{
struct clean_work *work;
+ if (ctx->flushing)
+ return;
+
+ ctx->flushing = 1;
+
if (destroy_wq) {
_mlx4_ib_mcg_port_cleanup(ctx, destroy_wq);
+ ctx->flushing = 0;
return;
}
work = kmalloc(sizeof *work, GFP_KERNEL);
if (!work) {
+ ctx->flushing = 0;
mcg_warn("failed allocating work for cleanup\n");
return;
}
diff --git a/drivers/input/mouse/bcm5974.c b/drivers/input/mouse/bcm5974.c
index 3a78f235fa3e..2baff1b79a55 100644
--- a/drivers/input/mouse/bcm5974.c
+++ b/drivers/input/mouse/bcm5974.c
@@ -84,6 +84,10 @@
#define USB_DEVICE_ID_APPLE_WELLSPRING7_ANSI 0x0262
#define USB_DEVICE_ID_APPLE_WELLSPRING7_ISO 0x0263
#define USB_DEVICE_ID_APPLE_WELLSPRING7_JIS 0x0264
+/* MacbookPro10,2 (unibody, October 2012) */
+#define USB_DEVICE_ID_APPLE_WELLSPRING7A_ANSI 0x0259
+#define USB_DEVICE_ID_APPLE_WELLSPRING7A_ISO 0x025a
+#define USB_DEVICE_ID_APPLE_WELLSPRING7A_JIS 0x025b
#define BCM5974_DEVICE(prod) { \
.match_flags = (USB_DEVICE_ID_MATCH_DEVICE | \
@@ -137,6 +141,10 @@ static const struct usb_device_id bcm5974_table[] = {
BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRING7_ANSI),
BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRING7_ISO),
BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRING7_JIS),
+ /* MacbookPro10,2 */
+ BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRING7A_ANSI),
+ BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRING7A_ISO),
+ BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRING7A_JIS),
/* Terminating entry */
{}
};
@@ -379,6 +387,19 @@ static const struct bcm5974_config bcm5974_config_table[] = {
{ SN_COORD, -150, 6730 },
{ SN_ORIENT, -MAX_FINGER_ORIENTATION, MAX_FINGER_ORIENTATION }
},
+ {
+ USB_DEVICE_ID_APPLE_WELLSPRING7A_ANSI,
+ USB_DEVICE_ID_APPLE_WELLSPRING7A_ISO,
+ USB_DEVICE_ID_APPLE_WELLSPRING7A_JIS,
+ HAS_INTEGRATED_BUTTON,
+ 0x84, sizeof(struct bt_data),
+ 0x81, TYPE2, FINGER_TYPE2, FINGER_TYPE2 + SIZEOF_ALL_FINGERS,
+ { SN_PRESSURE, 0, 300 },
+ { SN_WIDTH, 0, 2048 },
+ { SN_COORD, -4750, 5280 },
+ { SN_COORD, -150, 6730 },
+ { SN_ORIENT, -MAX_FINGER_ORIENTATION, MAX_FINGER_ORIENTATION }
+ },
{}
};
diff --git a/drivers/isdn/gigaset/bas-gigaset.c b/drivers/isdn/gigaset/bas-gigaset.c
index 527588708948..c44950d3eb7b 100644
--- a/drivers/isdn/gigaset/bas-gigaset.c
+++ b/drivers/isdn/gigaset/bas-gigaset.c
@@ -617,7 +617,13 @@ static void int_in_work(struct work_struct *work)
if (rc == 0)
/* success, resubmit interrupt read URB */
rc = usb_submit_urb(urb, GFP_ATOMIC);
- if (rc != 0 && rc != -ENODEV) {
+
+ switch (rc) {
+ case 0: /* success */
+ case -ENODEV: /* device gone */
+ case -EINVAL: /* URB already resubmitted, or terminal badness */
+ break;
+ default: /* failure: try to recover by resetting the device */
dev_err(cs->dev, "clear halt failed: %s\n", get_usb_rcmsg(rc));
rc = usb_lock_device_for_reset(ucs->udev, ucs->interface);
if (rc == 0) {
@@ -2442,7 +2448,9 @@ static void gigaset_disconnect(struct usb_interface *interface)
}
/* gigaset_suspend
- * This function is called before the USB connection is suspended.
+ * This function is called before the USB connection is suspended
+ * or before the USB device is reset.
+ * In the latter case, message == PMSG_ON.
*/
static int gigaset_suspend(struct usb_interface *intf, pm_message_t message)
{
@@ -2498,7 +2506,12 @@ static int gigaset_suspend(struct usb_interface *intf, pm_message_t message)
del_timer_sync(&ucs->timer_atrdy);
del_timer_sync(&ucs->timer_cmd_in);
del_timer_sync(&ucs->timer_int_in);
- cancel_work_sync(&ucs->int_in_wq);
+
+ /* don't try to cancel int_in_wq from within reset as it
+ * might be the one requesting the reset
+ */
+ if (message.event != PM_EVENT_ON)
+ cancel_work_sync(&ucs->int_in_wq);
gig_dbg(DEBUG_SUSPEND, "suspend complete");
return 0;
diff --git a/drivers/md/faulty.c b/drivers/md/faulty.c
index 45135f69509c..5e7dc772f5de 100644
--- a/drivers/md/faulty.c
+++ b/drivers/md/faulty.c
@@ -315,8 +315,11 @@ static int run(struct mddev *mddev)
}
conf->nfaults = 0;
- rdev_for_each(rdev, mddev)
+ rdev_for_each(rdev, mddev) {
conf->rdev = rdev;
+ disk_stack_limits(mddev->gendisk, rdev->bdev,
+ rdev->data_offset << 9);
+ }
md_set_array_sectors(mddev, faulty_size(mddev, 0, 0));
mddev->private = conf;
diff --git a/drivers/md/raid1.c b/drivers/md/raid1.c
index 8034fbd6190c..636bae0405e8 100644
--- a/drivers/md/raid1.c
+++ b/drivers/md/raid1.c
@@ -2710,7 +2710,7 @@ static struct r1conf *setup_conf(struct mddev *mddev)
|| disk_idx < 0)
continue;
if (test_bit(Replacement, &rdev->flags))
- disk = conf->mirrors + conf->raid_disks + disk_idx;
+ disk = conf->mirrors + mddev->raid_disks + disk_idx;
else
disk = conf->mirrors + disk_idx;
diff --git a/drivers/md/raid10.c b/drivers/md/raid10.c
index 906ccbd0f7dc..d1295aff4173 100644
--- a/drivers/md/raid10.c
+++ b/drivers/md/raid10.c
@@ -1783,7 +1783,7 @@ static int raid10_add_disk(struct mddev *mddev, struct md_rdev *rdev)
clear_bit(Unmerged, &rdev->flags);
}
md_integrity_add_rdev(rdev, mddev);
- if (blk_queue_discard(bdev_get_queue(rdev->bdev)))
+ if (mddev->queue && blk_queue_discard(bdev_get_queue(rdev->bdev)))
queue_flag_set_unlocked(QUEUE_FLAG_DISCARD, mddev->queue);
print_conf(conf);
@@ -3613,11 +3613,14 @@ static int run(struct mddev *mddev)
discard_supported = true;
}
- if (discard_supported)
- queue_flag_set_unlocked(QUEUE_FLAG_DISCARD, mddev->queue);
- else
- queue_flag_clear_unlocked(QUEUE_FLAG_DISCARD, mddev->queue);
-
+ if (mddev->queue) {
+ if (discard_supported)
+ queue_flag_set_unlocked(QUEUE_FLAG_DISCARD,
+ mddev->queue);
+ else
+ queue_flag_clear_unlocked(QUEUE_FLAG_DISCARD,
+ mddev->queue);
+ }
/* need to check that every block has at least one working mirror */
if (!enough(conf, -1)) {
printk(KERN_ERR "md/raid10:%s: not enough operational mirrors.\n",
diff --git a/drivers/net/can/flexcan.c b/drivers/net/can/flexcan.c
index c78ecfca1e45..a412bf6d73ef 100644
--- a/drivers/net/can/flexcan.c
+++ b/drivers/net/can/flexcan.c
@@ -144,9 +144,22 @@
#define FLEXCAN_MB_CODE_MASK (0xf0ffffff)
-/* FLEXCAN hardware feature flags */
+/*
+ * FLEXCAN hardware feature flags
+ *
+ * Below is some version info we got:
+ * SOC Version IP-Version Glitch- [TR]WRN_INT
+ * Filter? connected?
+ * MX25 FlexCAN2 03.00.00.00 no no
+ * MX28 FlexCAN2 03.00.04.00 yes yes
+ * MX35 FlexCAN2 03.00.00.00 no no
+ * MX53 FlexCAN2 03.00.00.00 yes no
+ * MX6s FlexCAN3 10.00.12.00 yes yes
+ *
+ * Some SOCs do not have the RX_WARN & TX_WARN interrupt line connected.
+ */
#define FLEXCAN_HAS_V10_FEATURES BIT(1) /* For core version >= 10 */
-#define FLEXCAN_HAS_BROKEN_ERR_STATE BIT(2) /* Broken error state handling */
+#define FLEXCAN_HAS_BROKEN_ERR_STATE BIT(2) /* [TR]WRN_INT not connected */
/* Structure of the message buffer */
struct flexcan_mb {
@@ -205,7 +218,7 @@ static struct flexcan_devtype_data fsl_p1010_devtype_data = {
};
static struct flexcan_devtype_data fsl_imx28_devtype_data;
static struct flexcan_devtype_data fsl_imx6q_devtype_data = {
- .features = FLEXCAN_HAS_V10_FEATURES | FLEXCAN_HAS_BROKEN_ERR_STATE,
+ .features = FLEXCAN_HAS_V10_FEATURES,
};
static const struct can_bittiming_const flexcan_bittiming_const = {
diff --git a/drivers/net/can/sja1000/peak_pci.c b/drivers/net/can/sja1000/peak_pci.c
index f5b82aeb2540..6525dbcca4e3 100644
--- a/drivers/net/can/sja1000/peak_pci.c
+++ b/drivers/net/can/sja1000/peak_pci.c
@@ -30,9 +30,10 @@
#include "sja1000.h"
-MODULE_AUTHOR("Wolfgang Grandegger <wg@grandegger.com>");
+MODULE_AUTHOR("Stephane Grosjean <s.grosjean@peak-system.com>");
MODULE_DESCRIPTION("Socket-CAN driver for PEAK PCAN PCI family cards");
MODULE_SUPPORTED_DEVICE("PEAK PCAN PCI/PCIe/PCIeC miniPCI CAN cards");
+MODULE_SUPPORTED_DEVICE("PEAK PCAN miniPCIe/cPCI PC/104+ PCI/104e CAN Cards");
MODULE_LICENSE("GPL v2");
#define DRV_NAME "peak_pci"
@@ -64,7 +65,11 @@ struct peak_pci_chan {
#define PEAK_PCI_DEVICE_ID 0x0001 /* for PCI/PCIe slot cards */
#define PEAK_PCIEC_DEVICE_ID 0x0002 /* for ExpressCard slot cards */
#define PEAK_PCIE_DEVICE_ID 0x0003 /* for nextgen PCIe slot cards */
-#define PEAK_MPCI_DEVICE_ID 0x0008 /* The miniPCI slot cards */
+#define PEAK_CPCI_DEVICE_ID 0x0004 /* for nextgen cPCI slot cards */
+#define PEAK_MPCI_DEVICE_ID 0x0005 /* for nextgen miniPCI slot cards */
+#define PEAK_PC_104P_DEVICE_ID 0x0006 /* PCAN-PC/104+ cards */
+#define PEAK_PCI_104E_DEVICE_ID 0x0007 /* PCAN-PCI/104 Express cards */
+#define PEAK_MPCIE_DEVICE_ID 0x0008 /* The miniPCIe slot cards */
#define PEAK_PCI_CHAN_MAX 4
@@ -76,6 +81,10 @@ static DEFINE_PCI_DEVICE_TABLE(peak_pci_tbl) = {
{PEAK_PCI_VENDOR_ID, PEAK_PCI_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID,},
{PEAK_PCI_VENDOR_ID, PEAK_PCIE_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID,},
{PEAK_PCI_VENDOR_ID, PEAK_MPCI_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID,},
+ {PEAK_PCI_VENDOR_ID, PEAK_MPCIE_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID,},
+ {PEAK_PCI_VENDOR_ID, PEAK_PC_104P_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID,},
+ {PEAK_PCI_VENDOR_ID, PEAK_PCI_104E_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID,},
+ {PEAK_PCI_VENDOR_ID, PEAK_CPCI_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID,},
#ifdef CONFIG_CAN_PEAK_PCIEC
{PEAK_PCI_VENDOR_ID, PEAK_PCIEC_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID,},
#endif
diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h b/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h
index a4da893ac1e1..378988b5709a 100644
--- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h
+++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h
@@ -251,6 +251,8 @@ struct adapter_params {
unsigned char rev; /* chip revision */
unsigned char offload;
+ unsigned char bypass;
+
unsigned int ofldq_wr_cred;
};
@@ -642,6 +644,23 @@ extern int dbfifo_int_thresh;
#define for_each_port(adapter, iter) \
for (iter = 0; iter < (adapter)->params.nports; ++iter)
+static inline int is_bypass(struct adapter *adap)
+{
+ return adap->params.bypass;
+}
+
+static inline int is_bypass_device(int device)
+{
+ /* this should be set based upon device capabilities */
+ switch (device) {
+ case 0x440b:
+ case 0x440c:
+ return 1;
+ default:
+ return 0;
+ }
+}
+
static inline unsigned int core_ticks_per_usec(const struct adapter *adap)
{
return adap->params.vpd.cclk / 1000;
diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c
index 604f4f87f550..c1cde11b0c6d 100644
--- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c
+++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c
@@ -3513,18 +3513,6 @@ static int adap_init0_no_config(struct adapter *adapter, int reset)
if (ret < 0)
goto bye;
-#ifndef CONFIG_CHELSIO_T4_OFFLOAD
- /*
- * If we're a pure NIC driver then disable all offloading facilities.
- * This will allow the firmware to optimize aspects of the hardware
- * configuration which will result in improved performance.
- */
- caps_cmd.ofldcaps = 0;
- caps_cmd.iscsicaps = 0;
- caps_cmd.rdmacaps = 0;
- caps_cmd.fcoecaps = 0;
-#endif
-
if (caps_cmd.niccaps & htons(FW_CAPS_CONFIG_NIC_VM)) {
if (!vf_acls)
caps_cmd.niccaps ^= htons(FW_CAPS_CONFIG_NIC_VM);
@@ -3745,6 +3733,7 @@ static int adap_init0(struct adapter *adap)
u32 v, port_vec;
enum dev_state state;
u32 params[7], val[7];
+ struct fw_caps_config_cmd caps_cmd;
int reset = 1, j;
/*
@@ -3898,6 +3887,9 @@ static int adap_init0(struct adapter *adap)
goto bye;
}
+ if (is_bypass_device(adap->pdev->device))
+ adap->params.bypass = 1;
+
/*
* Grab some of our basic fundamental operating parameters.
*/
@@ -3940,13 +3932,12 @@ static int adap_init0(struct adapter *adap)
adap->tids.aftid_end = val[1];
}
-#ifdef CONFIG_CHELSIO_T4_OFFLOAD
/*
* Get device capabilities so we can determine what resources we need
* to manage.
*/
memset(&caps_cmd, 0, sizeof(caps_cmd));
- caps_cmd.op_to_write = htonl(V_FW_CMD_OP(FW_CAPS_CONFIG_CMD) |
+ caps_cmd.op_to_write = htonl(FW_CMD_OP(FW_CAPS_CONFIG_CMD) |
FW_CMD_REQUEST | FW_CMD_READ);
caps_cmd.retval_len16 = htonl(FW_LEN16(caps_cmd));
ret = t4_wr_mbox(adap, adap->mbox, &caps_cmd, sizeof(caps_cmd),
@@ -3991,15 +3982,6 @@ static int adap_init0(struct adapter *adap)
adap->vres.ddp.size = val[4] - val[3] + 1;
adap->params.ofldq_wr_cred = val[5];
- params[0] = FW_PARAM_PFVF(ETHOFLD_START);
- params[1] = FW_PARAM_PFVF(ETHOFLD_END);
- ret = t4_query_params(adap, adap->mbox, adap->fn, 0, 2,
- params, val);
- if ((val[0] != val[1]) && (ret >= 0)) {
- adap->tids.uotid_base = val[0];
- adap->tids.nuotids = val[1] - val[0] + 1;
- }
-
adap->params.offload = 1;
}
if (caps_cmd.rdmacaps) {
@@ -4048,7 +4030,6 @@ static int adap_init0(struct adapter *adap)
}
#undef FW_PARAM_PFVF
#undef FW_PARAM_DEV
-#endif /* CONFIG_CHELSIO_T4_OFFLOAD */
/*
* These are finalized by FW initialization, load their values now.
diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_uld.h b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_uld.h
index 1b899fea1a91..39bec73ff87c 100644
--- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_uld.h
+++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_uld.h
@@ -102,6 +102,9 @@ struct tid_info {
unsigned int ftid_base;
unsigned int aftid_base;
unsigned int aftid_end;
+ /* Server filter region */
+ unsigned int sftid_base;
+ unsigned int nsftids;
spinlock_t atid_lock ____cacheline_aligned_in_smp;
union aopen_entry *afree;
diff --git a/drivers/net/ethernet/freescale/gianfar_ptp.c b/drivers/net/ethernet/freescale/gianfar_ptp.c
index b9db0e040563..2e5daee0438a 100644
--- a/drivers/net/ethernet/freescale/gianfar_ptp.c
+++ b/drivers/net/ethernet/freescale/gianfar_ptp.c
@@ -478,7 +478,7 @@ static int gianfar_ptp_probe(struct platform_device *dev)
pr_err("no resource\n");
goto no_resource;
}
- if (request_resource(&ioport_resource, etsects->rsrc)) {
+ if (request_resource(&iomem_resource, etsects->rsrc)) {
pr_err("resource busy\n");
goto no_resource;
}
diff --git a/drivers/net/ethernet/mellanox/mlx4/en_tx.c b/drivers/net/ethernet/mellanox/mlx4/en_tx.c
index c10e3a6de09f..b35094c590ba 100644
--- a/drivers/net/ethernet/mellanox/mlx4/en_tx.c
+++ b/drivers/net/ethernet/mellanox/mlx4/en_tx.c
@@ -143,7 +143,6 @@ void mlx4_en_destroy_tx_ring(struct mlx4_en_priv *priv,
mlx4_bf_free(mdev->dev, &ring->bf);
mlx4_qp_remove(mdev->dev, &ring->qp);
mlx4_qp_free(mdev->dev, &ring->qp);
- mlx4_qp_release_range(mdev->dev, ring->qpn, 1);
mlx4_en_unmap_buffer(&ring->wqres.buf);
mlx4_free_hwq_res(mdev->dev, &ring->wqres, ring->buf_size);
kfree(ring->bounce_buf);
@@ -712,7 +711,7 @@ netdev_tx_t mlx4_en_xmit(struct sk_buff *skb, struct net_device *dev)
if (bounce)
tx_desc = mlx4_en_bounce_to_desc(priv, ring, index, desc_size);
- if (ring->bf_enabled && desc_size <= MAX_BF && !bounce && !vlan_tag) {
+ if (ring->bf_enabled && desc_size <= MAX_BF && !bounce && !vlan_tx_tag_present(skb)) {
*(__be32 *) (&tx_desc->ctrl.vlan_tag) |= cpu_to_be32(ring->doorbell_qpn);
op_own |= htonl((bf_index & 0xffff) << 8);
/* Ensure new descirptor hits memory
diff --git a/drivers/net/ethernet/mellanox/mlx4/eq.c b/drivers/net/ethernet/mellanox/mlx4/eq.c
index 51c764901ad2..b84a88bc44dc 100644
--- a/drivers/net/ethernet/mellanox/mlx4/eq.c
+++ b/drivers/net/ethernet/mellanox/mlx4/eq.c
@@ -329,9 +329,6 @@ int set_and_calc_slave_port_state(struct mlx4_dev *dev, int slave,
ctx = &priv->mfunc.master.slave_state[slave];
spin_lock_irqsave(&ctx->lock, flags);
- mlx4_dbg(dev, "%s: slave: %d, current state: %d new event :%d\n",
- __func__, slave, cur_state, event);
-
switch (cur_state) {
case SLAVE_PORT_DOWN:
if (MLX4_PORT_STATE_DEV_EVENT_PORT_UP == event)
@@ -366,9 +363,6 @@ int set_and_calc_slave_port_state(struct mlx4_dev *dev, int slave,
goto out;
}
ret = mlx4_get_slave_port_state(dev, slave, port);
- mlx4_dbg(dev, "%s: slave: %d, current state: %d new event"
- " :%d gen_event: %d\n",
- __func__, slave, cur_state, event, *gen_event);
out:
spin_unlock_irqrestore(&ctx->lock, flags);
@@ -843,6 +837,18 @@ static void __iomem *mlx4_get_eq_uar(struct mlx4_dev *dev, struct mlx4_eq *eq)
return priv->eq_table.uar_map[index] + 0x800 + 8 * (eq->eqn % 4);
}
+static void mlx4_unmap_uar(struct mlx4_dev *dev)
+{
+ struct mlx4_priv *priv = mlx4_priv(dev);
+ int i;
+
+ for (i = 0; i < mlx4_num_eq_uar(dev); ++i)
+ if (priv->eq_table.uar_map[i]) {
+ iounmap(priv->eq_table.uar_map[i]);
+ priv->eq_table.uar_map[i] = NULL;
+ }
+}
+
static int mlx4_create_eq(struct mlx4_dev *dev, int nent,
u8 intr, struct mlx4_eq *eq)
{
@@ -1207,6 +1213,7 @@ err_out_unmap:
mlx4_free_irqs(dev);
err_out_bitmap:
+ mlx4_unmap_uar(dev);
mlx4_bitmap_cleanup(&priv->eq_table.bitmap);
err_out_free:
@@ -1231,10 +1238,7 @@ void mlx4_cleanup_eq_table(struct mlx4_dev *dev)
if (!mlx4_is_slave(dev))
mlx4_unmap_clr_int(dev);
- for (i = 0; i < mlx4_num_eq_uar(dev); ++i)
- if (priv->eq_table.uar_map[i])
- iounmap(priv->eq_table.uar_map[i]);
-
+ mlx4_unmap_uar(dev);
mlx4_bitmap_cleanup(&priv->eq_table.bitmap);
kfree(priv->eq_table.uar_map);
diff --git a/drivers/net/ethernet/mellanox/mlx4/main.c b/drivers/net/ethernet/mellanox/mlx4/main.c
index 80df2ab0177c..2aa80afd98d2 100644
--- a/drivers/net/ethernet/mellanox/mlx4/main.c
+++ b/drivers/net/ethernet/mellanox/mlx4/main.c
@@ -1405,7 +1405,10 @@ unmap_bf:
unmap_bf_area(dev);
err_close:
- mlx4_close_hca(dev);
+ if (mlx4_is_slave(dev))
+ mlx4_slave_exit(dev);
+ else
+ mlx4_CLOSE_HCA(dev, 0);
err_free_icm:
if (!mlx4_is_slave(dev))
diff --git a/drivers/net/ethernet/mellanox/mlx4/resource_tracker.c b/drivers/net/ethernet/mellanox/mlx4/resource_tracker.c
index 926c911c0ac4..b05705f50f0f 100644
--- a/drivers/net/ethernet/mellanox/mlx4/resource_tracker.c
+++ b/drivers/net/ethernet/mellanox/mlx4/resource_tracker.c
@@ -330,9 +330,6 @@ static void update_pkey_index(struct mlx4_dev *dev, int slave,
new_index = priv->virt2phys_pkey[slave][port - 1][orig_index];
*(u8 *)(inbox->buf + 35) = new_index;
-
- mlx4_dbg(dev, "port = %d, orig pkey index = %d, "
- "new pkey index = %d\n", port, orig_index, new_index);
}
static void update_gid(struct mlx4_dev *dev, struct mlx4_cmd_mailbox *inbox,
@@ -351,9 +348,6 @@ static void update_gid(struct mlx4_dev *dev, struct mlx4_cmd_mailbox *inbox,
if (optpar & MLX4_QP_OPTPAR_ALT_ADDR_PATH)
qp_ctx->alt_path.mgid_index = slave & 0x7F;
}
-
- mlx4_dbg(dev, "slave %d, new gid index: 0x%x ",
- slave, qp_ctx->pri_path.mgid_index);
}
static int mpt_mask(struct mlx4_dev *dev)
diff --git a/drivers/net/ethernet/oki-semi/pch_gbe/pch_gbe_main.c b/drivers/net/ethernet/oki-semi/pch_gbe/pch_gbe_main.c
index b2a94d02a521..4c4fe5b1a29a 100644
--- a/drivers/net/ethernet/oki-semi/pch_gbe/pch_gbe_main.c
+++ b/drivers/net/ethernet/oki-semi/pch_gbe/pch_gbe_main.c
@@ -339,26 +339,6 @@ static void pch_gbe_wait_clr_bit(void *reg, u32 bit)
}
/**
- * pch_gbe_wait_clr_bit_irq - Wait to clear a bit for interrupt context
- * @reg: Pointer of register
- * @busy: Busy bit
- */
-static int pch_gbe_wait_clr_bit_irq(void *reg, u32 bit)
-{
- u32 tmp;
- int ret = -1;
- /* wait busy */
- tmp = 20;
- while ((ioread32(reg) & bit) && --tmp)
- udelay(5);
- if (!tmp)
- pr_err("Error: busy bit is not cleared\n");
- else
- ret = 0;
- return ret;
-}
-
-/**
* pch_gbe_mac_mar_set - Set MAC address register
* @hw: Pointer to the HW structure
* @addr: Pointer to the MAC address
@@ -409,15 +389,20 @@ static void pch_gbe_mac_reset_hw(struct pch_gbe_hw *hw)
return;
}
-static void pch_gbe_mac_reset_rx(struct pch_gbe_hw *hw)
+static void pch_gbe_disable_mac_rx(struct pch_gbe_hw *hw)
{
- /* Read the MAC addresses. and store to the private data */
- pch_gbe_mac_read_mac_addr(hw);
- iowrite32(PCH_GBE_RX_RST, &hw->reg->RESET);
- pch_gbe_wait_clr_bit_irq(&hw->reg->RESET, PCH_GBE_RX_RST);
- /* Setup the MAC addresses */
- pch_gbe_mac_mar_set(hw, hw->mac.addr, 0);
- return;
+ u32 rctl;
+ /* Disables Receive MAC */
+ rctl = ioread32(&hw->reg->MAC_RX_EN);
+ iowrite32((rctl & ~PCH_GBE_MRE_MAC_RX_EN), &hw->reg->MAC_RX_EN);
+}
+
+static void pch_gbe_enable_mac_rx(struct pch_gbe_hw *hw)
+{
+ u32 rctl;
+ /* Enables Receive MAC */
+ rctl = ioread32(&hw->reg->MAC_RX_EN);
+ iowrite32((rctl | PCH_GBE_MRE_MAC_RX_EN), &hw->reg->MAC_RX_EN);
}
/**
@@ -913,7 +898,7 @@ static void pch_gbe_setup_rctl(struct pch_gbe_adapter *adapter)
static void pch_gbe_configure_rx(struct pch_gbe_adapter *adapter)
{
struct pch_gbe_hw *hw = &adapter->hw;
- u32 rdba, rdlen, rctl, rxdma;
+ u32 rdba, rdlen, rxdma;
pr_debug("dma adr = 0x%08llx size = 0x%08x\n",
(unsigned long long)adapter->rx_ring->dma,
@@ -921,9 +906,7 @@ static void pch_gbe_configure_rx(struct pch_gbe_adapter *adapter)
pch_gbe_mac_force_mac_fc(hw);
- /* Disables Receive MAC */
- rctl = ioread32(&hw->reg->MAC_RX_EN);
- iowrite32((rctl & ~PCH_GBE_MRE_MAC_RX_EN), &hw->reg->MAC_RX_EN);
+ pch_gbe_disable_mac_rx(hw);
/* Disables Receive DMA */
rxdma = ioread32(&hw->reg->DMA_CTRL);
@@ -1316,38 +1299,17 @@ void pch_gbe_update_stats(struct pch_gbe_adapter *adapter)
spin_unlock_irqrestore(&adapter->stats_lock, flags);
}
-static void pch_gbe_stop_receive(struct pch_gbe_adapter *adapter)
+static void pch_gbe_disable_dma_rx(struct pch_gbe_hw *hw)
{
- struct pch_gbe_hw *hw = &adapter->hw;
u32 rxdma;
- u16 value;
- int ret;
/* Disable Receive DMA */
rxdma = ioread32(&hw->reg->DMA_CTRL);
rxdma &= ~PCH_GBE_RX_DMA_EN;
iowrite32(rxdma, &hw->reg->DMA_CTRL);
- /* Wait Rx DMA BUS is IDLE */
- ret = pch_gbe_wait_clr_bit_irq(&hw->reg->RX_DMA_ST, PCH_GBE_IDLE_CHECK);
- if (ret) {
- /* Disable Bus master */
- pci_read_config_word(adapter->pdev, PCI_COMMAND, &value);
- value &= ~PCI_COMMAND_MASTER;
- pci_write_config_word(adapter->pdev, PCI_COMMAND, value);
- /* Stop Receive */
- pch_gbe_mac_reset_rx(hw);
- /* Enable Bus master */
- value |= PCI_COMMAND_MASTER;
- pci_write_config_word(adapter->pdev, PCI_COMMAND, value);
- } else {
- /* Stop Receive */
- pch_gbe_mac_reset_rx(hw);
- }
- /* reprogram multicast address register after reset */
- pch_gbe_set_multi(adapter->netdev);
}
-static void pch_gbe_start_receive(struct pch_gbe_hw *hw)
+static void pch_gbe_enable_dma_rx(struct pch_gbe_hw *hw)
{
u32 rxdma;
@@ -1355,9 +1317,6 @@ static void pch_gbe_start_receive(struct pch_gbe_hw *hw)
rxdma = ioread32(&hw->reg->DMA_CTRL);
rxdma |= PCH_GBE_RX_DMA_EN;
iowrite32(rxdma, &hw->reg->DMA_CTRL);
- /* Enables Receive */
- iowrite32(PCH_GBE_MRE_MAC_RX_EN, &hw->reg->MAC_RX_EN);
- return;
}
/**
@@ -1393,7 +1352,7 @@ static irqreturn_t pch_gbe_intr(int irq, void *data)
int_en = ioread32(&hw->reg->INT_EN);
iowrite32((int_en & ~PCH_GBE_INT_RX_FIFO_ERR),
&hw->reg->INT_EN);
- pch_gbe_stop_receive(adapter);
+ pch_gbe_disable_dma_rx(&adapter->hw);
int_st |= ioread32(&hw->reg->INT_ST);
int_st = int_st & ioread32(&hw->reg->INT_EN);
}
@@ -1971,12 +1930,12 @@ int pch_gbe_up(struct pch_gbe_adapter *adapter)
struct net_device *netdev = adapter->netdev;
struct pch_gbe_tx_ring *tx_ring = adapter->tx_ring;
struct pch_gbe_rx_ring *rx_ring = adapter->rx_ring;
- int err;
+ int err = -EINVAL;
/* Ensure we have a valid MAC */
if (!is_valid_ether_addr(adapter->hw.mac.addr)) {
pr_err("Error: Invalid MAC address\n");
- return -EINVAL;
+ goto out;
}
/* hardware has been reset, we need to reload some things */
@@ -1989,18 +1948,19 @@ int pch_gbe_up(struct pch_gbe_adapter *adapter)
err = pch_gbe_request_irq(adapter);
if (err) {
- pr_err("Error: can't bring device up\n");
- return err;
+ pr_err("Error: can't bring device up - irq request failed\n");
+ goto out;
}
err = pch_gbe_alloc_rx_buffers_pool(adapter, rx_ring, rx_ring->count);
if (err) {
- pr_err("Error: can't bring device up\n");
- return err;
+ pr_err("Error: can't bring device up - alloc rx buffers pool failed\n");
+ goto freeirq;
}
pch_gbe_alloc_tx_buffers(adapter, tx_ring);
pch_gbe_alloc_rx_buffers(adapter, rx_ring, rx_ring->count);
adapter->tx_queue_len = netdev->tx_queue_len;
- pch_gbe_start_receive(&adapter->hw);
+ pch_gbe_enable_dma_rx(&adapter->hw);
+ pch_gbe_enable_mac_rx(&adapter->hw);
mod_timer(&adapter->watchdog_timer, jiffies);
@@ -2009,6 +1969,11 @@ int pch_gbe_up(struct pch_gbe_adapter *adapter)
netif_start_queue(adapter->netdev);
return 0;
+
+freeirq:
+ pch_gbe_free_irq(adapter);
+out:
+ return err;
}
/**
@@ -2405,7 +2370,6 @@ static int pch_gbe_napi_poll(struct napi_struct *napi, int budget)
int work_done = 0;
bool poll_end_flag = false;
bool cleaned = false;
- u32 int_en;
pr_debug("budget : %d\n", budget);
@@ -2422,19 +2386,13 @@ static int pch_gbe_napi_poll(struct napi_struct *napi, int budget)
if (poll_end_flag) {
napi_complete(napi);
- if (adapter->rx_stop_flag) {
- adapter->rx_stop_flag = false;
- pch_gbe_start_receive(&adapter->hw);
- }
pch_gbe_irq_enable(adapter);
- } else
- if (adapter->rx_stop_flag) {
- adapter->rx_stop_flag = false;
- pch_gbe_start_receive(&adapter->hw);
- int_en = ioread32(&adapter->hw.reg->INT_EN);
- iowrite32((int_en | PCH_GBE_INT_RX_FIFO_ERR),
- &adapter->hw.reg->INT_EN);
- }
+ }
+
+ if (adapter->rx_stop_flag) {
+ adapter->rx_stop_flag = false;
+ pch_gbe_enable_dma_rx(&adapter->hw);
+ }
pr_debug("poll_end_flag : %d work_done : %d budget : %d\n",
poll_end_flag, work_done, budget);
diff --git a/drivers/net/ethernet/qlogic/qla3xxx.c b/drivers/net/ethernet/qlogic/qla3xxx.c
index df09b1cb742f..6407d0d77e81 100644
--- a/drivers/net/ethernet/qlogic/qla3xxx.c
+++ b/drivers/net/ethernet/qlogic/qla3xxx.c
@@ -2525,6 +2525,13 @@ static int ql_alloc_net_req_rsp_queues(struct ql3_adapter *qdev)
qdev->req_q_size =
(u32) (NUM_REQ_Q_ENTRIES * sizeof(struct ob_mac_iocb_req));
+ qdev->rsp_q_size = NUM_RSP_Q_ENTRIES * sizeof(struct net_rsp_iocb);
+
+ /* The barrier is required to ensure request and response queue
+ * addr writes to the registers.
+ */
+ wmb();
+
qdev->req_q_virt_addr =
pci_alloc_consistent(qdev->pdev,
(size_t) qdev->req_q_size,
@@ -2536,8 +2543,6 @@ static int ql_alloc_net_req_rsp_queues(struct ql3_adapter *qdev)
return -ENOMEM;
}
- qdev->rsp_q_size = NUM_RSP_Q_ENTRIES * sizeof(struct net_rsp_iocb);
-
qdev->rsp_q_virt_addr =
pci_alloc_consistent(qdev->pdev,
(size_t) qdev->rsp_q_size,
diff --git a/drivers/net/ethernet/ti/Kconfig b/drivers/net/ethernet/ti/Kconfig
index b26cbda5efa9..2c41894d5472 100644
--- a/drivers/net/ethernet/ti/Kconfig
+++ b/drivers/net/ethernet/ti/Kconfig
@@ -5,7 +5,7 @@
config NET_VENDOR_TI
bool "Texas Instruments (TI) devices"
default y
- depends on PCI || EISA || AR7 || (ARM && (ARCH_DAVINCI || ARCH_OMAP3))
+ depends on PCI || EISA || AR7 || (ARM && (ARCH_DAVINCI || ARCH_OMAP3 || SOC_AM33XX))
---help---
If you have a network (Ethernet) card belonging to this class, say Y
and read the Ethernet-HOWTO, available from
diff --git a/drivers/net/ethernet/tile/tilegx.c b/drivers/net/ethernet/tile/tilegx.c
index 4e2a1628484d..4e9810013850 100644
--- a/drivers/net/ethernet/tile/tilegx.c
+++ b/drivers/net/ethernet/tile/tilegx.c
@@ -1334,11 +1334,11 @@ static int tso_count_edescs(struct sk_buff *skb)
{
struct skb_shared_info *sh = skb_shinfo(skb);
unsigned int sh_len = skb_transport_offset(skb) + tcp_hdrlen(skb);
- unsigned int data_len = skb->data_len + skb->hdr_len - sh_len;
+ unsigned int data_len = skb->len - sh_len;
unsigned int p_len = sh->gso_size;
long f_id = -1; /* id of the current fragment */
- long f_size = skb->hdr_len; /* size of the current fragment */
- long f_used = sh_len; /* bytes used from the current fragment */
+ long f_size = skb_headlen(skb) - sh_len; /* current fragment size */
+ long f_used = 0; /* bytes used from the current fragment */
long n; /* size of the current piece of payload */
int num_edescs = 0;
int segment;
@@ -1353,7 +1353,7 @@ static int tso_count_edescs(struct sk_buff *skb)
/* Advance as needed. */
while (f_used >= f_size) {
f_id++;
- f_size = sh->frags[f_id].size;
+ f_size = skb_frag_size(&sh->frags[f_id]);
f_used = 0;
}
@@ -1384,13 +1384,13 @@ static void tso_headers_prepare(struct sk_buff *skb, unsigned char *headers,
struct iphdr *ih;
struct tcphdr *th;
unsigned int sh_len = skb_transport_offset(skb) + tcp_hdrlen(skb);
- unsigned int data_len = skb->data_len + skb->hdr_len - sh_len;
+ unsigned int data_len = skb->len - sh_len;
unsigned char *data = skb->data;
unsigned int ih_off, th_off, p_len;
unsigned int isum_seed, tsum_seed, id, seq;
long f_id = -1; /* id of the current fragment */
- long f_size = skb->hdr_len; /* size of the current fragment */
- long f_used = sh_len; /* bytes used from the current fragment */
+ long f_size = skb_headlen(skb) - sh_len; /* current fragment size */
+ long f_used = 0; /* bytes used from the current fragment */
long n; /* size of the current piece of payload */
int segment;
@@ -1405,7 +1405,7 @@ static void tso_headers_prepare(struct sk_buff *skb, unsigned char *headers,
isum_seed = ((0xFFFF - ih->check) +
(0xFFFF - ih->tot_len) +
(0xFFFF - ih->id));
- tsum_seed = th->check + (0xFFFF ^ htons(sh_len + data_len));
+ tsum_seed = th->check + (0xFFFF ^ htons(skb->len));
id = ntohs(ih->id);
seq = ntohl(th->seq);
@@ -1444,7 +1444,7 @@ static void tso_headers_prepare(struct sk_buff *skb, unsigned char *headers,
/* Advance as needed. */
while (f_used >= f_size) {
f_id++;
- f_size = sh->frags[f_id].size;
+ f_size = skb_frag_size(&sh->frags[f_id]);
f_used = 0;
}
@@ -1478,14 +1478,14 @@ static void tso_egress(struct net_device *dev, gxio_mpipe_equeue_t *equeue,
struct tile_net_priv *priv = netdev_priv(dev);
struct skb_shared_info *sh = skb_shinfo(skb);
unsigned int sh_len = skb_transport_offset(skb) + tcp_hdrlen(skb);
- unsigned int data_len = skb->data_len + skb->hdr_len - sh_len;
+ unsigned int data_len = skb->len - sh_len;
unsigned int p_len = sh->gso_size;
gxio_mpipe_edesc_t edesc_head = { { 0 } };
gxio_mpipe_edesc_t edesc_body = { { 0 } };
long f_id = -1; /* id of the current fragment */
- long f_size = skb->hdr_len; /* size of the current fragment */
- long f_used = sh_len; /* bytes used from the current fragment */
- void *f_data = skb->data;
+ long f_size = skb_headlen(skb) - sh_len; /* current fragment size */
+ long f_used = 0; /* bytes used from the current fragment */
+ void *f_data = skb->data + sh_len;
long n; /* size of the current piece of payload */
unsigned long tx_packets = 0, tx_bytes = 0;
unsigned int csum_start;
@@ -1516,15 +1516,18 @@ static void tso_egress(struct net_device *dev, gxio_mpipe_equeue_t *equeue,
/* Egress the payload. */
while (p_used < p_len) {
+ void *va;
/* Advance as needed. */
while (f_used >= f_size) {
f_id++;
- f_size = sh->frags[f_id].size;
- f_used = 0;
+ f_size = skb_frag_size(&sh->frags[f_id]);
f_data = tile_net_frag_buf(&sh->frags[f_id]);
+ f_used = 0;
}
+ va = f_data + f_used;
+
/* Use bytes from the current fragment. */
n = p_len - p_used;
if (n > f_size - f_used)
@@ -1533,7 +1536,7 @@ static void tso_egress(struct net_device *dev, gxio_mpipe_equeue_t *equeue,
p_used += n;
/* Egress a piece of the payload. */
- edesc_body.va = va_to_tile_io_addr(f_data) + f_used;
+ edesc_body.va = va_to_tile_io_addr(va);
edesc_body.xfer_size = n;
edesc_body.bound = !(p_used < p_len);
gxio_mpipe_equeue_put_at(equeue, edesc_body, slot);
diff --git a/drivers/net/phy/Kconfig b/drivers/net/phy/Kconfig
index 983bbf4d5ef6..961f0b293913 100644
--- a/drivers/net/phy/Kconfig
+++ b/drivers/net/phy/Kconfig
@@ -15,6 +15,11 @@ if PHYLIB
comment "MII PHY device drivers"
+config AT803X_PHY
+ tristate "Drivers for Atheros AT803X PHYs"
+ ---help---
+ Currently supports the AT8030 and AT8035 model
+
config AMD_PHY
tristate "Drivers for the AMD PHYs"
---help---
diff --git a/drivers/net/phy/Makefile b/drivers/net/phy/Makefile
index 426674debae4..9645e389a58d 100644
--- a/drivers/net/phy/Makefile
+++ b/drivers/net/phy/Makefile
@@ -25,6 +25,7 @@ obj-$(CONFIG_STE10XP) += ste10Xp.o
obj-$(CONFIG_MICREL_PHY) += micrel.o
obj-$(CONFIG_MDIO_OCTEON) += mdio-octeon.o
obj-$(CONFIG_MICREL_KS8995MA) += spi_ks8995.o
+obj-$(CONFIG_AT803X_PHY) += at803x.o
obj-$(CONFIG_AMD_PHY) += amd.o
obj-$(CONFIG_MDIO_BUS_MUX) += mdio-mux.o
obj-$(CONFIG_MDIO_BUS_MUX_GPIO) += mdio-mux-gpio.o
diff --git a/drivers/net/phy/at803x.c b/drivers/net/phy/at803x.c
new file mode 100644
index 000000000000..45cbc10de01c
--- /dev/null
+++ b/drivers/net/phy/at803x.c
@@ -0,0 +1,176 @@
+/*
+ * drivers/net/phy/at803x.c
+ *
+ * Driver for Atheros 803x PHY
+ *
+ * Author: Matus Ujhelyi <ujhelyi.m@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ */
+
+#include <linux/phy.h>
+#include <linux/module.h>
+#include <linux/string.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+
+#define AT803X_INTR_ENABLE 0x12
+#define AT803X_INTR_STATUS 0x13
+#define AT803X_WOL_ENABLE 0x01
+#define AT803X_DEVICE_ADDR 0x03
+#define AT803X_LOC_MAC_ADDR_0_15_OFFSET 0x804C
+#define AT803X_LOC_MAC_ADDR_16_31_OFFSET 0x804B
+#define AT803X_LOC_MAC_ADDR_32_47_OFFSET 0x804A
+#define AT803X_MMD_ACCESS_CONTROL 0x0D
+#define AT803X_MMD_ACCESS_CONTROL_DATA 0x0E
+#define AT803X_FUNC_DATA 0x4003
+
+MODULE_DESCRIPTION("Atheros 803x PHY driver");
+MODULE_AUTHOR("Matus Ujhelyi");
+MODULE_LICENSE("GPL");
+
+static void at803x_set_wol_mac_addr(struct phy_device *phydev)
+{
+ struct net_device *ndev = phydev->attached_dev;
+ const u8 *mac;
+ unsigned int i, offsets[] = {
+ AT803X_LOC_MAC_ADDR_32_47_OFFSET,
+ AT803X_LOC_MAC_ADDR_16_31_OFFSET,
+ AT803X_LOC_MAC_ADDR_0_15_OFFSET,
+ };
+
+ if (!ndev)
+ return;
+
+ mac = (const u8 *) ndev->dev_addr;
+
+ if (!is_valid_ether_addr(mac))
+ return;
+
+ for (i = 0; i < 3; i++) {
+ phy_write(phydev, AT803X_MMD_ACCESS_CONTROL,
+ AT803X_DEVICE_ADDR);
+ phy_write(phydev, AT803X_MMD_ACCESS_CONTROL_DATA,
+ offsets[i]);
+ phy_write(phydev, AT803X_MMD_ACCESS_CONTROL,
+ AT803X_FUNC_DATA);
+ phy_write(phydev, AT803X_MMD_ACCESS_CONTROL_DATA,
+ mac[(i * 2) + 1] | (mac[(i * 2)] << 8));
+ }
+}
+
+static int at803x_config_init(struct phy_device *phydev)
+{
+ int val;
+ u32 features;
+ int status;
+
+ features = SUPPORTED_TP | SUPPORTED_MII | SUPPORTED_AUI |
+ SUPPORTED_FIBRE | SUPPORTED_BNC;
+
+ val = phy_read(phydev, MII_BMSR);
+ if (val < 0)
+ return val;
+
+ if (val & BMSR_ANEGCAPABLE)
+ features |= SUPPORTED_Autoneg;
+ if (val & BMSR_100FULL)
+ features |= SUPPORTED_100baseT_Full;
+ if (val & BMSR_100HALF)
+ features |= SUPPORTED_100baseT_Half;
+ if (val & BMSR_10FULL)
+ features |= SUPPORTED_10baseT_Full;
+ if (val & BMSR_10HALF)
+ features |= SUPPORTED_10baseT_Half;
+
+ if (val & BMSR_ESTATEN) {
+ val = phy_read(phydev, MII_ESTATUS);
+ if (val < 0)
+ return val;
+
+ if (val & ESTATUS_1000_TFULL)
+ features |= SUPPORTED_1000baseT_Full;
+ if (val & ESTATUS_1000_THALF)
+ features |= SUPPORTED_1000baseT_Half;
+ }
+
+ phydev->supported = features;
+ phydev->advertising = features;
+
+ /* enable WOL */
+ at803x_set_wol_mac_addr(phydev);
+ status = phy_write(phydev, AT803X_INTR_ENABLE, AT803X_WOL_ENABLE);
+ status = phy_read(phydev, AT803X_INTR_STATUS);
+
+ return 0;
+}
+
+/* ATHEROS 8035 */
+static struct phy_driver at8035_driver = {
+ .phy_id = 0x004dd072,
+ .name = "Atheros 8035 ethernet",
+ .phy_id_mask = 0xffffffef,
+ .config_init = at803x_config_init,
+ .features = PHY_GBIT_FEATURES,
+ .flags = PHY_HAS_INTERRUPT,
+ .config_aneg = &genphy_config_aneg,
+ .read_status = &genphy_read_status,
+ .driver = {
+ .owner = THIS_MODULE,
+ },
+};
+
+/* ATHEROS 8030 */
+static struct phy_driver at8030_driver = {
+ .phy_id = 0x004dd076,
+ .name = "Atheros 8030 ethernet",
+ .phy_id_mask = 0xffffffef,
+ .config_init = at803x_config_init,
+ .features = PHY_GBIT_FEATURES,
+ .flags = PHY_HAS_INTERRUPT,
+ .config_aneg = &genphy_config_aneg,
+ .read_status = &genphy_read_status,
+ .driver = {
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init atheros_init(void)
+{
+ int ret;
+
+ ret = phy_driver_register(&at8035_driver);
+ if (ret)
+ goto err1;
+
+ ret = phy_driver_register(&at8030_driver);
+ if (ret)
+ goto err2;
+
+ return 0;
+
+err2:
+ phy_driver_unregister(&at8035_driver);
+err1:
+ return ret;
+}
+
+static void __exit atheros_exit(void)
+{
+ phy_driver_unregister(&at8035_driver);
+ phy_driver_unregister(&at8030_driver);
+}
+
+module_init(atheros_init);
+module_exit(atheros_exit);
+
+static struct mdio_device_id __maybe_unused atheros_tbl[] = {
+ { 0x004dd076, 0xffffffef },
+ { 0x004dd072, 0xffffffef },
+ { }
+};
+
+MODULE_DEVICE_TABLE(mdio, atheros_tbl);
diff --git a/drivers/net/usb/cdc_ether.c b/drivers/net/usb/cdc_ether.c
index a03de7197049..d0129827602b 100644
--- a/drivers/net/usb/cdc_ether.c
+++ b/drivers/net/usb/cdc_ether.c
@@ -592,6 +592,32 @@ static const struct usb_device_id products [] = {
.driver_info = 0,
},
+/* Novatel USB551L and MC551 - handled by qmi_wwan */
+{
+ .match_flags = USB_DEVICE_ID_MATCH_VENDOR
+ | USB_DEVICE_ID_MATCH_PRODUCT
+ | USB_DEVICE_ID_MATCH_INT_INFO,
+ .idVendor = NOVATEL_VENDOR_ID,
+ .idProduct = 0xB001,
+ .bInterfaceClass = USB_CLASS_COMM,
+ .bInterfaceSubClass = USB_CDC_SUBCLASS_ETHERNET,
+ .bInterfaceProtocol = USB_CDC_PROTO_NONE,
+ .driver_info = 0,
+},
+
+/* Novatel E362 - handled by qmi_wwan */
+{
+ .match_flags = USB_DEVICE_ID_MATCH_VENDOR
+ | USB_DEVICE_ID_MATCH_PRODUCT
+ | USB_DEVICE_ID_MATCH_INT_INFO,
+ .idVendor = NOVATEL_VENDOR_ID,
+ .idProduct = 0x9010,
+ .bInterfaceClass = USB_CLASS_COMM,
+ .bInterfaceSubClass = USB_CDC_SUBCLASS_ETHERNET,
+ .bInterfaceProtocol = USB_CDC_PROTO_NONE,
+ .driver_info = 0,
+},
+
/*
* WHITELIST!!!
*
@@ -604,21 +630,6 @@ static const struct usb_device_id products [] = {
* because of bugs/quirks in a given product (like Zaurus, above).
*/
{
- /* Novatel USB551L */
- /* This match must come *before* the generic CDC-ETHER match so that
- * we get FLAG_WWAN set on the device, since it's descriptors are
- * generic CDC-ETHER.
- */
- .match_flags = USB_DEVICE_ID_MATCH_VENDOR
- | USB_DEVICE_ID_MATCH_PRODUCT
- | USB_DEVICE_ID_MATCH_INT_INFO,
- .idVendor = NOVATEL_VENDOR_ID,
- .idProduct = 0xB001,
- .bInterfaceClass = USB_CLASS_COMM,
- .bInterfaceSubClass = USB_CDC_SUBCLASS_ETHERNET,
- .bInterfaceProtocol = USB_CDC_PROTO_NONE,
- .driver_info = (unsigned long)&wwan_info,
-}, {
/* ZTE (Vodafone) K3805-Z */
.match_flags = USB_DEVICE_ID_MATCH_VENDOR
| USB_DEVICE_ID_MATCH_PRODUCT
diff --git a/drivers/net/usb/ipheth.c b/drivers/net/usb/ipheth.c
index a28a983d465e..534d8becbbdc 100644
--- a/drivers/net/usb/ipheth.c
+++ b/drivers/net/usb/ipheth.c
@@ -62,6 +62,7 @@
#define USB_PRODUCT_IPAD 0x129a
#define USB_PRODUCT_IPHONE_4_VZW 0x129c
#define USB_PRODUCT_IPHONE_4S 0x12a0
+#define USB_PRODUCT_IPHONE_5 0x12a8
#define IPHETH_USBINTF_CLASS 255
#define IPHETH_USBINTF_SUBCLASS 253
@@ -113,6 +114,10 @@ static struct usb_device_id ipheth_table[] = {
USB_VENDOR_APPLE, USB_PRODUCT_IPHONE_4S,
IPHETH_USBINTF_CLASS, IPHETH_USBINTF_SUBCLASS,
IPHETH_USBINTF_PROTO) },
+ { USB_DEVICE_AND_INTERFACE_INFO(
+ USB_VENDOR_APPLE, USB_PRODUCT_IPHONE_5,
+ IPHETH_USBINTF_CLASS, IPHETH_USBINTF_SUBCLASS,
+ IPHETH_USBINTF_PROTO) },
{ }
};
MODULE_DEVICE_TABLE(usb, ipheth_table);
diff --git a/drivers/net/usb/qmi_wwan.c b/drivers/net/usb/qmi_wwan.c
index 6883c371c59f..3b566fa0f8e6 100644
--- a/drivers/net/usb/qmi_wwan.c
+++ b/drivers/net/usb/qmi_wwan.c
@@ -369,18 +369,73 @@ static const struct usb_device_id products[] = {
USB_VENDOR_AND_INTERFACE_INFO(0x106c, USB_CLASS_VENDOR_SPEC, 0xf1, 0xff),
.driver_info = (unsigned long)&qmi_wwan_info,
},
+ { /* Novatel USB551L and MC551 */
+ USB_DEVICE_AND_INTERFACE_INFO(0x1410, 0xb001,
+ USB_CLASS_COMM,
+ USB_CDC_SUBCLASS_ETHERNET,
+ USB_CDC_PROTO_NONE),
+ .driver_info = (unsigned long)&qmi_wwan_info,
+ },
+ { /* Novatel E362 */
+ USB_DEVICE_AND_INTERFACE_INFO(0x1410, 0x9010,
+ USB_CLASS_COMM,
+ USB_CDC_SUBCLASS_ETHERNET,
+ USB_CDC_PROTO_NONE),
+ .driver_info = (unsigned long)&qmi_wwan_info,
+ },
/* 3. Combined interface devices matching on interface number */
+ {QMI_FIXED_INTF(0x19d2, 0x0002, 1)},
+ {QMI_FIXED_INTF(0x19d2, 0x0012, 1)},
+ {QMI_FIXED_INTF(0x19d2, 0x0017, 3)},
+ {QMI_FIXED_INTF(0x19d2, 0x0021, 4)},
+ {QMI_FIXED_INTF(0x19d2, 0x0025, 1)},
+ {QMI_FIXED_INTF(0x19d2, 0x0031, 4)},
+ {QMI_FIXED_INTF(0x19d2, 0x0042, 4)},
+ {QMI_FIXED_INTF(0x19d2, 0x0049, 5)},
+ {QMI_FIXED_INTF(0x19d2, 0x0052, 4)},
{QMI_FIXED_INTF(0x19d2, 0x0055, 1)}, /* ZTE (Vodafone) K3520-Z */
+ {QMI_FIXED_INTF(0x19d2, 0x0058, 4)},
{QMI_FIXED_INTF(0x19d2, 0x0063, 4)}, /* ZTE (Vodafone) K3565-Z */
{QMI_FIXED_INTF(0x19d2, 0x0104, 4)}, /* ZTE (Vodafone) K4505-Z */
+ {QMI_FIXED_INTF(0x19d2, 0x0113, 5)},
+ {QMI_FIXED_INTF(0x19d2, 0x0118, 5)},
+ {QMI_FIXED_INTF(0x19d2, 0x0121, 5)},
+ {QMI_FIXED_INTF(0x19d2, 0x0123, 4)},
+ {QMI_FIXED_INTF(0x19d2, 0x0124, 5)},
+ {QMI_FIXED_INTF(0x19d2, 0x0125, 6)},
+ {QMI_FIXED_INTF(0x19d2, 0x0126, 5)},
+ {QMI_FIXED_INTF(0x19d2, 0x0130, 1)},
+ {QMI_FIXED_INTF(0x19d2, 0x0133, 3)},
+ {QMI_FIXED_INTF(0x19d2, 0x0141, 5)},
{QMI_FIXED_INTF(0x19d2, 0x0157, 5)}, /* ZTE MF683 */
+ {QMI_FIXED_INTF(0x19d2, 0x0158, 3)},
{QMI_FIXED_INTF(0x19d2, 0x0167, 4)}, /* ZTE MF820D */
+ {QMI_FIXED_INTF(0x19d2, 0x0168, 4)},
+ {QMI_FIXED_INTF(0x19d2, 0x0176, 3)},
+ {QMI_FIXED_INTF(0x19d2, 0x0178, 3)},
+ {QMI_FIXED_INTF(0x19d2, 0x0191, 4)}, /* ZTE EuFi890 */
+ {QMI_FIXED_INTF(0x19d2, 0x0199, 1)}, /* ZTE MF820S */
+ {QMI_FIXED_INTF(0x19d2, 0x0200, 1)},
+ {QMI_FIXED_INTF(0x19d2, 0x0257, 3)}, /* ZTE MF821 */
{QMI_FIXED_INTF(0x19d2, 0x0326, 4)}, /* ZTE MF821D */
{QMI_FIXED_INTF(0x19d2, 0x1008, 4)}, /* ZTE (Vodafone) K3570-Z */
{QMI_FIXED_INTF(0x19d2, 0x1010, 4)}, /* ZTE (Vodafone) K3571-Z */
+ {QMI_FIXED_INTF(0x19d2, 0x1012, 4)},
{QMI_FIXED_INTF(0x19d2, 0x1018, 3)}, /* ZTE (Vodafone) K5006-Z */
+ {QMI_FIXED_INTF(0x19d2, 0x1021, 2)},
+ {QMI_FIXED_INTF(0x19d2, 0x1245, 4)},
+ {QMI_FIXED_INTF(0x19d2, 0x1247, 4)},
+ {QMI_FIXED_INTF(0x19d2, 0x1252, 4)},
+ {QMI_FIXED_INTF(0x19d2, 0x1254, 4)},
+ {QMI_FIXED_INTF(0x19d2, 0x1255, 3)},
+ {QMI_FIXED_INTF(0x19d2, 0x1255, 4)},
+ {QMI_FIXED_INTF(0x19d2, 0x1256, 4)},
+ {QMI_FIXED_INTF(0x19d2, 0x1401, 2)},
{QMI_FIXED_INTF(0x19d2, 0x1402, 2)}, /* ZTE MF60 */
+ {QMI_FIXED_INTF(0x19d2, 0x1424, 2)},
+ {QMI_FIXED_INTF(0x19d2, 0x1425, 2)},
+ {QMI_FIXED_INTF(0x19d2, 0x1426, 2)}, /* ZTE MF91 */
{QMI_FIXED_INTF(0x19d2, 0x2002, 4)}, /* ZTE (Vodafone) K3765-Z */
{QMI_FIXED_INTF(0x0f3d, 0x68a2, 8)}, /* Sierra Wireless MC7700 */
{QMI_FIXED_INTF(0x114f, 0x68a2, 8)}, /* Sierra Wireless MC7750 */
diff --git a/drivers/net/usb/usbnet.c b/drivers/net/usb/usbnet.c
index f9819d10b1f9..cb04f900cc46 100644
--- a/drivers/net/usb/usbnet.c
+++ b/drivers/net/usb/usbnet.c
@@ -1158,6 +1158,7 @@ netdev_tx_t usbnet_start_xmit (struct sk_buff *skb,
usb_anchor_urb(urb, &dev->deferred);
/* no use to process more packets */
netif_stop_queue(net);
+ usb_put_urb(urb);
spin_unlock_irqrestore(&dev->txq.lock, flags);
netdev_dbg(dev->net, "Delaying transmission for resumption\n");
goto deferred;
@@ -1310,6 +1311,8 @@ void usbnet_disconnect (struct usb_interface *intf)
cancel_work_sync(&dev->kevent);
+ usb_scuttle_anchored_urbs(&dev->deferred);
+
if (dev->driver_info->unbind)
dev->driver_info->unbind (dev, intf);
diff --git a/drivers/net/wireless/ath/ath9k/ar9003_2p2_initvals.h b/drivers/net/wireless/ath/ath9k/ar9003_2p2_initvals.h
index 89bf94d4d8a1..6f7cf49eff4d 100644
--- a/drivers/net/wireless/ath/ath9k/ar9003_2p2_initvals.h
+++ b/drivers/net/wireless/ath/ath9k/ar9003_2p2_initvals.h
@@ -534,107 +534,107 @@ static const u32 ar9300_2p2_baseband_core[][2] = {
static const u32 ar9300Modes_high_power_tx_gain_table_2p2[][5] = {
/* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */
- {0x0000a2dc, 0x000cfff0, 0x000cfff0, 0x03aaa352, 0x03aaa352},
- {0x0000a2e0, 0x000f0000, 0x000f0000, 0x03ccc584, 0x03ccc584},
- {0x0000a2e4, 0x03f00000, 0x03f00000, 0x03f0f800, 0x03f0f800},
+ {0x0000a2dc, 0x00033800, 0x00033800, 0x03aaa352, 0x03aaa352},
+ {0x0000a2e0, 0x0003c000, 0x0003c000, 0x03ccc584, 0x03ccc584},
+ {0x0000a2e4, 0x03fc0000, 0x03fc0000, 0x03f0f800, 0x03f0f800},
{0x0000a2e8, 0x00000000, 0x00000000, 0x03ff0000, 0x03ff0000},
{0x0000a410, 0x000050d9, 0x000050d9, 0x000050d9, 0x000050d9},
{0x0000a500, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
{0x0000a504, 0x06000003, 0x06000003, 0x04000002, 0x04000002},
{0x0000a508, 0x0a000020, 0x0a000020, 0x08000004, 0x08000004},
{0x0000a50c, 0x10000023, 0x10000023, 0x0b000200, 0x0b000200},
- {0x0000a510, 0x15000028, 0x15000028, 0x0f000202, 0x0f000202},
- {0x0000a514, 0x1b00002b, 0x1b00002b, 0x12000400, 0x12000400},
- {0x0000a518, 0x1f020028, 0x1f020028, 0x16000402, 0x16000402},
- {0x0000a51c, 0x2502002b, 0x2502002b, 0x19000404, 0x19000404},
- {0x0000a520, 0x2a04002a, 0x2a04002a, 0x1c000603, 0x1c000603},
- {0x0000a524, 0x2e06002a, 0x2e06002a, 0x21000a02, 0x21000a02},
- {0x0000a528, 0x3302202d, 0x3302202d, 0x25000a04, 0x25000a04},
- {0x0000a52c, 0x3804202c, 0x3804202c, 0x28000a20, 0x28000a20},
- {0x0000a530, 0x3c06202c, 0x3c06202c, 0x2c000e20, 0x2c000e20},
- {0x0000a534, 0x4108202d, 0x4108202d, 0x30000e22, 0x30000e22},
- {0x0000a538, 0x4506402d, 0x4506402d, 0x34000e24, 0x34000e24},
- {0x0000a53c, 0x4906222d, 0x4906222d, 0x38001640, 0x38001640},
- {0x0000a540, 0x4d062231, 0x4d062231, 0x3c001660, 0x3c001660},
- {0x0000a544, 0x50082231, 0x50082231, 0x3f001861, 0x3f001861},
- {0x0000a548, 0x5608422e, 0x5608422e, 0x43001a81, 0x43001a81},
- {0x0000a54c, 0x5a08442e, 0x5a08442e, 0x47001a83, 0x47001a83},
- {0x0000a550, 0x5e0a4431, 0x5e0a4431, 0x4a001c84, 0x4a001c84},
- {0x0000a554, 0x640a4432, 0x640a4432, 0x4e001ce3, 0x4e001ce3},
- {0x0000a558, 0x680a4434, 0x680a4434, 0x52001ce5, 0x52001ce5},
- {0x0000a55c, 0x6c0a6434, 0x6c0a6434, 0x56001ce9, 0x56001ce9},
- {0x0000a560, 0x6f0a6633, 0x6f0a6633, 0x5a001ceb, 0x5a001ceb},
- {0x0000a564, 0x730c6634, 0x730c6634, 0x5d001eec, 0x5d001eec},
- {0x0000a568, 0x730c6634, 0x730c6634, 0x5d001eec, 0x5d001eec},
- {0x0000a56c, 0x730c6634, 0x730c6634, 0x5d001eec, 0x5d001eec},
- {0x0000a570, 0x730c6634, 0x730c6634, 0x5d001eec, 0x5d001eec},
- {0x0000a574, 0x730c6634, 0x730c6634, 0x5d001eec, 0x5d001eec},
- {0x0000a578, 0x730c6634, 0x730c6634, 0x5d001eec, 0x5d001eec},
- {0x0000a57c, 0x730c6634, 0x730c6634, 0x5d001eec, 0x5d001eec},
+ {0x0000a510, 0x16000220, 0x16000220, 0x0f000202, 0x0f000202},
+ {0x0000a514, 0x1c000223, 0x1c000223, 0x12000400, 0x12000400},
+ {0x0000a518, 0x21002220, 0x21002220, 0x16000402, 0x16000402},
+ {0x0000a51c, 0x27002223, 0x27002223, 0x19000404, 0x19000404},
+ {0x0000a520, 0x2b022220, 0x2b022220, 0x1c000603, 0x1c000603},
+ {0x0000a524, 0x2f022222, 0x2f022222, 0x21000a02, 0x21000a02},
+ {0x0000a528, 0x34022225, 0x34022225, 0x25000a04, 0x25000a04},
+ {0x0000a52c, 0x3a02222a, 0x3a02222a, 0x28000a20, 0x28000a20},
+ {0x0000a530, 0x3e02222c, 0x3e02222c, 0x2c000e20, 0x2c000e20},
+ {0x0000a534, 0x4202242a, 0x4202242a, 0x30000e22, 0x30000e22},
+ {0x0000a538, 0x4702244a, 0x4702244a, 0x34000e24, 0x34000e24},
+ {0x0000a53c, 0x4b02244c, 0x4b02244c, 0x38001640, 0x38001640},
+ {0x0000a540, 0x4e02246c, 0x4e02246c, 0x3c001660, 0x3c001660},
+ {0x0000a544, 0x52022470, 0x52022470, 0x3f001861, 0x3f001861},
+ {0x0000a548, 0x55022490, 0x55022490, 0x43001a81, 0x43001a81},
+ {0x0000a54c, 0x59022492, 0x59022492, 0x47001a83, 0x47001a83},
+ {0x0000a550, 0x5d022692, 0x5d022692, 0x4a001c84, 0x4a001c84},
+ {0x0000a554, 0x61022892, 0x61022892, 0x4e001ce3, 0x4e001ce3},
+ {0x0000a558, 0x65024890, 0x65024890, 0x52001ce5, 0x52001ce5},
+ {0x0000a55c, 0x69024892, 0x69024892, 0x56001ce9, 0x56001ce9},
+ {0x0000a560, 0x6e024c92, 0x6e024c92, 0x5a001ceb, 0x5a001ceb},
+ {0x0000a564, 0x74026e92, 0x74026e92, 0x5d001eec, 0x5d001eec},
+ {0x0000a568, 0x74026e92, 0x74026e92, 0x5d001eec, 0x5d001eec},
+ {0x0000a56c, 0x74026e92, 0x74026e92, 0x5d001eec, 0x5d001eec},
+ {0x0000a570, 0x74026e92, 0x74026e92, 0x5d001eec, 0x5d001eec},
+ {0x0000a574, 0x74026e92, 0x74026e92, 0x5d001eec, 0x5d001eec},
+ {0x0000a578, 0x74026e92, 0x74026e92, 0x5d001eec, 0x5d001eec},
+ {0x0000a57c, 0x74026e92, 0x74026e92, 0x5d001eec, 0x5d001eec},
{0x0000a580, 0x00800000, 0x00800000, 0x00800000, 0x00800000},
{0x0000a584, 0x06800003, 0x06800003, 0x04800002, 0x04800002},
{0x0000a588, 0x0a800020, 0x0a800020, 0x08800004, 0x08800004},
{0x0000a58c, 0x10800023, 0x10800023, 0x0b800200, 0x0b800200},
- {0x0000a590, 0x15800028, 0x15800028, 0x0f800202, 0x0f800202},
- {0x0000a594, 0x1b80002b, 0x1b80002b, 0x12800400, 0x12800400},
- {0x0000a598, 0x1f820028, 0x1f820028, 0x16800402, 0x16800402},
- {0x0000a59c, 0x2582002b, 0x2582002b, 0x19800404, 0x19800404},
- {0x0000a5a0, 0x2a84002a, 0x2a84002a, 0x1c800603, 0x1c800603},
- {0x0000a5a4, 0x2e86002a, 0x2e86002a, 0x21800a02, 0x21800a02},
- {0x0000a5a8, 0x3382202d, 0x3382202d, 0x25800a04, 0x25800a04},
- {0x0000a5ac, 0x3884202c, 0x3884202c, 0x28800a20, 0x28800a20},
- {0x0000a5b0, 0x3c86202c, 0x3c86202c, 0x2c800e20, 0x2c800e20},
- {0x0000a5b4, 0x4188202d, 0x4188202d, 0x30800e22, 0x30800e22},
- {0x0000a5b8, 0x4586402d, 0x4586402d, 0x34800e24, 0x34800e24},
- {0x0000a5bc, 0x4986222d, 0x4986222d, 0x38801640, 0x38801640},
- {0x0000a5c0, 0x4d862231, 0x4d862231, 0x3c801660, 0x3c801660},
- {0x0000a5c4, 0x50882231, 0x50882231, 0x3f801861, 0x3f801861},
- {0x0000a5c8, 0x5688422e, 0x5688422e, 0x43801a81, 0x43801a81},
- {0x0000a5cc, 0x5a88442e, 0x5a88442e, 0x47801a83, 0x47801a83},
- {0x0000a5d0, 0x5e8a4431, 0x5e8a4431, 0x4a801c84, 0x4a801c84},
- {0x0000a5d4, 0x648a4432, 0x648a4432, 0x4e801ce3, 0x4e801ce3},
- {0x0000a5d8, 0x688a4434, 0x688a4434, 0x52801ce5, 0x52801ce5},
- {0x0000a5dc, 0x6c8a6434, 0x6c8a6434, 0x56801ce9, 0x56801ce9},
- {0x0000a5e0, 0x6f8a6633, 0x6f8a6633, 0x5a801ceb, 0x5a801ceb},
- {0x0000a5e4, 0x738c6634, 0x738c6634, 0x5d801eec, 0x5d801eec},
- {0x0000a5e8, 0x738c6634, 0x738c6634, 0x5d801eec, 0x5d801eec},
- {0x0000a5ec, 0x738c6634, 0x738c6634, 0x5d801eec, 0x5d801eec},
- {0x0000a5f0, 0x738c6634, 0x738c6634, 0x5d801eec, 0x5d801eec},
- {0x0000a5f4, 0x738c6634, 0x738c6634, 0x5d801eec, 0x5d801eec},
- {0x0000a5f8, 0x738c6634, 0x738c6634, 0x5d801eec, 0x5d801eec},
- {0x0000a5fc, 0x738c6634, 0x738c6634, 0x5d801eec, 0x5d801eec},
+ {0x0000a590, 0x16800220, 0x16800220, 0x0f800202, 0x0f800202},
+ {0x0000a594, 0x1c800223, 0x1c800223, 0x12800400, 0x12800400},
+ {0x0000a598, 0x21802220, 0x21802220, 0x16800402, 0x16800402},
+ {0x0000a59c, 0x27802223, 0x27802223, 0x19800404, 0x19800404},
+ {0x0000a5a0, 0x2b822220, 0x2b822220, 0x1c800603, 0x1c800603},
+ {0x0000a5a4, 0x2f822222, 0x2f822222, 0x21800a02, 0x21800a02},
+ {0x0000a5a8, 0x34822225, 0x34822225, 0x25800a04, 0x25800a04},
+ {0x0000a5ac, 0x3a82222a, 0x3a82222a, 0x28800a20, 0x28800a20},
+ {0x0000a5b0, 0x3e82222c, 0x3e82222c, 0x2c800e20, 0x2c800e20},
+ {0x0000a5b4, 0x4282242a, 0x4282242a, 0x30800e22, 0x30800e22},
+ {0x0000a5b8, 0x4782244a, 0x4782244a, 0x34800e24, 0x34800e24},
+ {0x0000a5bc, 0x4b82244c, 0x4b82244c, 0x38801640, 0x38801640},
+ {0x0000a5c0, 0x4e82246c, 0x4e82246c, 0x3c801660, 0x3c801660},
+ {0x0000a5c4, 0x52822470, 0x52822470, 0x3f801861, 0x3f801861},
+ {0x0000a5c8, 0x55822490, 0x55822490, 0x43801a81, 0x43801a81},
+ {0x0000a5cc, 0x59822492, 0x59822492, 0x47801a83, 0x47801a83},
+ {0x0000a5d0, 0x5d822692, 0x5d822692, 0x4a801c84, 0x4a801c84},
+ {0x0000a5d4, 0x61822892, 0x61822892, 0x4e801ce3, 0x4e801ce3},
+ {0x0000a5d8, 0x65824890, 0x65824890, 0x52801ce5, 0x52801ce5},
+ {0x0000a5dc, 0x69824892, 0x69824892, 0x56801ce9, 0x56801ce9},
+ {0x0000a5e0, 0x6e824c92, 0x6e824c92, 0x5a801ceb, 0x5a801ceb},
+ {0x0000a5e4, 0x74826e92, 0x74826e92, 0x5d801eec, 0x5d801eec},
+ {0x0000a5e8, 0x74826e92, 0x74826e92, 0x5d801eec, 0x5d801eec},
+ {0x0000a5ec, 0x74826e92, 0x74826e92, 0x5d801eec, 0x5d801eec},
+ {0x0000a5f0, 0x74826e92, 0x74826e92, 0x5d801eec, 0x5d801eec},
+ {0x0000a5f4, 0x74826e92, 0x74826e92, 0x5d801eec, 0x5d801eec},
+ {0x0000a5f8, 0x74826e92, 0x74826e92, 0x5d801eec, 0x5d801eec},
+ {0x0000a5fc, 0x74826e92, 0x74826e92, 0x5d801eec, 0x5d801eec},
{0x0000a600, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
{0x0000a604, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
- {0x0000a608, 0x01804601, 0x01804601, 0x00000000, 0x00000000},
- {0x0000a60c, 0x01804601, 0x01804601, 0x00000000, 0x00000000},
- {0x0000a610, 0x01804601, 0x01804601, 0x00000000, 0x00000000},
- {0x0000a614, 0x01804601, 0x01804601, 0x01404000, 0x01404000},
- {0x0000a618, 0x01804601, 0x01804601, 0x01404501, 0x01404501},
- {0x0000a61c, 0x01804601, 0x01804601, 0x02008501, 0x02008501},
- {0x0000a620, 0x03408d02, 0x03408d02, 0x0280ca03, 0x0280ca03},
- {0x0000a624, 0x0300cc03, 0x0300cc03, 0x03010c04, 0x03010c04},
- {0x0000a628, 0x03410d04, 0x03410d04, 0x04014c04, 0x04014c04},
- {0x0000a62c, 0x03410d04, 0x03410d04, 0x04015005, 0x04015005},
- {0x0000a630, 0x03410d04, 0x03410d04, 0x04015005, 0x04015005},
- {0x0000a634, 0x03410d04, 0x03410d04, 0x04015005, 0x04015005},
- {0x0000a638, 0x03410d04, 0x03410d04, 0x04015005, 0x04015005},
- {0x0000a63c, 0x03410d04, 0x03410d04, 0x04015005, 0x04015005},
- {0x0000b2dc, 0x000cfff0, 0x000cfff0, 0x03aaa352, 0x03aaa352},
- {0x0000b2e0, 0x000f0000, 0x000f0000, 0x03ccc584, 0x03ccc584},
- {0x0000b2e4, 0x03f00000, 0x03f00000, 0x03f0f800, 0x03f0f800},
+ {0x0000a608, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+ {0x0000a60c, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+ {0x0000a610, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+ {0x0000a614, 0x02004000, 0x02004000, 0x01404000, 0x01404000},
+ {0x0000a618, 0x02004801, 0x02004801, 0x01404501, 0x01404501},
+ {0x0000a61c, 0x02808a02, 0x02808a02, 0x02008501, 0x02008501},
+ {0x0000a620, 0x0380ce03, 0x0380ce03, 0x0280ca03, 0x0280ca03},
+ {0x0000a624, 0x04411104, 0x04411104, 0x03010c04, 0x03010c04},
+ {0x0000a628, 0x04411104, 0x04411104, 0x04014c04, 0x04014c04},
+ {0x0000a62c, 0x04411104, 0x04411104, 0x04015005, 0x04015005},
+ {0x0000a630, 0x04411104, 0x04411104, 0x04015005, 0x04015005},
+ {0x0000a634, 0x04411104, 0x04411104, 0x04015005, 0x04015005},
+ {0x0000a638, 0x04411104, 0x04411104, 0x04015005, 0x04015005},
+ {0x0000a63c, 0x04411104, 0x04411104, 0x04015005, 0x04015005},
+ {0x0000b2dc, 0x00033800, 0x00033800, 0x03aaa352, 0x03aaa352},
+ {0x0000b2e0, 0x0003c000, 0x0003c000, 0x03ccc584, 0x03ccc584},
+ {0x0000b2e4, 0x03fc0000, 0x03fc0000, 0x03f0f800, 0x03f0f800},
{0x0000b2e8, 0x00000000, 0x00000000, 0x03ff0000, 0x03ff0000},
- {0x0000c2dc, 0x000cfff0, 0x000cfff0, 0x03aaa352, 0x03aaa352},
- {0x0000c2e0, 0x000f0000, 0x000f0000, 0x03ccc584, 0x03ccc584},
- {0x0000c2e4, 0x03f00000, 0x03f00000, 0x03f0f800, 0x03f0f800},
+ {0x0000c2dc, 0x00033800, 0x00033800, 0x03aaa352, 0x03aaa352},
+ {0x0000c2e0, 0x0003c000, 0x0003c000, 0x03ccc584, 0x03ccc584},
+ {0x0000c2e4, 0x03fc0000, 0x03fc0000, 0x03f0f800, 0x03f0f800},
{0x0000c2e8, 0x00000000, 0x00000000, 0x03ff0000, 0x03ff0000},
{0x00016044, 0x012492d4, 0x012492d4, 0x012492d4, 0x012492d4},
- {0x00016048, 0x61200001, 0x61200001, 0x66480001, 0x66480001},
+ {0x00016048, 0x66480001, 0x66480001, 0x66480001, 0x66480001},
{0x00016068, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c},
{0x00016444, 0x012492d4, 0x012492d4, 0x012492d4, 0x012492d4},
- {0x00016448, 0x61200001, 0x61200001, 0x66480001, 0x66480001},
+ {0x00016448, 0x66480001, 0x66480001, 0x66480001, 0x66480001},
{0x00016468, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c},
{0x00016844, 0x012492d4, 0x012492d4, 0x012492d4, 0x012492d4},
- {0x00016848, 0x61200001, 0x61200001, 0x66480001, 0x66480001},
+ {0x00016848, 0x66480001, 0x66480001, 0x66480001, 0x66480001},
{0x00016868, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c},
};
diff --git a/drivers/net/wireless/ath/ath9k/hif_usb.c b/drivers/net/wireless/ath/ath9k/hif_usb.c
index 924c4616c3d9..f5dda84176c3 100644
--- a/drivers/net/wireless/ath/ath9k/hif_usb.c
+++ b/drivers/net/wireless/ath/ath9k/hif_usb.c
@@ -38,6 +38,7 @@ static struct usb_device_id ath9k_hif_usb_ids[] = {
{ USB_DEVICE(0x04CA, 0x4605) }, /* Liteon */
{ USB_DEVICE(0x040D, 0x3801) }, /* VIA */
{ USB_DEVICE(0x0cf3, 0xb003) }, /* Ubiquiti WifiStation Ext */
+ { USB_DEVICE(0x0cf3, 0xb002) }, /* Ubiquiti WifiStation */
{ USB_DEVICE(0x057c, 0x8403) }, /* AVM FRITZ!WLAN 11N v2 USB */
{ USB_DEVICE(0x0cf3, 0x7015),
diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c
index 73730e94e0ac..c5a99c8c8168 100644
--- a/drivers/net/wireless/b43/main.c
+++ b/drivers/net/wireless/b43/main.c
@@ -5404,6 +5404,8 @@ static void b43_bcma_remove(struct bcma_device *core)
cancel_work_sync(&wldev->restart_work);
B43_WARN_ON(!wl);
+ if (!wldev->fw.ucode.data)
+ return; /* NULL if firmware never loaded */
if (wl->current_dev == wldev && wl->hw_registred) {
b43_leds_stop(wldev);
ieee80211_unregister_hw(wl->hw);
@@ -5478,6 +5480,8 @@ static void b43_ssb_remove(struct ssb_device *sdev)
cancel_work_sync(&wldev->restart_work);
B43_WARN_ON(!wl);
+ if (!wldev->fw.ucode.data)
+ return; /* NULL if firmware never loaded */
if (wl->current_dev == wldev && wl->hw_registred) {
b43_leds_stop(wldev);
ieee80211_unregister_hw(wl->hw);
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/usb.c b/drivers/net/wireless/brcm80211/brcmfmac/usb.c
index a2b4b1e71017..7a6dfdc67b6c 100644
--- a/drivers/net/wireless/brcm80211/brcmfmac/usb.c
+++ b/drivers/net/wireless/brcm80211/brcmfmac/usb.c
@@ -1339,7 +1339,7 @@ static int brcmf_usb_probe_cb(struct brcmf_usbdev_info *devinfo,
}
ret = brcmf_bus_start(dev);
- if (ret == -ENOLINK) {
+ if (ret) {
brcmf_dbg(ERROR, "dongle is not responding\n");
brcmf_detach(dev);
goto fail;
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c b/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c
index c1abaa6db59e..a6f1e8166008 100644
--- a/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c
+++ b/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c
@@ -3569,7 +3569,7 @@ brcmf_cfg80211_sched_scan_start(struct wiphy *wiphy,
if (!request || !request->n_ssids || !request->n_match_sets) {
WL_ERR("Invalid sched scan req!! n_ssids:%d\n",
- request->n_ssids);
+ request ? request->n_ssids : 0);
return -EINVAL;
}
@@ -3972,7 +3972,7 @@ brcmf_set_management_ie(struct brcmf_cfg80211_info *cfg,
u8 *iovar_ie_buf;
u8 *curr_ie_buf;
u8 *mgmt_ie_buf = NULL;
- u32 mgmt_ie_buf_len = 0;
+ int mgmt_ie_buf_len;
u32 *mgmt_ie_len = 0;
u32 del_add_ie_buf_len = 0;
u32 total_ie_buf_len = 0;
@@ -3982,7 +3982,7 @@ brcmf_set_management_ie(struct brcmf_cfg80211_info *cfg,
struct parsed_vndr_ie_info *vndrie_info;
s32 i;
u8 *ptr;
- u32 remained_buf_len;
+ int remained_buf_len;
WL_TRACE("bssidx %d, pktflag : 0x%02X\n", bssidx, pktflag);
iovar_ie_buf = kzalloc(WL_EXTRA_BUF_MAX, GFP_KERNEL);
@@ -4606,12 +4606,13 @@ brcmf_bss_roaming_done(struct brcmf_cfg80211_info *cfg,
struct brcmf_cfg80211_profile *profile = cfg->profile;
struct brcmf_cfg80211_connect_info *conn_info = cfg_to_conn(cfg);
struct wiphy *wiphy = cfg_to_wiphy(cfg);
- struct brcmf_channel_info_le channel_le;
- struct ieee80211_channel *notify_channel;
+ struct ieee80211_channel *notify_channel = NULL;
struct ieee80211_supported_band *band;
+ struct brcmf_bss_info_le *bi;
u32 freq;
s32 err = 0;
u32 target_channel;
+ u8 *buf;
WL_TRACE("Enter\n");
@@ -4619,11 +4620,22 @@ brcmf_bss_roaming_done(struct brcmf_cfg80211_info *cfg,
memcpy(profile->bssid, e->addr, ETH_ALEN);
brcmf_update_bss_info(cfg);
- brcmf_exec_dcmd(ndev, BRCMF_C_GET_CHANNEL, &channel_le,
- sizeof(channel_le));
+ buf = kzalloc(WL_BSS_INFO_MAX, GFP_KERNEL);
+ if (buf == NULL) {
+ err = -ENOMEM;
+ goto done;
+ }
+
+ /* data sent to dongle has to be little endian */
+ *(__le32 *)buf = cpu_to_le32(WL_BSS_INFO_MAX);
+ err = brcmf_exec_dcmd(ndev, BRCMF_C_GET_BSS_INFO, buf, WL_BSS_INFO_MAX);
+
+ if (err)
+ goto done;
- target_channel = le32_to_cpu(channel_le.target_channel);
- WL_CONN("Roamed to channel %d\n", target_channel);
+ bi = (struct brcmf_bss_info_le *)(buf + 4);
+ target_channel = bi->ctl_ch ? bi->ctl_ch :
+ CHSPEC_CHANNEL(le16_to_cpu(bi->chanspec));
if (target_channel <= CH_MAX_2G_CHANNEL)
band = wiphy->bands[IEEE80211_BAND_2GHZ];
@@ -4633,6 +4645,8 @@ brcmf_bss_roaming_done(struct brcmf_cfg80211_info *cfg,
freq = ieee80211_channel_to_frequency(target_channel, band->band);
notify_channel = ieee80211_get_channel(wiphy, freq);
+done:
+ kfree(buf);
cfg80211_roamed(ndev, notify_channel, (u8 *)profile->bssid,
conn_info->req_ie, conn_info->req_ie_len,
conn_info->resp_ie, conn_info->resp_ie_len, GFP_KERNEL);
@@ -5186,41 +5200,6 @@ brcmf_cfg80211_event(struct net_device *ndev,
schedule_work(&cfg->event_work);
}
-static s32 brcmf_dongle_mode(struct net_device *ndev, s32 iftype)
-{
- s32 infra = 0;
- s32 err = 0;
-
- switch (iftype) {
- case NL80211_IFTYPE_MONITOR:
- case NL80211_IFTYPE_WDS:
- WL_ERR("type (%d) : currently we do not support this mode\n",
- iftype);
- err = -EINVAL;
- return err;
- case NL80211_IFTYPE_ADHOC:
- infra = 0;
- break;
- case NL80211_IFTYPE_STATION:
- infra = 1;
- break;
- case NL80211_IFTYPE_AP:
- infra = 1;
- break;
- default:
- err = -EINVAL;
- WL_ERR("invalid type (%d)\n", iftype);
- return err;
- }
- err = brcmf_exec_dcmd_u32(ndev, BRCMF_C_SET_INFRA, &infra);
- if (err) {
- WL_ERR("WLC_SET_INFRA error (%d)\n", err);
- return err;
- }
-
- return 0;
-}
-
static s32 brcmf_dongle_eventmsg(struct net_device *ndev)
{
/* Room for "event_msgs" + '\0' + bitvec */
@@ -5439,7 +5418,8 @@ static s32 brcmf_config_dongle(struct brcmf_cfg80211_info *cfg)
WL_BEACON_TIMEOUT);
if (err)
goto default_conf_out;
- err = brcmf_dongle_mode(ndev, wdev->iftype);
+ err = brcmf_cfg80211_change_iface(wdev->wiphy, ndev, wdev->iftype,
+ NULL, NULL);
if (err && err != -EINPROGRESS)
goto default_conf_out;
err = brcmf_dongle_probecap(cfg);
diff --git a/drivers/net/wireless/ipw2x00/ipw2200.c b/drivers/net/wireless/ipw2x00/ipw2200.c
index 935120fc8c93..768bf612533e 100644
--- a/drivers/net/wireless/ipw2x00/ipw2200.c
+++ b/drivers/net/wireless/ipw2x00/ipw2200.c
@@ -10472,7 +10472,7 @@ static void ipw_handle_promiscuous_tx(struct ipw_priv *priv,
} else
len = src->len;
- dst = alloc_skb(len + sizeof(*rt_hdr), GFP_ATOMIC);
+ dst = alloc_skb(len + sizeof(*rt_hdr) + sizeof(u16)*2, GFP_ATOMIC);
if (!dst)
continue;
diff --git a/drivers/net/wireless/iwlwifi/dvm/devices.c b/drivers/net/wireless/iwlwifi/dvm/devices.c
index 349c205d5f62..da5862064195 100644
--- a/drivers/net/wireless/iwlwifi/dvm/devices.c
+++ b/drivers/net/wireless/iwlwifi/dvm/devices.c
@@ -518,7 +518,7 @@ static int iwl6000_hw_channel_switch(struct iwl_priv *priv,
* See iwlagn_mac_channel_switch.
*/
struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS];
- struct iwl6000_channel_switch_cmd cmd;
+ struct iwl6000_channel_switch_cmd *cmd;
u32 switch_time_in_usec, ucode_switch_time;
u16 ch;
u32 tsf_low;
@@ -527,18 +527,25 @@ static int iwl6000_hw_channel_switch(struct iwl_priv *priv,
struct ieee80211_vif *vif = ctx->vif;
struct iwl_host_cmd hcmd = {
.id = REPLY_CHANNEL_SWITCH,
- .len = { sizeof(cmd), },
+ .len = { sizeof(*cmd), },
.flags = CMD_SYNC,
- .data = { &cmd, },
+ .dataflags[0] = IWL_HCMD_DFL_NOCOPY,
};
+ int err;
- cmd.band = priv->band == IEEE80211_BAND_2GHZ;
+ cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
+ if (!cmd)
+ return -ENOMEM;
+
+ hcmd.data[0] = cmd;
+
+ cmd->band = priv->band == IEEE80211_BAND_2GHZ;
ch = ch_switch->channel->hw_value;
IWL_DEBUG_11H(priv, "channel switch from %u to %u\n",
ctx->active.channel, ch);
- cmd.channel = cpu_to_le16(ch);
- cmd.rxon_flags = ctx->staging.flags;
- cmd.rxon_filter_flags = ctx->staging.filter_flags;
+ cmd->channel = cpu_to_le16(ch);
+ cmd->rxon_flags = ctx->staging.flags;
+ cmd->rxon_filter_flags = ctx->staging.filter_flags;
switch_count = ch_switch->count;
tsf_low = ch_switch->timestamp & 0x0ffffffff;
/*
@@ -554,23 +561,25 @@ static int iwl6000_hw_channel_switch(struct iwl_priv *priv,
switch_count = 0;
}
if (switch_count <= 1)
- cmd.switch_time = cpu_to_le32(priv->ucode_beacon_time);
+ cmd->switch_time = cpu_to_le32(priv->ucode_beacon_time);
else {
switch_time_in_usec =
vif->bss_conf.beacon_int * switch_count * TIME_UNIT;
ucode_switch_time = iwl_usecs_to_beacons(priv,
switch_time_in_usec,
beacon_interval);
- cmd.switch_time = iwl_add_beacon_time(priv,
- priv->ucode_beacon_time,
- ucode_switch_time,
- beacon_interval);
+ cmd->switch_time = iwl_add_beacon_time(priv,
+ priv->ucode_beacon_time,
+ ucode_switch_time,
+ beacon_interval);
}
IWL_DEBUG_11H(priv, "uCode time for the switch is 0x%x\n",
- cmd.switch_time);
- cmd.expect_beacon = ch_switch->channel->flags & IEEE80211_CHAN_RADAR;
+ cmd->switch_time);
+ cmd->expect_beacon = ch_switch->channel->flags & IEEE80211_CHAN_RADAR;
- return iwl_dvm_send_cmd(priv, &hcmd);
+ err = iwl_dvm_send_cmd(priv, &hcmd);
+ kfree(cmd);
+ return err;
}
struct iwl_lib_ops iwl6000_lib = {
diff --git a/drivers/net/wireless/mwifiex/cfg80211.c b/drivers/net/wireless/mwifiex/cfg80211.c
index 0679458a1bac..780d3e168297 100644
--- a/drivers/net/wireless/mwifiex/cfg80211.c
+++ b/drivers/net/wireless/mwifiex/cfg80211.c
@@ -1825,8 +1825,6 @@ mwifiex_cfg80211_scan(struct wiphy *wiphy,
return -EBUSY;
}
- priv->scan_request = request;
-
priv->user_scan_cfg = kzalloc(sizeof(struct mwifiex_user_scan_cfg),
GFP_KERNEL);
if (!priv->user_scan_cfg) {
@@ -1834,6 +1832,8 @@ mwifiex_cfg80211_scan(struct wiphy *wiphy,
return -ENOMEM;
}
+ priv->scan_request = request;
+
priv->user_scan_cfg->num_ssids = request->n_ssids;
priv->user_scan_cfg->ssid_list = request->ssids;
@@ -1870,6 +1870,9 @@ mwifiex_cfg80211_scan(struct wiphy *wiphy,
ret = mwifiex_scan_networks(priv, priv->user_scan_cfg);
if (ret) {
dev_err(priv->adapter->dev, "scan failed: %d\n", ret);
+ priv->scan_request = NULL;
+ kfree(priv->user_scan_cfg);
+ priv->user_scan_cfg = NULL;
return ret;
}
diff --git a/drivers/net/wireless/mwifiex/scan.c b/drivers/net/wireless/mwifiex/scan.c
index 00b658d3b6ec..9171aaedbccd 100644
--- a/drivers/net/wireless/mwifiex/scan.c
+++ b/drivers/net/wireless/mwifiex/scan.c
@@ -1843,21 +1843,18 @@ static int mwifiex_scan_specific_ssid(struct mwifiex_private *priv,
struct cfg80211_ssid *req_ssid)
{
struct mwifiex_adapter *adapter = priv->adapter;
- int ret = 0;
+ int ret;
struct mwifiex_user_scan_cfg *scan_cfg;
- if (!req_ssid)
- return -1;
-
if (adapter->scan_processing) {
- dev_dbg(adapter->dev, "cmd: Scan already in process...\n");
- return ret;
+ dev_err(adapter->dev, "cmd: Scan already in process...\n");
+ return -EBUSY;
}
if (priv->scan_block) {
- dev_dbg(adapter->dev,
+ dev_err(adapter->dev,
"cmd: Scan is blocked during association...\n");
- return ret;
+ return -EBUSY;
}
scan_cfg = kzalloc(sizeof(struct mwifiex_user_scan_cfg), GFP_KERNEL);
diff --git a/drivers/net/wireless/rt2x00/rt2500usb.c b/drivers/net/wireless/rt2x00/rt2500usb.c
index a12e84f892be..6b2e1e431dd2 100644
--- a/drivers/net/wireless/rt2x00/rt2500usb.c
+++ b/drivers/net/wireless/rt2x00/rt2500usb.c
@@ -1988,6 +1988,7 @@ static struct usb_driver rt2500usb_driver = {
.disconnect = rt2x00usb_disconnect,
.suspend = rt2x00usb_suspend,
.resume = rt2x00usb_resume,
+ .reset_resume = rt2x00usb_resume,
.disable_hub_initiated_lpm = 1,
};
diff --git a/drivers/net/wireless/rt2x00/rt2800usb.c b/drivers/net/wireless/rt2x00/rt2800usb.c
index c9e9370eb789..3b8fb5a603f2 100644
--- a/drivers/net/wireless/rt2x00/rt2800usb.c
+++ b/drivers/net/wireless/rt2x00/rt2800usb.c
@@ -1282,6 +1282,7 @@ static struct usb_driver rt2800usb_driver = {
.disconnect = rt2x00usb_disconnect,
.suspend = rt2x00usb_suspend,
.resume = rt2x00usb_resume,
+ .reset_resume = rt2x00usb_resume,
.disable_hub_initiated_lpm = 1,
};
diff --git a/drivers/net/wireless/rt2x00/rt73usb.c b/drivers/net/wireless/rt2x00/rt73usb.c
index e5eb43b3eee7..24eec66e9fd2 100644
--- a/drivers/net/wireless/rt2x00/rt73usb.c
+++ b/drivers/net/wireless/rt2x00/rt73usb.c
@@ -2535,6 +2535,7 @@ static struct usb_driver rt73usb_driver = {
.disconnect = rt2x00usb_disconnect,
.suspend = rt2x00usb_suspend,
.resume = rt2x00usb_resume,
+ .reset_resume = rt2x00usb_resume,
.disable_hub_initiated_lpm = 1,
};
diff --git a/drivers/net/wireless/rtlwifi/usb.c b/drivers/net/wireless/rtlwifi/usb.c
index 030beb45d8b0..e3ea4b346889 100644
--- a/drivers/net/wireless/rtlwifi/usb.c
+++ b/drivers/net/wireless/rtlwifi/usb.c
@@ -673,7 +673,7 @@ static int rtl_usb_start(struct ieee80211_hw *hw)
set_hal_start(rtlhal);
/* Start bulk IN */
- _rtl_usb_receive(hw);
+ err = _rtl_usb_receive(hw);
}
return err;
diff --git a/drivers/scsi/qla2xxx/qla_mid.c b/drivers/scsi/qla2xxx/qla_mid.c
index bd4708a422cd..20fd974f903a 100644
--- a/drivers/scsi/qla2xxx/qla_mid.c
+++ b/drivers/scsi/qla2xxx/qla_mid.c
@@ -149,6 +149,7 @@ qla2x00_mark_vp_devices_dead(scsi_qla_host_t *vha)
int
qla24xx_disable_vp(scsi_qla_host_t *vha)
{
+ unsigned long flags;
int ret;
ret = qla24xx_control_vp(vha, VCE_COMMAND_DISABLE_VPS_LOGO_ALL);
@@ -156,7 +157,9 @@ qla24xx_disable_vp(scsi_qla_host_t *vha)
atomic_set(&vha->loop_down_timer, LOOP_DOWN_TIME);
/* Remove port id from vp target map */
+ spin_lock_irqsave(&vha->hw->vport_slock, flags);
qlt_update_vp_map(vha, RESET_AL_PA);
+ spin_unlock_irqrestore(&vha->hw->vport_slock, flags);
qla2x00_mark_vp_devices_dead(vha);
atomic_set(&vha->vp_state, VP_FAILED);
diff --git a/drivers/scsi/qla2xxx/qla_target.c b/drivers/scsi/qla2xxx/qla_target.c
index 0e09d8f433d1..62aa5584f644 100644
--- a/drivers/scsi/qla2xxx/qla_target.c
+++ b/drivers/scsi/qla2xxx/qla_target.c
@@ -557,6 +557,7 @@ static bool qlt_check_fcport_exist(struct scsi_qla_host *vha,
int pmap_len;
fc_port_t *fcport;
int global_resets;
+ unsigned long flags;
retry:
global_resets = atomic_read(&ha->tgt.qla_tgt->tgt_global_resets_count);
@@ -625,10 +626,10 @@ retry:
sess->s_id.b.area, sess->loop_id, fcport->d_id.b.domain,
fcport->d_id.b.al_pa, fcport->d_id.b.area, fcport->loop_id);
- sess->s_id = fcport->d_id;
- sess->loop_id = fcport->loop_id;
- sess->conf_compl_supported = !!(fcport->flags &
- FCF_CONF_COMP_SUPPORTED);
+ spin_lock_irqsave(&ha->hardware_lock, flags);
+ ha->tgt.tgt_ops->update_sess(sess, fcport->d_id, fcport->loop_id,
+ (fcport->flags & FCF_CONF_COMP_SUPPORTED));
+ spin_unlock_irqrestore(&ha->hardware_lock, flags);
res = true;
@@ -740,10 +741,9 @@ static struct qla_tgt_sess *qlt_create_sess(
qlt_undelete_sess(sess);
kref_get(&sess->se_sess->sess_kref);
- sess->s_id = fcport->d_id;
- sess->loop_id = fcport->loop_id;
- sess->conf_compl_supported = !!(fcport->flags &
- FCF_CONF_COMP_SUPPORTED);
+ ha->tgt.tgt_ops->update_sess(sess, fcport->d_id, fcport->loop_id,
+ (fcport->flags & FCF_CONF_COMP_SUPPORTED));
+
if (sess->local && !local)
sess->local = 0;
spin_unlock_irqrestore(&ha->hardware_lock, flags);
@@ -796,8 +796,7 @@ static struct qla_tgt_sess *qlt_create_sess(
*/
kref_get(&sess->se_sess->sess_kref);
- sess->conf_compl_supported = !!(fcport->flags &
- FCF_CONF_COMP_SUPPORTED);
+ sess->conf_compl_supported = (fcport->flags & FCF_CONF_COMP_SUPPORTED);
BUILD_BUG_ON(sizeof(sess->port_name) != sizeof(fcport->port_name));
memcpy(sess->port_name, fcport->port_name, sizeof(sess->port_name));
@@ -869,10 +868,8 @@ void qlt_fc_port_added(struct scsi_qla_host *vha, fc_port_t *fcport)
ql_dbg(ql_dbg_tgt_mgt, vha, 0xf007,
"Reappeared sess %p\n", sess);
}
- sess->s_id = fcport->d_id;
- sess->loop_id = fcport->loop_id;
- sess->conf_compl_supported = !!(fcport->flags &
- FCF_CONF_COMP_SUPPORTED);
+ ha->tgt.tgt_ops->update_sess(sess, fcport->d_id, fcport->loop_id,
+ (fcport->flags & FCF_CONF_COMP_SUPPORTED));
}
if (sess && sess->local) {
diff --git a/drivers/scsi/qla2xxx/qla_target.h b/drivers/scsi/qla2xxx/qla_target.h
index 170af1571214..bad749561ec2 100644
--- a/drivers/scsi/qla2xxx/qla_target.h
+++ b/drivers/scsi/qla2xxx/qla_target.h
@@ -648,6 +648,7 @@ struct qla_tgt_func_tmpl {
int (*check_initiator_node_acl)(struct scsi_qla_host *, unsigned char *,
void *, uint8_t *, uint16_t);
+ void (*update_sess)(struct qla_tgt_sess *, port_id_t, uint16_t, bool);
struct qla_tgt_sess *(*find_sess_by_loop_id)(struct scsi_qla_host *,
const uint16_t);
struct qla_tgt_sess *(*find_sess_by_s_id)(struct scsi_qla_host *,
diff --git a/drivers/scsi/qla2xxx/tcm_qla2xxx.c b/drivers/scsi/qla2xxx/tcm_qla2xxx.c
index 2358c16c4c8e..3d74f2f39ae1 100644
--- a/drivers/scsi/qla2xxx/tcm_qla2xxx.c
+++ b/drivers/scsi/qla2xxx/tcm_qla2xxx.c
@@ -237,7 +237,7 @@ static char *tcm_qla2xxx_get_fabric_wwn(struct se_portal_group *se_tpg)
struct tcm_qla2xxx_tpg, se_tpg);
struct tcm_qla2xxx_lport *lport = tpg->lport;
- return &lport->lport_name[0];
+ return lport->lport_naa_name;
}
static char *tcm_qla2xxx_npiv_get_fabric_wwn(struct se_portal_group *se_tpg)
@@ -1457,6 +1457,78 @@ static int tcm_qla2xxx_check_initiator_node_acl(
return 0;
}
+static void tcm_qla2xxx_update_sess(struct qla_tgt_sess *sess, port_id_t s_id,
+ uint16_t loop_id, bool conf_compl_supported)
+{
+ struct qla_tgt *tgt = sess->tgt;
+ struct qla_hw_data *ha = tgt->ha;
+ struct tcm_qla2xxx_lport *lport = ha->tgt.target_lport_ptr;
+ struct se_node_acl *se_nacl = sess->se_sess->se_node_acl;
+ struct tcm_qla2xxx_nacl *nacl = container_of(se_nacl,
+ struct tcm_qla2xxx_nacl, se_node_acl);
+ u32 key;
+
+
+ if (sess->loop_id != loop_id || sess->s_id.b24 != s_id.b24)
+ pr_info("Updating session %p from port %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x loop_id %d -> %d s_id %x:%x:%x -> %x:%x:%x\n",
+ sess,
+ sess->port_name[0], sess->port_name[1],
+ sess->port_name[2], sess->port_name[3],
+ sess->port_name[4], sess->port_name[5],
+ sess->port_name[6], sess->port_name[7],
+ sess->loop_id, loop_id,
+ sess->s_id.b.domain, sess->s_id.b.area, sess->s_id.b.al_pa,
+ s_id.b.domain, s_id.b.area, s_id.b.al_pa);
+
+ if (sess->loop_id != loop_id) {
+ /*
+ * Because we can shuffle loop IDs around and we
+ * update different sessions non-atomically, we might
+ * have overwritten this session's old loop ID
+ * already, and we might end up overwriting some other
+ * session that will be updated later. So we have to
+ * be extra careful and we can't warn about those things...
+ */
+ if (lport->lport_loopid_map[sess->loop_id].se_nacl == se_nacl)
+ lport->lport_loopid_map[sess->loop_id].se_nacl = NULL;
+
+ lport->lport_loopid_map[loop_id].se_nacl = se_nacl;
+
+ sess->loop_id = loop_id;
+ }
+
+ if (sess->s_id.b24 != s_id.b24) {
+ key = (((u32) sess->s_id.b.domain << 16) |
+ ((u32) sess->s_id.b.area << 8) |
+ ((u32) sess->s_id.b.al_pa));
+
+ if (btree_lookup32(&lport->lport_fcport_map, key))
+ WARN(btree_remove32(&lport->lport_fcport_map, key) != se_nacl,
+ "Found wrong se_nacl when updating s_id %x:%x:%x\n",
+ sess->s_id.b.domain, sess->s_id.b.area, sess->s_id.b.al_pa);
+ else
+ WARN(1, "No lport_fcport_map entry for s_id %x:%x:%x\n",
+ sess->s_id.b.domain, sess->s_id.b.area, sess->s_id.b.al_pa);
+
+ key = (((u32) s_id.b.domain << 16) |
+ ((u32) s_id.b.area << 8) |
+ ((u32) s_id.b.al_pa));
+
+ if (btree_lookup32(&lport->lport_fcport_map, key)) {
+ WARN(1, "Already have lport_fcport_map entry for s_id %x:%x:%x\n",
+ s_id.b.domain, s_id.b.area, s_id.b.al_pa);
+ btree_update32(&lport->lport_fcport_map, key, se_nacl);
+ } else {
+ btree_insert32(&lport->lport_fcport_map, key, se_nacl, GFP_ATOMIC);
+ }
+
+ sess->s_id = s_id;
+ nacl->nport_id = key;
+ }
+
+ sess->conf_compl_supported = conf_compl_supported;
+}
+
/*
* Calls into tcm_qla2xxx used by qla2xxx LLD I/O path.
*/
@@ -1467,6 +1539,7 @@ static struct qla_tgt_func_tmpl tcm_qla2xxx_template = {
.free_cmd = tcm_qla2xxx_free_cmd,
.free_mcmd = tcm_qla2xxx_free_mcmd,
.free_session = tcm_qla2xxx_free_session,
+ .update_sess = tcm_qla2xxx_update_sess,
.check_initiator_node_acl = tcm_qla2xxx_check_initiator_node_acl,
.find_sess_by_s_id = tcm_qla2xxx_find_sess_by_s_id,
.find_sess_by_loop_id = tcm_qla2xxx_find_sess_by_loop_id,
@@ -1534,6 +1607,7 @@ static struct se_wwn *tcm_qla2xxx_make_lport(
lport->lport_wwpn = wwpn;
tcm_qla2xxx_format_wwn(&lport->lport_name[0], TCM_QLA2XXX_NAMELEN,
wwpn);
+ sprintf(lport->lport_naa_name, "naa.%016llx", (unsigned long long) wwpn);
ret = tcm_qla2xxx_init_lport(lport);
if (ret != 0)
@@ -1601,6 +1675,7 @@ static struct se_wwn *tcm_qla2xxx_npiv_make_lport(
lport->lport_npiv_wwnn = npiv_wwnn;
tcm_qla2xxx_npiv_format_wwn(&lport->lport_npiv_name[0],
TCM_QLA2XXX_NAMELEN, npiv_wwpn, npiv_wwnn);
+ sprintf(lport->lport_naa_name, "naa.%016llx", (unsigned long long) npiv_wwpn);
/* FIXME: tcm_qla2xxx_npiv_make_lport */
ret = -ENOSYS;
diff --git a/drivers/scsi/qla2xxx/tcm_qla2xxx.h b/drivers/scsi/qla2xxx/tcm_qla2xxx.h
index 825498103352..9ba075fe9781 100644
--- a/drivers/scsi/qla2xxx/tcm_qla2xxx.h
+++ b/drivers/scsi/qla2xxx/tcm_qla2xxx.h
@@ -61,6 +61,8 @@ struct tcm_qla2xxx_lport {
u64 lport_npiv_wwnn;
/* ASCII formatted WWPN for FC Target Lport */
char lport_name[TCM_QLA2XXX_NAMELEN];
+ /* ASCII formatted naa WWPN for VPD page 83 etc */
+ char lport_naa_name[TCM_QLA2XXX_NAMELEN];
/* ASCII formatted WWPN+WWNN for NPIV FC Target Lport */
char lport_npiv_name[TCM_QLA2XXX_NPIV_NAMELEN];
/* map for fc_port pointers in 24-bit FC Port ID space */
diff --git a/drivers/spi/spi-mxs.c b/drivers/spi/spi-mxs.c
index edf1360ab09e..86dd04d6bc87 100644
--- a/drivers/spi/spi-mxs.c
+++ b/drivers/spi/spi-mxs.c
@@ -323,6 +323,7 @@ static int mxs_spi_txrx_dma(struct mxs_spi *spi, int cs,
if (!ret) {
dev_err(ssp->dev, "DMA transfer timeout\n");
ret = -ETIMEDOUT;
+ dmaengine_terminate_all(ssp->dmach);
goto err_vmalloc;
}
@@ -480,7 +481,7 @@ static int mxs_spi_transfer_one(struct spi_master *master,
first = last = 0;
}
- m->status = 0;
+ m->status = status;
spi_finalize_current_message(master);
return status;
diff --git a/drivers/target/target_core_sbc.c b/drivers/target/target_core_sbc.c
index 868f8aa04f13..a6e27d967c7b 100644
--- a/drivers/target/target_core_sbc.c
+++ b/drivers/target/target_core_sbc.c
@@ -135,6 +135,12 @@ static int sbc_emulate_verify(struct se_cmd *cmd)
return 0;
}
+static int sbc_emulate_noop(struct se_cmd *cmd)
+{
+ target_complete_cmd(cmd, GOOD);
+ return 0;
+}
+
static inline u32 sbc_get_size(struct se_cmd *cmd, u32 sectors)
{
return cmd->se_dev->se_sub_dev->se_dev_attrib.block_size * sectors;
@@ -531,6 +537,18 @@ int sbc_parse_cdb(struct se_cmd *cmd, struct spc_ops *ops)
size = 0;
cmd->execute_cmd = sbc_emulate_verify;
break;
+ case REZERO_UNIT:
+ case SEEK_6:
+ case SEEK_10:
+ /*
+ * There are still clients out there which use these old SCSI-2
+ * commands. This mainly happens when running VMs with legacy
+ * guest systems, connected via SCSI command pass-through to
+ * iSCSI targets. Make them happy and return status GOOD.
+ */
+ size = 0;
+ cmd->execute_cmd = sbc_emulate_noop;
+ break;
default:
ret = spc_parse_cdb(cmd, &size);
if (ret)
diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c
index c33baff86aa6..9097155e9ebe 100644
--- a/drivers/target/target_core_transport.c
+++ b/drivers/target/target_core_transport.c
@@ -1616,7 +1616,6 @@ static void target_complete_tmr_failure(struct work_struct *work)
se_cmd->se_tmr_req->response = TMR_LUN_DOES_NOT_EXIST;
se_cmd->se_tfo->queue_tm_rsp(se_cmd);
- transport_generic_free_cmd(se_cmd, 0);
}
/**
diff --git a/drivers/vhost/net.c b/drivers/vhost/net.c
index 072cbbadbc36..7f93f34b7f91 100644
--- a/drivers/vhost/net.c
+++ b/drivers/vhost/net.c
@@ -379,7 +379,8 @@ static void handle_rx(struct vhost_net *net)
.hdr.gso_type = VIRTIO_NET_HDR_GSO_NONE
};
size_t total_len = 0;
- int err, headcount, mergeable;
+ int err, mergeable;
+ s16 headcount;
size_t vhost_hlen, sock_hlen;
size_t vhost_len, sock_len;
/* TODO: check that we are running from vhost_worker? */
diff --git a/fs/bio.c b/fs/bio.c
index 9298c65ad9c7..b96fc6ce4855 100644
--- a/fs/bio.c
+++ b/fs/bio.c
@@ -75,6 +75,7 @@ static struct kmem_cache *bio_find_or_create_slab(unsigned int extra_size)
unsigned int sz = sizeof(struct bio) + extra_size;
struct kmem_cache *slab = NULL;
struct bio_slab *bslab, *new_bio_slabs;
+ unsigned int new_bio_slab_max;
unsigned int i, entry = -1;
mutex_lock(&bio_slab_lock);
@@ -97,12 +98,13 @@ static struct kmem_cache *bio_find_or_create_slab(unsigned int extra_size)
goto out_unlock;
if (bio_slab_nr == bio_slab_max && entry == -1) {
- bio_slab_max <<= 1;
+ new_bio_slab_max = bio_slab_max << 1;
new_bio_slabs = krealloc(bio_slabs,
- bio_slab_max * sizeof(struct bio_slab),
+ new_bio_slab_max * sizeof(struct bio_slab),
GFP_KERNEL);
if (!new_bio_slabs)
goto out_unlock;
+ bio_slab_max = new_bio_slab_max;
bio_slabs = new_bio_slabs;
}
if (entry == -1)
diff --git a/fs/block_dev.c b/fs/block_dev.c
index b3c1d3dae77d..1a1e5e3b1eaf 100644
--- a/fs/block_dev.c
+++ b/fs/block_dev.c
@@ -1661,6 +1661,39 @@ static int blkdev_mmap(struct file *file, struct vm_area_struct *vma)
return ret;
}
+static ssize_t blkdev_splice_read(struct file *file, loff_t *ppos,
+ struct pipe_inode_info *pipe, size_t len,
+ unsigned int flags)
+{
+ ssize_t ret;
+ struct block_device *bdev = I_BDEV(file->f_mapping->host);
+
+ percpu_down_read(&bdev->bd_block_size_semaphore);
+
+ ret = generic_file_splice_read(file, ppos, pipe, len, flags);
+
+ percpu_up_read(&bdev->bd_block_size_semaphore);
+
+ return ret;
+}
+
+static ssize_t blkdev_splice_write(struct pipe_inode_info *pipe,
+ struct file *file, loff_t *ppos, size_t len,
+ unsigned int flags)
+{
+ ssize_t ret;
+ struct block_device *bdev = I_BDEV(file->f_mapping->host);
+
+ percpu_down_read(&bdev->bd_block_size_semaphore);
+
+ ret = generic_file_splice_write(pipe, file, ppos, len, flags);
+
+ percpu_up_read(&bdev->bd_block_size_semaphore);
+
+ return ret;
+}
+
+
/*
* Try to release a page associated with block device when the system
* is under memory pressure.
@@ -1699,8 +1732,8 @@ const struct file_operations def_blk_fops = {
#ifdef CONFIG_COMPAT
.compat_ioctl = compat_blkdev_ioctl,
#endif
- .splice_read = generic_file_splice_read,
- .splice_write = generic_file_splice_write,
+ .splice_read = blkdev_splice_read,
+ .splice_write = blkdev_splice_write,
};
int ioctl_by_bdev(struct block_device *bdev, unsigned cmd, unsigned long arg)
diff --git a/fs/ceph/export.c b/fs/ceph/export.c
index 02ce90972d81..9349bb37a2fe 100644
--- a/fs/ceph/export.c
+++ b/fs/ceph/export.c
@@ -90,6 +90,8 @@ static int ceph_encode_fh(struct inode *inode, u32 *rawfh, int *max_len,
*max_len = handle_length;
type = 255;
}
+ if (dentry)
+ dput(dentry);
return type;
}
diff --git a/fs/exec.c b/fs/exec.c
index 8b9011b67041..0039055b1fc6 100644
--- a/fs/exec.c
+++ b/fs/exec.c
@@ -1083,7 +1083,8 @@ int flush_old_exec(struct linux_binprm * bprm)
bprm->mm = NULL; /* We're using it now */
set_fs(USER_DS);
- current->flags &= ~(PF_RANDOMIZE | PF_FORKNOEXEC | PF_KTHREAD);
+ current->flags &=
+ ~(PF_RANDOMIZE | PF_FORKNOEXEC | PF_KTHREAD | PF_NOFREEZE);
flush_thread();
current->personality &= ~bprm->per_clear;
diff --git a/fs/ext4/ialloc.c b/fs/ext4/ialloc.c
index 4facdd29a350..3a100e7a62a8 100644
--- a/fs/ext4/ialloc.c
+++ b/fs/ext4/ialloc.c
@@ -725,6 +725,10 @@ repeat_in_this_group:
"inode=%lu", ino + 1);
continue;
}
+ BUFFER_TRACE(inode_bitmap_bh, "get_write_access");
+ err = ext4_journal_get_write_access(handle, inode_bitmap_bh);
+ if (err)
+ goto fail;
ext4_lock_group(sb, group);
ret2 = ext4_test_and_set_bit(ino, inode_bitmap_bh->b_data);
ext4_unlock_group(sb, group);
@@ -738,6 +742,11 @@ repeat_in_this_group:
goto out;
got:
+ BUFFER_TRACE(inode_bitmap_bh, "call ext4_handle_dirty_metadata");
+ err = ext4_handle_dirty_metadata(handle, NULL, inode_bitmap_bh);
+ if (err)
+ goto fail;
+
/* We may have to initialize the block bitmap if it isn't already */
if (ext4_has_group_desc_csum(sb) &&
gdp->bg_flags & cpu_to_le16(EXT4_BG_BLOCK_UNINIT)) {
@@ -771,11 +780,6 @@ got:
goto fail;
}
- BUFFER_TRACE(inode_bitmap_bh, "get_write_access");
- err = ext4_journal_get_write_access(handle, inode_bitmap_bh);
- if (err)
- goto fail;
-
BUFFER_TRACE(group_desc_bh, "get_write_access");
err = ext4_journal_get_write_access(handle, group_desc_bh);
if (err)
@@ -823,11 +827,6 @@ got:
}
ext4_unlock_group(sb, group);
- BUFFER_TRACE(inode_bitmap_bh, "call ext4_handle_dirty_metadata");
- err = ext4_handle_dirty_metadata(handle, NULL, inode_bitmap_bh);
- if (err)
- goto fail;
-
BUFFER_TRACE(group_desc_bh, "call ext4_handle_dirty_metadata");
err = ext4_handle_dirty_metadata(handle, NULL, group_desc_bh);
if (err)
diff --git a/fs/file.c b/fs/file.c
index d3b5fa80b71b..708d997a7748 100644
--- a/fs/file.c
+++ b/fs/file.c
@@ -900,7 +900,7 @@ int replace_fd(unsigned fd, struct file *file, unsigned flags)
return __close_fd(files, fd);
if (fd >= rlimit(RLIMIT_NOFILE))
- return -EMFILE;
+ return -EBADF;
spin_lock(&files->file_lock);
err = expand_files(files, fd);
@@ -926,7 +926,7 @@ SYSCALL_DEFINE3(dup3, unsigned int, oldfd, unsigned int, newfd, int, flags)
return -EINVAL;
if (newfd >= rlimit(RLIMIT_NOFILE))
- return -EMFILE;
+ return -EBADF;
spin_lock(&files->file_lock);
err = expand_files(files, newfd);
diff --git a/include/linux/compat.h b/include/linux/compat.h
index d0ced1011f2f..d2db71077d93 100644
--- a/include/linux/compat.h
+++ b/include/linux/compat.h
@@ -286,10 +286,8 @@ asmlinkage ssize_t compat_sys_pwritev(unsigned long fd,
int compat_do_execve(const char *filename, const compat_uptr_t __user *argv,
const compat_uptr_t __user *envp, struct pt_regs *regs);
-#ifdef __ARCH_WANT_SYS_EXECVE
asmlinkage long compat_sys_execve(const char __user *filename, const compat_uptr_t __user *argv,
const compat_uptr_t __user *envp);
-#endif
asmlinkage long compat_sys_select(int n, compat_ulong_t __user *inp,
compat_ulong_t __user *outp, compat_ulong_t __user *exp,
diff --git a/include/linux/kvm_host.h b/include/linux/kvm_host.h
index 93bfc9f9815c..ecc554374e44 100644
--- a/include/linux/kvm_host.h
+++ b/include/linux/kvm_host.h
@@ -42,19 +42,8 @@
*/
#define KVM_MEMSLOT_INVALID (1UL << 16)
-/*
- * If we support unaligned MMIO, at most one fragment will be split into two:
- */
-#ifdef KVM_UNALIGNED_MMIO
-# define KVM_EXTRA_MMIO_FRAGMENTS 1
-#else
-# define KVM_EXTRA_MMIO_FRAGMENTS 0
-#endif
-
-#define KVM_USER_MMIO_SIZE 8
-
-#define KVM_MAX_MMIO_FRAGMENTS \
- (KVM_MMIO_SIZE / KVM_USER_MMIO_SIZE + KVM_EXTRA_MMIO_FRAGMENTS)
+/* Two fragments for cross MMIO pages. */
+#define KVM_MAX_MMIO_FRAGMENTS 2
/*
* For the normal pfn, the highest 12 bits should be zero,
diff --git a/include/linux/percpu-rwsem.h b/include/linux/percpu-rwsem.h
index cf80f7e5277f..250a4acddb2b 100644
--- a/include/linux/percpu-rwsem.h
+++ b/include/linux/percpu-rwsem.h
@@ -12,34 +12,27 @@ struct percpu_rw_semaphore {
struct mutex mtx;
};
+#define light_mb() barrier()
+#define heavy_mb() synchronize_sched()
+
static inline void percpu_down_read(struct percpu_rw_semaphore *p)
{
- rcu_read_lock();
+ rcu_read_lock_sched();
if (unlikely(p->locked)) {
- rcu_read_unlock();
+ rcu_read_unlock_sched();
mutex_lock(&p->mtx);
this_cpu_inc(*p->counters);
mutex_unlock(&p->mtx);
return;
}
this_cpu_inc(*p->counters);
- rcu_read_unlock();
+ rcu_read_unlock_sched();
+ light_mb(); /* A, between read of p->locked and read of data, paired with D */
}
static inline void percpu_up_read(struct percpu_rw_semaphore *p)
{
- /*
- * On X86, write operation in this_cpu_dec serves as a memory unlock
- * barrier (i.e. memory accesses may be moved before the write, but
- * no memory accesses are moved past the write).
- * On other architectures this may not be the case, so we need smp_mb()
- * there.
- */
-#if defined(CONFIG_X86) && (!defined(CONFIG_X86_PPRO_FENCE) && !defined(CONFIG_X86_OOSTORE))
- barrier();
-#else
- smp_mb();
-#endif
+ light_mb(); /* B, between read of the data and write to p->counter, paired with C */
this_cpu_dec(*p->counters);
}
@@ -58,14 +51,15 @@ static inline void percpu_down_write(struct percpu_rw_semaphore *p)
{
mutex_lock(&p->mtx);
p->locked = true;
- synchronize_rcu();
+ synchronize_sched(); /* make sure that all readers exit the rcu_read_lock_sched region */
while (__percpu_count(p->counters))
msleep(1);
- smp_rmb(); /* paired with smp_mb() in percpu_sem_up_read() */
+ heavy_mb(); /* C, between read of p->counter and write to data, paired with B */
}
static inline void percpu_up_write(struct percpu_rw_semaphore *p)
{
+ heavy_mb(); /* D, between write to data and write to p->locked, paired with A */
p->locked = false;
mutex_unlock(&p->mtx);
}
diff --git a/include/linux/raid/Kbuild b/include/linux/raid/Kbuild
index 2415a64c5e51..e69de29bb2d1 100644
--- a/include/linux/raid/Kbuild
+++ b/include/linux/raid/Kbuild
@@ -1,2 +0,0 @@
-header-y += md_p.h
-header-y += md_u.h
diff --git a/include/linux/raid/md_u.h b/include/linux/raid/md_u.h
index fb1abb3367e9..358c04bfbe2a 100644
--- a/include/linux/raid/md_u.h
+++ b/include/linux/raid/md_u.h
@@ -11,149 +11,10 @@
(for example /usr/src/linux/COPYING); if not, write to the Free
Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
-
#ifndef _MD_U_H
#define _MD_U_H
-/*
- * Different major versions are not compatible.
- * Different minor versions are only downward compatible.
- * Different patchlevel versions are downward and upward compatible.
- */
-#define MD_MAJOR_VERSION 0
-#define MD_MINOR_VERSION 90
-/*
- * MD_PATCHLEVEL_VERSION indicates kernel functionality.
- * >=1 means different superblock formats are selectable using SET_ARRAY_INFO
- * and major_version/minor_version accordingly
- * >=2 means that Internal bitmaps are supported by setting MD_SB_BITMAP_PRESENT
- * in the super status byte
- * >=3 means that bitmap superblock version 4 is supported, which uses
- * little-ending representation rather than host-endian
- */
-#define MD_PATCHLEVEL_VERSION 3
-
-/* ioctls */
-
-/* status */
-#define RAID_VERSION _IOR (MD_MAJOR, 0x10, mdu_version_t)
-#define GET_ARRAY_INFO _IOR (MD_MAJOR, 0x11, mdu_array_info_t)
-#define GET_DISK_INFO _IOR (MD_MAJOR, 0x12, mdu_disk_info_t)
-#define PRINT_RAID_DEBUG _IO (MD_MAJOR, 0x13)
-#define RAID_AUTORUN _IO (MD_MAJOR, 0x14)
-#define GET_BITMAP_FILE _IOR (MD_MAJOR, 0x15, mdu_bitmap_file_t)
-
-/* configuration */
-#define CLEAR_ARRAY _IO (MD_MAJOR, 0x20)
-#define ADD_NEW_DISK _IOW (MD_MAJOR, 0x21, mdu_disk_info_t)
-#define HOT_REMOVE_DISK _IO (MD_MAJOR, 0x22)
-#define SET_ARRAY_INFO _IOW (MD_MAJOR, 0x23, mdu_array_info_t)
-#define SET_DISK_INFO _IO (MD_MAJOR, 0x24)
-#define WRITE_RAID_INFO _IO (MD_MAJOR, 0x25)
-#define UNPROTECT_ARRAY _IO (MD_MAJOR, 0x26)
-#define PROTECT_ARRAY _IO (MD_MAJOR, 0x27)
-#define HOT_ADD_DISK _IO (MD_MAJOR, 0x28)
-#define SET_DISK_FAULTY _IO (MD_MAJOR, 0x29)
-#define HOT_GENERATE_ERROR _IO (MD_MAJOR, 0x2a)
-#define SET_BITMAP_FILE _IOW (MD_MAJOR, 0x2b, int)
+#include <uapi/linux/raid/md_u.h>
-/* usage */
-#define RUN_ARRAY _IOW (MD_MAJOR, 0x30, mdu_param_t)
-/* 0x31 was START_ARRAY */
-#define STOP_ARRAY _IO (MD_MAJOR, 0x32)
-#define STOP_ARRAY_RO _IO (MD_MAJOR, 0x33)
-#define RESTART_ARRAY_RW _IO (MD_MAJOR, 0x34)
-
-/* 63 partitions with the alternate major number (mdp) */
-#define MdpMinorShift 6
-#ifdef __KERNEL__
extern int mdp_major;
-#endif
-
-typedef struct mdu_version_s {
- int major;
- int minor;
- int patchlevel;
-} mdu_version_t;
-
-typedef struct mdu_array_info_s {
- /*
- * Generic constant information
- */
- int major_version;
- int minor_version;
- int patch_version;
- int ctime;
- int level;
- int size;
- int nr_disks;
- int raid_disks;
- int md_minor;
- int not_persistent;
-
- /*
- * Generic state information
- */
- int utime; /* 0 Superblock update time */
- int state; /* 1 State bits (clean, ...) */
- int active_disks; /* 2 Number of currently active disks */
- int working_disks; /* 3 Number of working disks */
- int failed_disks; /* 4 Number of failed disks */
- int spare_disks; /* 5 Number of spare disks */
-
- /*
- * Personality information
- */
- int layout; /* 0 the array's physical layout */
- int chunk_size; /* 1 chunk size in bytes */
-
-} mdu_array_info_t;
-
-/* non-obvious values for 'level' */
-#define LEVEL_MULTIPATH (-4)
-#define LEVEL_LINEAR (-1)
-#define LEVEL_FAULTY (-5)
-
-/* we need a value for 'no level specified' and 0
- * means 'raid0', so we need something else. This is
- * for internal use only
- */
-#define LEVEL_NONE (-1000000)
-
-typedef struct mdu_disk_info_s {
- /*
- * configuration/status of one particular disk
- */
- int number;
- int major;
- int minor;
- int raid_disk;
- int state;
-
-} mdu_disk_info_t;
-
-typedef struct mdu_start_info_s {
- /*
- * configuration/status of one particular disk
- */
- int major;
- int minor;
- int raid_disk;
- int state;
-
-} mdu_start_info_t;
-
-typedef struct mdu_bitmap_file_s
-{
- char pathname[4096];
-} mdu_bitmap_file_t;
-
-typedef struct mdu_param_s
-{
- int personality; /* 1,2,3,4 */
- int chunk_size; /* in bytes */
- int max_fault; /* unused for now */
-} mdu_param_t;
-
#endif
-
diff --git a/include/linux/tcp.h b/include/linux/tcp.h
index 8a7fc4be2d75..60b7aac15e0e 100644
--- a/include/linux/tcp.h
+++ b/include/linux/tcp.h
@@ -191,7 +191,8 @@ struct tcp_sock {
u8 do_early_retrans:1,/* Enable RFC5827 early-retransmit */
early_retrans_delayed:1, /* Delayed ER timer installed */
syn_data:1, /* SYN includes data */
- syn_fastopen:1; /* SYN includes Fast Open option */
+ syn_fastopen:1, /* SYN includes Fast Open option */
+ syn_data_acked:1;/* data in SYN is acked by SYN-ACK */
/* RTT measurement */
u32 srtt; /* smoothed round trip time << 3 */
diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index 1b4989082244..f8cd4cf3fad8 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -1218,6 +1218,7 @@ struct cfg80211_deauth_request {
const u8 *ie;
size_t ie_len;
u16 reason_code;
+ bool local_state_change;
};
/**
diff --git a/include/sound/core.h b/include/sound/core.h
index bc056687f647..93896ad1fcdd 100644
--- a/include/sound/core.h
+++ b/include/sound/core.h
@@ -132,6 +132,7 @@ struct snd_card {
int shutdown; /* this card is going down */
int free_on_last_close; /* free in context of file_release */
wait_queue_head_t shutdown_sleep;
+ atomic_t refcount; /* refcount for disconnection */
struct device *dev; /* device assigned to this card */
struct device *card_dev; /* cardX object for sysfs */
@@ -189,6 +190,7 @@ struct snd_minor {
const struct file_operations *f_ops; /* file operations */
void *private_data; /* private data for f_ops->open */
struct device *dev; /* device for sysfs */
+ struct snd_card *card_ptr; /* assigned card instance */
};
/* return a device pointer linked to each sound device as a parent */
@@ -295,6 +297,7 @@ int snd_card_info_done(void);
int snd_component_add(struct snd_card *card, const char *component);
int snd_card_file_add(struct snd_card *card, struct file *file);
int snd_card_file_remove(struct snd_card *card, struct file *file);
+void snd_card_unref(struct snd_card *card);
#define snd_card_set_dev(card, devptr) ((card)->dev = (devptr))
diff --git a/include/uapi/linux/raid/Kbuild b/include/uapi/linux/raid/Kbuild
index aafaa5aa54d4..e2c3d25405d7 100644
--- a/include/uapi/linux/raid/Kbuild
+++ b/include/uapi/linux/raid/Kbuild
@@ -1 +1,3 @@
# UAPI Header export list
+header-y += md_p.h
+header-y += md_u.h
diff --git a/include/linux/raid/md_p.h b/include/uapi/linux/raid/md_p.h
index ee753536ab70..ee753536ab70 100644
--- a/include/linux/raid/md_p.h
+++ b/include/uapi/linux/raid/md_p.h
diff --git a/include/uapi/linux/raid/md_u.h b/include/uapi/linux/raid/md_u.h
new file mode 100644
index 000000000000..4133e744e4e6
--- /dev/null
+++ b/include/uapi/linux/raid/md_u.h
@@ -0,0 +1,155 @@
+/*
+ md_u.h : user <=> kernel API between Linux raidtools and RAID drivers
+ Copyright (C) 1998 Ingo Molnar
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ You should have received a copy of the GNU General Public License
+ (for example /usr/src/linux/COPYING); if not, write to the Free
+ Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#ifndef _UAPI_MD_U_H
+#define _UAPI_MD_U_H
+
+/*
+ * Different major versions are not compatible.
+ * Different minor versions are only downward compatible.
+ * Different patchlevel versions are downward and upward compatible.
+ */
+#define MD_MAJOR_VERSION 0
+#define MD_MINOR_VERSION 90
+/*
+ * MD_PATCHLEVEL_VERSION indicates kernel functionality.
+ * >=1 means different superblock formats are selectable using SET_ARRAY_INFO
+ * and major_version/minor_version accordingly
+ * >=2 means that Internal bitmaps are supported by setting MD_SB_BITMAP_PRESENT
+ * in the super status byte
+ * >=3 means that bitmap superblock version 4 is supported, which uses
+ * little-ending representation rather than host-endian
+ */
+#define MD_PATCHLEVEL_VERSION 3
+
+/* ioctls */
+
+/* status */
+#define RAID_VERSION _IOR (MD_MAJOR, 0x10, mdu_version_t)
+#define GET_ARRAY_INFO _IOR (MD_MAJOR, 0x11, mdu_array_info_t)
+#define GET_DISK_INFO _IOR (MD_MAJOR, 0x12, mdu_disk_info_t)
+#define PRINT_RAID_DEBUG _IO (MD_MAJOR, 0x13)
+#define RAID_AUTORUN _IO (MD_MAJOR, 0x14)
+#define GET_BITMAP_FILE _IOR (MD_MAJOR, 0x15, mdu_bitmap_file_t)
+
+/* configuration */
+#define CLEAR_ARRAY _IO (MD_MAJOR, 0x20)
+#define ADD_NEW_DISK _IOW (MD_MAJOR, 0x21, mdu_disk_info_t)
+#define HOT_REMOVE_DISK _IO (MD_MAJOR, 0x22)
+#define SET_ARRAY_INFO _IOW (MD_MAJOR, 0x23, mdu_array_info_t)
+#define SET_DISK_INFO _IO (MD_MAJOR, 0x24)
+#define WRITE_RAID_INFO _IO (MD_MAJOR, 0x25)
+#define UNPROTECT_ARRAY _IO (MD_MAJOR, 0x26)
+#define PROTECT_ARRAY _IO (MD_MAJOR, 0x27)
+#define HOT_ADD_DISK _IO (MD_MAJOR, 0x28)
+#define SET_DISK_FAULTY _IO (MD_MAJOR, 0x29)
+#define HOT_GENERATE_ERROR _IO (MD_MAJOR, 0x2a)
+#define SET_BITMAP_FILE _IOW (MD_MAJOR, 0x2b, int)
+
+/* usage */
+#define RUN_ARRAY _IOW (MD_MAJOR, 0x30, mdu_param_t)
+/* 0x31 was START_ARRAY */
+#define STOP_ARRAY _IO (MD_MAJOR, 0x32)
+#define STOP_ARRAY_RO _IO (MD_MAJOR, 0x33)
+#define RESTART_ARRAY_RW _IO (MD_MAJOR, 0x34)
+
+/* 63 partitions with the alternate major number (mdp) */
+#define MdpMinorShift 6
+
+typedef struct mdu_version_s {
+ int major;
+ int minor;
+ int patchlevel;
+} mdu_version_t;
+
+typedef struct mdu_array_info_s {
+ /*
+ * Generic constant information
+ */
+ int major_version;
+ int minor_version;
+ int patch_version;
+ int ctime;
+ int level;
+ int size;
+ int nr_disks;
+ int raid_disks;
+ int md_minor;
+ int not_persistent;
+
+ /*
+ * Generic state information
+ */
+ int utime; /* 0 Superblock update time */
+ int state; /* 1 State bits (clean, ...) */
+ int active_disks; /* 2 Number of currently active disks */
+ int working_disks; /* 3 Number of working disks */
+ int failed_disks; /* 4 Number of failed disks */
+ int spare_disks; /* 5 Number of spare disks */
+
+ /*
+ * Personality information
+ */
+ int layout; /* 0 the array's physical layout */
+ int chunk_size; /* 1 chunk size in bytes */
+
+} mdu_array_info_t;
+
+/* non-obvious values for 'level' */
+#define LEVEL_MULTIPATH (-4)
+#define LEVEL_LINEAR (-1)
+#define LEVEL_FAULTY (-5)
+
+/* we need a value for 'no level specified' and 0
+ * means 'raid0', so we need something else. This is
+ * for internal use only
+ */
+#define LEVEL_NONE (-1000000)
+
+typedef struct mdu_disk_info_s {
+ /*
+ * configuration/status of one particular disk
+ */
+ int number;
+ int major;
+ int minor;
+ int raid_disk;
+ int state;
+
+} mdu_disk_info_t;
+
+typedef struct mdu_start_info_s {
+ /*
+ * configuration/status of one particular disk
+ */
+ int major;
+ int minor;
+ int raid_disk;
+ int state;
+
+} mdu_start_info_t;
+
+typedef struct mdu_bitmap_file_s
+{
+ char pathname[4096];
+} mdu_bitmap_file_t;
+
+typedef struct mdu_param_s
+{
+ int personality; /* 1,2,3,4 */
+ int chunk_size; /* in bytes */
+ int max_fault; /* unused for now */
+} mdu_param_t;
+
+#endif /* _UAPI_MD_U_H */
diff --git a/include/uapi/linux/tcp.h b/include/uapi/linux/tcp.h
index c4b89a5cb7df..e962faa5ab0d 100644
--- a/include/uapi/linux/tcp.h
+++ b/include/uapi/linux/tcp.h
@@ -130,6 +130,7 @@ enum {
#define TCPI_OPT_WSCALE 4
#define TCPI_OPT_ECN 8 /* ECN was negociated at TCP session init */
#define TCPI_OPT_ECN_SEEN 16 /* we received at least one packet with ECT */
+#define TCPI_OPT_SYN_DATA 32 /* SYN-ACK acked data in SYN sent or rcvd */
enum tcp_ca_state {
TCP_CA_Open = 0,
diff --git a/init/main.c b/init/main.c
index 9cf77ab138a6..e33e09df3cbc 100644
--- a/init/main.c
+++ b/init/main.c
@@ -442,9 +442,11 @@ void __init __weak smp_setup_processor_id(void)
{
}
+# if THREAD_SIZE >= PAGE_SIZE
void __init __weak thread_info_cache_init(void)
{
}
+#endif
/*
* Set up kernel memory allocators
diff --git a/net/8021q/vlan.c b/net/8021q/vlan.c
index 9096bcb08132..ee070722a3a3 100644
--- a/net/8021q/vlan.c
+++ b/net/8021q/vlan.c
@@ -463,7 +463,9 @@ static int vlan_device_event(struct notifier_block *unused, unsigned long event,
case NETDEV_PRE_TYPE_CHANGE:
/* Forbid underlaying device to change its type. */
- return NOTIFY_BAD;
+ if (vlan_uses_dev(dev))
+ return NOTIFY_BAD;
+ break;
case NETDEV_NOTIFY_PEERS:
case NETDEV_BONDING_FAILOVER:
diff --git a/net/batman-adv/bridge_loop_avoidance.c b/net/batman-adv/bridge_loop_avoidance.c
index 0a9084ad19a6..fd8d5afec0dd 100644
--- a/net/batman-adv/bridge_loop_avoidance.c
+++ b/net/batman-adv/bridge_loop_avoidance.c
@@ -1167,6 +1167,8 @@ int batadv_bla_init(struct batadv_priv *bat_priv)
uint16_t crc;
unsigned long entrytime;
+ spin_lock_init(&bat_priv->bla.bcast_duplist_lock);
+
batadv_dbg(BATADV_DBG_BLA, bat_priv, "bla hash registering\n");
/* setting claim destination address */
@@ -1210,8 +1212,8 @@ int batadv_bla_init(struct batadv_priv *bat_priv)
/**
* batadv_bla_check_bcast_duplist
* @bat_priv: the bat priv with all the soft interface information
- * @bcast_packet: originator mac address
- * @hdr_size: maximum length of the frame
+ * @bcast_packet: encapsulated broadcast frame plus batman header
+ * @bcast_packet_len: length of encapsulated broadcast frame plus batman header
*
* check if it is on our broadcast list. Another gateway might
* have sent the same packet because it is connected to the same backbone,
@@ -1224,20 +1226,22 @@ int batadv_bla_init(struct batadv_priv *bat_priv)
*/
int batadv_bla_check_bcast_duplist(struct batadv_priv *bat_priv,
struct batadv_bcast_packet *bcast_packet,
- int hdr_size)
+ int bcast_packet_len)
{
- int i, length, curr;
+ int i, length, curr, ret = 0;
uint8_t *content;
uint16_t crc;
struct batadv_bcast_duplist_entry *entry;
- length = hdr_size - sizeof(*bcast_packet);
+ length = bcast_packet_len - sizeof(*bcast_packet);
content = (uint8_t *)bcast_packet;
content += sizeof(*bcast_packet);
/* calculate the crc ... */
crc = crc16(0, content, length);
+ spin_lock_bh(&bat_priv->bla.bcast_duplist_lock);
+
for (i = 0; i < BATADV_DUPLIST_SIZE; i++) {
curr = (bat_priv->bla.bcast_duplist_curr + i);
curr %= BATADV_DUPLIST_SIZE;
@@ -1259,9 +1263,12 @@ int batadv_bla_check_bcast_duplist(struct batadv_priv *bat_priv,
/* this entry seems to match: same crc, not too old,
* and from another gw. therefore return 1 to forbid it.
*/
- return 1;
+ ret = 1;
+ goto out;
}
- /* not found, add a new entry (overwrite the oldest entry) */
+ /* not found, add a new entry (overwrite the oldest entry)
+ * and allow it, its the first occurence.
+ */
curr = (bat_priv->bla.bcast_duplist_curr + BATADV_DUPLIST_SIZE - 1);
curr %= BATADV_DUPLIST_SIZE;
entry = &bat_priv->bla.bcast_duplist[curr];
@@ -1270,8 +1277,10 @@ int batadv_bla_check_bcast_duplist(struct batadv_priv *bat_priv,
memcpy(entry->orig, bcast_packet->orig, ETH_ALEN);
bat_priv->bla.bcast_duplist_curr = curr;
- /* allow it, its the first occurence. */
- return 0;
+out:
+ spin_unlock_bh(&bat_priv->bla.bcast_duplist_lock);
+
+ return ret;
}
diff --git a/net/batman-adv/routing.c b/net/batman-adv/routing.c
index 939fc01371df..376b4cc6ca82 100644
--- a/net/batman-adv/routing.c
+++ b/net/batman-adv/routing.c
@@ -1124,8 +1124,14 @@ int batadv_recv_bcast_packet(struct sk_buff *skb,
spin_unlock_bh(&orig_node->bcast_seqno_lock);
+ /* keep skb linear for crc calculation */
+ if (skb_linearize(skb) < 0)
+ goto out;
+
+ bcast_packet = (struct batadv_bcast_packet *)skb->data;
+
/* check whether this has been sent by another originator before */
- if (batadv_bla_check_bcast_duplist(bat_priv, bcast_packet, hdr_size))
+ if (batadv_bla_check_bcast_duplist(bat_priv, bcast_packet, skb->len))
goto out;
/* rebroadcast packet */
diff --git a/net/batman-adv/types.h b/net/batman-adv/types.h
index 2ed82caacdca..ac1e07a80454 100644
--- a/net/batman-adv/types.h
+++ b/net/batman-adv/types.h
@@ -205,6 +205,8 @@ struct batadv_priv_bla {
struct batadv_hashtable *backbone_hash;
struct batadv_bcast_duplist_entry bcast_duplist[BATADV_DUPLIST_SIZE];
int bcast_duplist_curr;
+ /* protects bcast_duplist and bcast_duplist_curr */
+ spinlock_t bcast_duplist_lock;
struct batadv_bla_claim_dst claim_dest;
struct delayed_work work;
};
diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c
index 8c225ef349cd..2ac8d50861e0 100644
--- a/net/bluetooth/smp.c
+++ b/net/bluetooth/smp.c
@@ -32,6 +32,8 @@
#define SMP_TIMEOUT msecs_to_jiffies(30000)
+#define AUTH_REQ_MASK 0x07
+
static inline void swap128(u8 src[16], u8 dst[16])
{
int i;
@@ -230,7 +232,7 @@ static void build_pairing_cmd(struct l2cap_conn *conn,
req->max_key_size = SMP_MAX_ENC_KEY_SIZE;
req->init_key_dist = 0;
req->resp_key_dist = dist_keys;
- req->auth_req = authreq;
+ req->auth_req = (authreq & AUTH_REQ_MASK);
return;
}
@@ -239,7 +241,7 @@ static void build_pairing_cmd(struct l2cap_conn *conn,
rsp->max_key_size = SMP_MAX_ENC_KEY_SIZE;
rsp->init_key_dist = 0;
rsp->resp_key_dist = req->resp_key_dist & dist_keys;
- rsp->auth_req = authreq;
+ rsp->auth_req = (authreq & AUTH_REQ_MASK);
}
static u8 check_enc_key_size(struct l2cap_conn *conn, __u8 max_key_size)
diff --git a/net/ceph/messenger.c b/net/ceph/messenger.c
index 159aa8bef9e7..3ef1759403b4 100644
--- a/net/ceph/messenger.c
+++ b/net/ceph/messenger.c
@@ -2300,10 +2300,11 @@ restart:
mutex_unlock(&con->mutex);
return;
} else {
- con->ops->put(con);
dout("con_work %p FAILED to back off %lu\n", con,
con->delay);
+ set_bit(CON_FLAG_BACKOFF, &con->flags);
}
+ goto done;
}
if (con->state == CON_STATE_STANDBY) {
@@ -2749,7 +2750,8 @@ static int ceph_con_in_msg_alloc(struct ceph_connection *con, int *skip)
msg = con->ops->alloc_msg(con, hdr, skip);
mutex_lock(&con->mutex);
if (con->state != CON_STATE_OPEN) {
- ceph_msg_put(msg);
+ if (msg)
+ ceph_msg_put(msg);
return -EAGAIN;
}
con->in_msg = msg;
diff --git a/net/core/skbuff.c b/net/core/skbuff.c
index 6e04b1fa11f2..4007c1437fda 100644
--- a/net/core/skbuff.c
+++ b/net/core/skbuff.c
@@ -3379,10 +3379,12 @@ EXPORT_SYMBOL(__skb_warn_lro_forwarding);
void kfree_skb_partial(struct sk_buff *skb, bool head_stolen)
{
- if (head_stolen)
+ if (head_stolen) {
+ skb_release_head_state(skb);
kmem_cache_free(skbuff_head_cache, skb);
- else
+ } else {
__kfree_skb(skb);
+ }
}
EXPORT_SYMBOL(kfree_skb_partial);
diff --git a/net/ipv4/route.c b/net/ipv4/route.c
index 432f4bb77238..a8c651216fa6 100644
--- a/net/ipv4/route.c
+++ b/net/ipv4/route.c
@@ -1163,8 +1163,12 @@ static bool rt_bind_exception(struct rtable *rt, struct fib_nh_exception *fnhe,
spin_lock_bh(&fnhe_lock);
if (daddr == fnhe->fnhe_daddr) {
- struct rtable *orig;
-
+ struct rtable *orig = rcu_dereference(fnhe->fnhe_rth);
+ if (orig && rt_is_expired(orig)) {
+ fnhe->fnhe_gw = 0;
+ fnhe->fnhe_pmtu = 0;
+ fnhe->fnhe_expires = 0;
+ }
if (fnhe->fnhe_pmtu) {
unsigned long expires = fnhe->fnhe_expires;
unsigned long diff = expires - jiffies;
@@ -1181,7 +1185,6 @@ static bool rt_bind_exception(struct rtable *rt, struct fib_nh_exception *fnhe,
} else if (!rt->rt_gateway)
rt->rt_gateway = daddr;
- orig = rcu_dereference(fnhe->fnhe_rth);
rcu_assign_pointer(fnhe->fnhe_rth, rt);
if (orig)
rt_free(orig);
diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c
index f32c02e2a543..197c0008503c 100644
--- a/net/ipv4/tcp.c
+++ b/net/ipv4/tcp.c
@@ -549,14 +549,12 @@ int tcp_ioctl(struct sock *sk, int cmd, unsigned long arg)
!tp->urg_data ||
before(tp->urg_seq, tp->copied_seq) ||
!before(tp->urg_seq, tp->rcv_nxt)) {
- struct sk_buff *skb;
answ = tp->rcv_nxt - tp->copied_seq;
- /* Subtract 1, if FIN is in queue. */
- skb = skb_peek_tail(&sk->sk_receive_queue);
- if (answ && skb)
- answ -= tcp_hdr(skb)->fin;
+ /* Subtract 1, if FIN was received */
+ if (answ && sock_flag(sk, SOCK_DONE))
+ answ--;
} else
answ = tp->urg_seq - tp->copied_seq;
release_sock(sk);
@@ -2766,6 +2764,8 @@ void tcp_get_info(const struct sock *sk, struct tcp_info *info)
info->tcpi_options |= TCPI_OPT_ECN;
if (tp->ecn_flags & TCP_ECN_SEEN)
info->tcpi_options |= TCPI_OPT_ECN_SEEN;
+ if (tp->syn_data_acked)
+ info->tcpi_options |= TCPI_OPT_SYN_DATA;
info->tcpi_rto = jiffies_to_usecs(icsk->icsk_rto);
info->tcpi_ato = jiffies_to_usecs(icsk->icsk_ack.ato);
diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c
index 432c36649db3..1db663983587 100644
--- a/net/ipv4/tcp_input.c
+++ b/net/ipv4/tcp_input.c
@@ -5646,6 +5646,7 @@ static bool tcp_rcv_fastopen_synack(struct sock *sk, struct sk_buff *synack,
tcp_rearm_rto(sk);
return true;
}
+ tp->syn_data_acked = tp->syn_data;
return false;
}
@@ -5963,7 +5964,7 @@ int tcp_rcv_state_process(struct sock *sk, struct sk_buff *skb,
req = tp->fastopen_rsk;
if (req != NULL) {
- BUG_ON(sk->sk_state != TCP_SYN_RECV &&
+ WARN_ON_ONCE(sk->sk_state != TCP_SYN_RECV &&
sk->sk_state != TCP_FIN_WAIT1);
if (tcp_check_req(sk, skb, req, NULL, true) == NULL)
@@ -6052,7 +6053,15 @@ int tcp_rcv_state_process(struct sock *sk, struct sk_buff *skb,
* ACK we have received, this would have acknowledged
* our SYNACK so stop the SYNACK timer.
*/
- if (acceptable && req != NULL) {
+ if (req != NULL) {
+ /* Return RST if ack_seq is invalid.
+ * Note that RFC793 only says to generate a
+ * DUPACK for it but for TCP Fast Open it seems
+ * better to treat this case like TCP_SYN_RECV
+ * above.
+ */
+ if (!acceptable)
+ return 1;
/* We no longer need the request sock. */
reqsk_fastopen_remove(sk, req, false);
tcp_rearm_rto(sk);
diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c
index ef998b008a57..0c4a64355603 100644
--- a/net/ipv4/tcp_ipv4.c
+++ b/net/ipv4/tcp_ipv4.c
@@ -1461,6 +1461,7 @@ static int tcp_v4_conn_req_fastopen(struct sock *sk,
skb_set_owner_r(skb, child);
__skb_queue_tail(&child->sk_receive_queue, skb);
tp->rcv_nxt = TCP_SKB_CB(skb)->end_seq;
+ tp->syn_data_acked = 1;
}
sk->sk_data_ready(sk, 0);
bh_unlock_sock(child);
diff --git a/net/ipv4/tcp_minisocks.c b/net/ipv4/tcp_minisocks.c
index 27536ba16c9d..a7302d974f32 100644
--- a/net/ipv4/tcp_minisocks.c
+++ b/net/ipv4/tcp_minisocks.c
@@ -510,6 +510,7 @@ struct sock *tcp_create_openreq_child(struct sock *sk, struct request_sock *req,
newtp->rx_opt.mss_clamp = req->mss;
TCP_ECN_openreq_child(newtp, req);
newtp->fastopen_rsk = NULL;
+ newtp->syn_data_acked = 0;
TCP_INC_STATS_BH(sock_net(sk), TCP_MIB_PASSIVEOPENS);
}
diff --git a/net/ipv4/tcp_timer.c b/net/ipv4/tcp_timer.c
index fc04711e80c8..d47c1b4421a3 100644
--- a/net/ipv4/tcp_timer.c
+++ b/net/ipv4/tcp_timer.c
@@ -347,8 +347,8 @@ void tcp_retransmit_timer(struct sock *sk)
return;
}
if (tp->fastopen_rsk) {
- BUG_ON(sk->sk_state != TCP_SYN_RECV &&
- sk->sk_state != TCP_FIN_WAIT1);
+ WARN_ON_ONCE(sk->sk_state != TCP_SYN_RECV &&
+ sk->sk_state != TCP_FIN_WAIT1);
tcp_fastopen_synack_timer(sk);
/* Before we receive ACK to our SYN-ACK don't retransmit
* anything else (e.g., data or FIN segments).
diff --git a/net/ipv6/route.c b/net/ipv6/route.c
index 7c7e963260e1..b1e6cf0b95fd 100644
--- a/net/ipv6/route.c
+++ b/net/ipv6/route.c
@@ -219,7 +219,7 @@ static struct dst_ops ip6_dst_blackhole_ops = {
};
static const u32 ip6_template_metrics[RTAX_MAX] = {
- [RTAX_HOPLIMIT - 1] = 255,
+ [RTAX_HOPLIMIT - 1] = 0,
};
static const struct rt6_info ip6_null_entry_template = {
@@ -1232,7 +1232,7 @@ struct dst_entry *icmp6_dst_alloc(struct net_device *dev,
rt->rt6i_dst.addr = fl6->daddr;
rt->rt6i_dst.plen = 128;
rt->rt6i_idev = idev;
- dst_metric_set(&rt->dst, RTAX_HOPLIMIT, 255);
+ dst_metric_set(&rt->dst, RTAX_HOPLIMIT, 0);
spin_lock_bh(&icmp6_dst_lock);
rt->dst.next = icmp6_dst_gc_list;
diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c
index 6f8a73c64fb3..7de7717ad67d 100644
--- a/net/mac80211/iface.c
+++ b/net/mac80211/iface.c
@@ -853,7 +853,7 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata,
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
if (info->control.vif == &sdata->vif) {
__skb_unlink(skb, &local->pending[i]);
- dev_kfree_skb_irq(skb);
+ ieee80211_free_txskb(&local->hw, skb);
}
}
}
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
index e714ed8bb198..1b7eed252fe9 100644
--- a/net/mac80211/mlme.c
+++ b/net/mac80211/mlme.c
@@ -3099,22 +3099,32 @@ static int ieee80211_prep_channel(struct ieee80211_sub_if_data *sdata,
ht_cfreq, ht_oper->primary_chan,
cbss->channel->band);
ht_oper = NULL;
+ } else {
+ channel_type = NL80211_CHAN_HT20;
}
}
- if (ht_oper) {
- channel_type = NL80211_CHAN_HT20;
+ if (ht_oper && sband->ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40) {
+ /*
+ * cfg80211 already verified that the channel itself can
+ * be used, but it didn't check that we can do the right
+ * HT type, so do that here as well. If HT40 isn't allowed
+ * on this channel, disable 40 MHz operation.
+ */
- if (sband->ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40) {
- switch (ht_oper->ht_param &
- IEEE80211_HT_PARAM_CHA_SEC_OFFSET) {
- case IEEE80211_HT_PARAM_CHA_SEC_ABOVE:
+ switch (ht_oper->ht_param & IEEE80211_HT_PARAM_CHA_SEC_OFFSET) {
+ case IEEE80211_HT_PARAM_CHA_SEC_ABOVE:
+ if (cbss->channel->flags & IEEE80211_CHAN_NO_HT40PLUS)
+ ifmgd->flags |= IEEE80211_STA_DISABLE_40MHZ;
+ else
channel_type = NL80211_CHAN_HT40PLUS;
- break;
- case IEEE80211_HT_PARAM_CHA_SEC_BELOW:
+ break;
+ case IEEE80211_HT_PARAM_CHA_SEC_BELOW:
+ if (cbss->channel->flags & IEEE80211_CHAN_NO_HT40MINUS)
+ ifmgd->flags |= IEEE80211_STA_DISABLE_40MHZ;
+ else
channel_type = NL80211_CHAN_HT40MINUS;
- break;
- }
+ break;
}
}
@@ -3549,6 +3559,7 @@ int ieee80211_mgd_deauth(struct ieee80211_sub_if_data *sdata,
{
struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
u8 frame_buf[IEEE80211_DEAUTH_FRAME_LEN];
+ bool tx = !req->local_state_change;
mutex_lock(&ifmgd->mtx);
@@ -3565,12 +3576,12 @@ int ieee80211_mgd_deauth(struct ieee80211_sub_if_data *sdata,
if (ifmgd->associated &&
ether_addr_equal(ifmgd->associated->bssid, req->bssid)) {
ieee80211_set_disassoc(sdata, IEEE80211_STYPE_DEAUTH,
- req->reason_code, true, frame_buf);
+ req->reason_code, tx, frame_buf);
} else {
drv_mgd_prepare_tx(sdata->local, sdata);
ieee80211_send_deauth_disassoc(sdata, req->bssid,
IEEE80211_STYPE_DEAUTH,
- req->reason_code, true,
+ req->reason_code, tx,
frame_buf);
}
diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c
index 797dd36a220d..0a4e4c04db89 100644
--- a/net/mac80211/sta_info.c
+++ b/net/mac80211/sta_info.c
@@ -650,7 +650,7 @@ static bool sta_info_cleanup_expire_buffered_ac(struct ieee80211_local *local,
*/
if (!skb)
break;
- dev_kfree_skb(skb);
+ ieee80211_free_txskb(&local->hw, skb);
}
/*
@@ -679,7 +679,7 @@ static bool sta_info_cleanup_expire_buffered_ac(struct ieee80211_local *local,
local->total_ps_buffered--;
ps_dbg(sta->sdata, "Buffered frame expired (STA %pM)\n",
sta->sta.addr);
- dev_kfree_skb(skb);
+ ieee80211_free_txskb(&local->hw, skb);
}
/*
diff --git a/net/mac80211/util.c b/net/mac80211/util.c
index 22ca35054dd0..94e586873979 100644
--- a/net/mac80211/util.c
+++ b/net/mac80211/util.c
@@ -406,7 +406,7 @@ void ieee80211_add_pending_skb(struct ieee80211_local *local,
int queue = info->hw_queue;
if (WARN_ON(!info->control.vif)) {
- kfree_skb(skb);
+ ieee80211_free_txskb(&local->hw, skb);
return;
}
@@ -431,7 +431,7 @@ void ieee80211_add_pending_skbs_fn(struct ieee80211_local *local,
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
if (WARN_ON(!info->control.vif)) {
- kfree_skb(skb);
+ ieee80211_free_txskb(&local->hw, skb);
continue;
}
diff --git a/net/mac80211/wpa.c b/net/mac80211/wpa.c
index bdb53aba888e..8bd2f5c6a56e 100644
--- a/net/mac80211/wpa.c
+++ b/net/mac80211/wpa.c
@@ -106,7 +106,8 @@ ieee80211_rx_h_michael_mic_verify(struct ieee80211_rx_data *rx)
if (status->flag & RX_FLAG_MMIC_ERROR)
goto mic_fail;
- if (!(status->flag & RX_FLAG_IV_STRIPPED) && rx->key)
+ if (!(status->flag & RX_FLAG_IV_STRIPPED) && rx->key &&
+ rx->key->conf.cipher == WLAN_CIPHER_SUITE_TKIP)
goto update_iv;
return RX_CONTINUE;
@@ -545,14 +546,19 @@ ieee80211_crypto_ccmp_decrypt(struct ieee80211_rx_data *rx)
static void bip_aad(struct sk_buff *skb, u8 *aad)
{
+ __le16 mask_fc;
+ struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
+
/* BIP AAD: FC(masked) || A1 || A2 || A3 */
/* FC type/subtype */
- aad[0] = skb->data[0];
/* Mask FC Retry, PwrMgt, MoreData flags to zero */
- aad[1] = skb->data[1] & ~(BIT(4) | BIT(5) | BIT(6));
+ mask_fc = hdr->frame_control;
+ mask_fc &= ~cpu_to_le16(IEEE80211_FCTL_RETRY | IEEE80211_FCTL_PM |
+ IEEE80211_FCTL_MOREDATA);
+ put_unaligned(mask_fc, (__le16 *) &aad[0]);
/* A1 || A2 || A3 */
- memcpy(aad + 2, skb->data + 4, 3 * ETH_ALEN);
+ memcpy(aad + 2, &hdr->addr1, 3 * ETH_ALEN);
}
diff --git a/net/netfilter/ipvs/ip_vs_ctl.c b/net/netfilter/ipvs/ip_vs_ctl.c
index 7e7198b51c06..c4ee43710aab 100644
--- a/net/netfilter/ipvs/ip_vs_ctl.c
+++ b/net/netfilter/ipvs/ip_vs_ctl.c
@@ -2589,6 +2589,8 @@ __ip_vs_get_timeouts(struct net *net, struct ip_vs_timeout_user *u)
struct ip_vs_proto_data *pd;
#endif
+ memset(u, 0, sizeof (*u));
+
#ifdef CONFIG_IP_VS_PROTO_TCP
pd = ip_vs_proto_data_get(net, IPPROTO_TCP);
u->tcp_timeout = pd->timeout_table[IP_VS_TCP_S_ESTABLISHED] / HZ;
@@ -2766,7 +2768,6 @@ do_ip_vs_get_ctl(struct sock *sk, int cmd, void __user *user, int *len)
{
struct ip_vs_timeout_user t;
- memset(&t, 0, sizeof(t));
__ip_vs_get_timeouts(net, &t);
if (copy_to_user(user, &t, sizeof(t)) != 0)
ret = -EFAULT;
diff --git a/net/netfilter/xt_CT.c b/net/netfilter/xt_CT.c
index 16c712563860..ae7f5daeee43 100644
--- a/net/netfilter/xt_CT.c
+++ b/net/netfilter/xt_CT.c
@@ -180,9 +180,9 @@ xt_ct_set_timeout(struct nf_conn *ct, const struct xt_tgchk_param *par,
typeof(nf_ct_timeout_find_get_hook) timeout_find_get;
struct ctnl_timeout *timeout;
struct nf_conn_timeout *timeout_ext;
- const struct ipt_entry *e = par->entryinfo;
struct nf_conntrack_l4proto *l4proto;
int ret = 0;
+ u8 proto;
rcu_read_lock();
timeout_find_get = rcu_dereference(nf_ct_timeout_find_get_hook);
@@ -192,9 +192,11 @@ xt_ct_set_timeout(struct nf_conn *ct, const struct xt_tgchk_param *par,
goto out;
}
- if (e->ip.invflags & IPT_INV_PROTO) {
+ proto = xt_ct_find_proto(par);
+ if (!proto) {
ret = -EINVAL;
- pr_info("You cannot use inversion on L4 protocol\n");
+ pr_info("You must specify a L4 protocol, and not use "
+ "inversions on it.\n");
goto out;
}
@@ -214,7 +216,7 @@ xt_ct_set_timeout(struct nf_conn *ct, const struct xt_tgchk_param *par,
/* Make sure the timeout policy matches any existing protocol tracker,
* otherwise default to generic.
*/
- l4proto = __nf_ct_l4proto_find(par->family, e->ip.proto);
+ l4proto = __nf_ct_l4proto_find(par->family, proto);
if (timeout->l4proto->l4proto != l4proto->l4proto) {
ret = -EINVAL;
pr_info("Timeout policy `%s' can only be used by L4 protocol "
diff --git a/net/netfilter/xt_TEE.c b/net/netfilter/xt_TEE.c
index ee2e5bc5a8c7..bd93e51d30ac 100644
--- a/net/netfilter/xt_TEE.c
+++ b/net/netfilter/xt_TEE.c
@@ -70,6 +70,7 @@ tee_tg_route4(struct sk_buff *skb, const struct xt_tee_tginfo *info)
fl4.daddr = info->gw.ip;
fl4.flowi4_tos = RT_TOS(iph->tos);
fl4.flowi4_scope = RT_SCOPE_UNIVERSE;
+ fl4.flowi4_flags = FLOWI_FLAG_KNOWN_NH;
rt = ip_route_output_key(net, &fl4);
if (IS_ERR(rt))
return false;
diff --git a/net/netfilter/xt_nat.c b/net/netfilter/xt_nat.c
index 81aafa8e4fef..bea7464cc43f 100644
--- a/net/netfilter/xt_nat.c
+++ b/net/netfilter/xt_nat.c
@@ -111,7 +111,7 @@ static struct xt_target xt_nat_target_reg[] __read_mostly = {
.family = NFPROTO_IPV4,
.table = "nat",
.hooks = (1 << NF_INET_POST_ROUTING) |
- (1 << NF_INET_LOCAL_OUT),
+ (1 << NF_INET_LOCAL_IN),
.me = THIS_MODULE,
},
{
@@ -123,7 +123,7 @@ static struct xt_target xt_nat_target_reg[] __read_mostly = {
.family = NFPROTO_IPV4,
.table = "nat",
.hooks = (1 << NF_INET_PRE_ROUTING) |
- (1 << NF_INET_LOCAL_IN),
+ (1 << NF_INET_LOCAL_OUT),
.me = THIS_MODULE,
},
{
@@ -133,7 +133,7 @@ static struct xt_target xt_nat_target_reg[] __read_mostly = {
.targetsize = sizeof(struct nf_nat_range),
.table = "nat",
.hooks = (1 << NF_INET_POST_ROUTING) |
- (1 << NF_INET_LOCAL_OUT),
+ (1 << NF_INET_LOCAL_IN),
.me = THIS_MODULE,
},
{
@@ -143,7 +143,7 @@ static struct xt_target xt_nat_target_reg[] __read_mostly = {
.targetsize = sizeof(struct nf_nat_range),
.table = "nat",
.hooks = (1 << NF_INET_PRE_ROUTING) |
- (1 << NF_INET_LOCAL_IN),
+ (1 << NF_INET_LOCAL_OUT),
.me = THIS_MODULE,
},
};
diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c
index 01e944a017a4..4da797fa5ec5 100644
--- a/net/netlink/af_netlink.c
+++ b/net/netlink/af_netlink.c
@@ -138,6 +138,8 @@ static int netlink_dump(struct sock *sk);
static DEFINE_RWLOCK(nl_table_lock);
static atomic_t nl_table_users = ATOMIC_INIT(0);
+#define nl_deref_protected(X) rcu_dereference_protected(X, lockdep_is_held(&nl_table_lock));
+
static ATOMIC_NOTIFIER_HEAD(netlink_chain);
static inline u32 netlink_group_mask(u32 group)
@@ -345,6 +347,11 @@ netlink_update_listeners(struct sock *sk)
struct hlist_node *node;
unsigned long mask;
unsigned int i;
+ struct listeners *listeners;
+
+ listeners = nl_deref_protected(tbl->listeners);
+ if (!listeners)
+ return;
for (i = 0; i < NLGRPLONGS(tbl->groups); i++) {
mask = 0;
@@ -352,7 +359,7 @@ netlink_update_listeners(struct sock *sk)
if (i < NLGRPLONGS(nlk_sk(sk)->ngroups))
mask |= nlk_sk(sk)->groups[i];
}
- tbl->listeners->masks[i] = mask;
+ listeners->masks[i] = mask;
}
/* this function is only called with the netlink table "grabbed", which
* makes sure updates are visible before bind or setsockopt return. */
@@ -536,7 +543,11 @@ static int netlink_release(struct socket *sock)
if (netlink_is_kernel(sk)) {
BUG_ON(nl_table[sk->sk_protocol].registered == 0);
if (--nl_table[sk->sk_protocol].registered == 0) {
- kfree(nl_table[sk->sk_protocol].listeners);
+ struct listeners *old;
+
+ old = nl_deref_protected(nl_table[sk->sk_protocol].listeners);
+ RCU_INIT_POINTER(nl_table[sk->sk_protocol].listeners, NULL);
+ kfree_rcu(old, rcu);
nl_table[sk->sk_protocol].module = NULL;
nl_table[sk->sk_protocol].bind = NULL;
nl_table[sk->sk_protocol].flags = 0;
@@ -982,7 +993,7 @@ int netlink_has_listeners(struct sock *sk, unsigned int group)
rcu_read_lock();
listeners = rcu_dereference(nl_table[sk->sk_protocol].listeners);
- if (group - 1 < nl_table[sk->sk_protocol].groups)
+ if (listeners && group - 1 < nl_table[sk->sk_protocol].groups)
res = test_bit(group - 1, listeners->masks);
rcu_read_unlock();
@@ -1625,7 +1636,7 @@ int __netlink_change_ngroups(struct sock *sk, unsigned int groups)
new = kzalloc(sizeof(*new) + NLGRPSZ(groups), GFP_ATOMIC);
if (!new)
return -ENOMEM;
- old = rcu_dereference_protected(tbl->listeners, 1);
+ old = nl_deref_protected(tbl->listeners);
memcpy(new->masks, old->masks, NLGRPSZ(tbl->groups));
rcu_assign_pointer(tbl->listeners, new);
diff --git a/net/wireless/mlme.c b/net/wireless/mlme.c
index 8016fee0752b..904a7f368325 100644
--- a/net/wireless/mlme.c
+++ b/net/wireless/mlme.c
@@ -457,20 +457,14 @@ int __cfg80211_mlme_deauth(struct cfg80211_registered_device *rdev,
.reason_code = reason,
.ie = ie,
.ie_len = ie_len,
+ .local_state_change = local_state_change,
};
ASSERT_WDEV_LOCK(wdev);
- if (local_state_change) {
- if (wdev->current_bss &&
- ether_addr_equal(wdev->current_bss->pub.bssid, bssid)) {
- cfg80211_unhold_bss(wdev->current_bss);
- cfg80211_put_bss(&wdev->current_bss->pub);
- wdev->current_bss = NULL;
- }
-
+ if (local_state_change && (!wdev->current_bss ||
+ !ether_addr_equal(wdev->current_bss->pub.bssid, bssid)))
return 0;
- }
return rdev->ops->deauth(&rdev->wiphy, dev, &req);
}
diff --git a/sound/core/compress_offload.c b/sound/core/compress_offload.c
index c40ae573346d..ad11dc994792 100644
--- a/sound/core/compress_offload.c
+++ b/sound/core/compress_offload.c
@@ -100,12 +100,15 @@ static int snd_compr_open(struct inode *inode, struct file *f)
if (dirn != compr->direction) {
pr_err("this device doesn't support this direction\n");
+ snd_card_unref(compr->card);
return -EINVAL;
}
data = kzalloc(sizeof(*data), GFP_KERNEL);
- if (!data)
+ if (!data) {
+ snd_card_unref(compr->card);
return -ENOMEM;
+ }
data->stream.ops = compr->ops;
data->stream.direction = dirn;
data->stream.private_data = compr->private_data;
@@ -113,6 +116,7 @@ static int snd_compr_open(struct inode *inode, struct file *f)
runtime = kzalloc(sizeof(*runtime), GFP_KERNEL);
if (!runtime) {
kfree(data);
+ snd_card_unref(compr->card);
return -ENOMEM;
}
runtime->state = SNDRV_PCM_STATE_OPEN;
@@ -126,7 +130,8 @@ static int snd_compr_open(struct inode *inode, struct file *f)
kfree(runtime);
kfree(data);
}
- return ret;
+ snd_card_unref(compr->card);
+ return 0;
}
static int snd_compr_free(struct inode *inode, struct file *f)
diff --git a/sound/core/control.c b/sound/core/control.c
index 7e86a5b9f3b5..8c7c2c9bba61 100644
--- a/sound/core/control.c
+++ b/sound/core/control.c
@@ -86,6 +86,7 @@ static int snd_ctl_open(struct inode *inode, struct file *file)
write_lock_irqsave(&card->ctl_files_rwlock, flags);
list_add_tail(&ctl->list, &card->ctl_files);
write_unlock_irqrestore(&card->ctl_files_rwlock, flags);
+ snd_card_unref(card);
return 0;
__error:
@@ -93,6 +94,8 @@ static int snd_ctl_open(struct inode *inode, struct file *file)
__error2:
snd_card_file_remove(card, file);
__error1:
+ if (card)
+ snd_card_unref(card);
return err;
}
@@ -1434,6 +1437,8 @@ static ssize_t snd_ctl_read(struct file *file, char __user *buffer,
spin_unlock_irq(&ctl->read_lock);
schedule();
remove_wait_queue(&ctl->change_sleep, &wait);
+ if (ctl->card->shutdown)
+ return -ENODEV;
if (signal_pending(current))
return -ERESTARTSYS;
spin_lock_irq(&ctl->read_lock);
diff --git a/sound/core/hwdep.c b/sound/core/hwdep.c
index 75ea16f35b1a..3f7f6628cf7b 100644
--- a/sound/core/hwdep.c
+++ b/sound/core/hwdep.c
@@ -100,8 +100,10 @@ static int snd_hwdep_open(struct inode *inode, struct file * file)
if (hw == NULL)
return -ENODEV;
- if (!try_module_get(hw->card->module))
+ if (!try_module_get(hw->card->module)) {
+ snd_card_unref(hw->card);
return -EFAULT;
+ }
init_waitqueue_entry(&wait, current);
add_wait_queue(&hw->open_wait, &wait);
@@ -129,6 +131,10 @@ static int snd_hwdep_open(struct inode *inode, struct file * file)
mutex_unlock(&hw->open_mutex);
schedule();
mutex_lock(&hw->open_mutex);
+ if (hw->card->shutdown) {
+ err = -ENODEV;
+ break;
+ }
if (signal_pending(current)) {
err = -ERESTARTSYS;
break;
@@ -148,6 +154,7 @@ static int snd_hwdep_open(struct inode *inode, struct file * file)
mutex_unlock(&hw->open_mutex);
if (err < 0)
module_put(hw->card->module);
+ snd_card_unref(hw->card);
return err;
}
@@ -459,12 +466,15 @@ static int snd_hwdep_dev_disconnect(struct snd_device *device)
mutex_unlock(&register_mutex);
return -EINVAL;
}
+ mutex_lock(&hwdep->open_mutex);
+ wake_up(&hwdep->open_wait);
#ifdef CONFIG_SND_OSSEMUL
if (hwdep->ossreg)
snd_unregister_oss_device(hwdep->oss_type, hwdep->card, hwdep->device);
#endif
snd_unregister_device(SNDRV_DEVICE_TYPE_HWDEP, hwdep->card, hwdep->device);
list_del_init(&hwdep->list);
+ mutex_unlock(&hwdep->open_mutex);
mutex_unlock(&register_mutex);
return 0;
}
diff --git a/sound/core/init.c b/sound/core/init.c
index d8ec849af128..7b012d15c2cf 100644
--- a/sound/core/init.c
+++ b/sound/core/init.c
@@ -213,6 +213,7 @@ int snd_card_create(int idx, const char *xid,
spin_lock_init(&card->files_lock);
INIT_LIST_HEAD(&card->files_list);
init_waitqueue_head(&card->shutdown_sleep);
+ atomic_set(&card->refcount, 0);
#ifdef CONFIG_PM
mutex_init(&card->power_lock);
init_waitqueue_head(&card->power_sleep);
@@ -446,21 +447,36 @@ static int snd_card_do_free(struct snd_card *card)
return 0;
}
+/**
+ * snd_card_unref - release the reference counter
+ * @card: the card instance
+ *
+ * Decrements the reference counter. When it reaches to zero, wake up
+ * the sleeper and call the destructor if needed.
+ */
+void snd_card_unref(struct snd_card *card)
+{
+ if (atomic_dec_and_test(&card->refcount)) {
+ wake_up(&card->shutdown_sleep);
+ if (card->free_on_last_close)
+ snd_card_do_free(card);
+ }
+}
+EXPORT_SYMBOL(snd_card_unref);
+
int snd_card_free_when_closed(struct snd_card *card)
{
- int free_now = 0;
- int ret = snd_card_disconnect(card);
- if (ret)
- return ret;
+ int ret;
- spin_lock(&card->files_lock);
- if (list_empty(&card->files_list))
- free_now = 1;
- else
- card->free_on_last_close = 1;
- spin_unlock(&card->files_lock);
+ atomic_inc(&card->refcount);
+ ret = snd_card_disconnect(card);
+ if (ret) {
+ atomic_dec(&card->refcount);
+ return ret;
+ }
- if (free_now)
+ card->free_on_last_close = 1;
+ if (atomic_dec_and_test(&card->refcount))
snd_card_do_free(card);
return 0;
}
@@ -474,7 +490,7 @@ int snd_card_free(struct snd_card *card)
return ret;
/* wait, until all devices are ready for the free operation */
- wait_event(card->shutdown_sleep, list_empty(&card->files_list));
+ wait_event(card->shutdown_sleep, !atomic_read(&card->refcount));
snd_card_do_free(card);
return 0;
}
@@ -886,6 +902,7 @@ int snd_card_file_add(struct snd_card *card, struct file *file)
return -ENODEV;
}
list_add(&mfile->list, &card->files_list);
+ atomic_inc(&card->refcount);
spin_unlock(&card->files_lock);
return 0;
}
@@ -908,7 +925,6 @@ EXPORT_SYMBOL(snd_card_file_add);
int snd_card_file_remove(struct snd_card *card, struct file *file)
{
struct snd_monitor_file *mfile, *found = NULL;
- int last_close = 0;
spin_lock(&card->files_lock);
list_for_each_entry(mfile, &card->files_list, list) {
@@ -923,19 +939,13 @@ int snd_card_file_remove(struct snd_card *card, struct file *file)
break;
}
}
- if (list_empty(&card->files_list))
- last_close = 1;
spin_unlock(&card->files_lock);
- if (last_close) {
- wake_up(&card->shutdown_sleep);
- if (card->free_on_last_close)
- snd_card_do_free(card);
- }
if (!found) {
snd_printk(KERN_ERR "ALSA card file remove problem (%p)\n", file);
return -ENOENT;
}
kfree(found);
+ snd_card_unref(card);
return 0;
}
diff --git a/sound/core/oss/mixer_oss.c b/sound/core/oss/mixer_oss.c
index 29f6ded02555..a9a2e63c0222 100644
--- a/sound/core/oss/mixer_oss.c
+++ b/sound/core/oss/mixer_oss.c
@@ -52,14 +52,19 @@ static int snd_mixer_oss_open(struct inode *inode, struct file *file)
SNDRV_OSS_DEVICE_TYPE_MIXER);
if (card == NULL)
return -ENODEV;
- if (card->mixer_oss == NULL)
+ if (card->mixer_oss == NULL) {
+ snd_card_unref(card);
return -ENODEV;
+ }
err = snd_card_file_add(card, file);
- if (err < 0)
+ if (err < 0) {
+ snd_card_unref(card);
return err;
+ }
fmixer = kzalloc(sizeof(*fmixer), GFP_KERNEL);
if (fmixer == NULL) {
snd_card_file_remove(card, file);
+ snd_card_unref(card);
return -ENOMEM;
}
fmixer->card = card;
@@ -68,6 +73,7 @@ static int snd_mixer_oss_open(struct inode *inode, struct file *file)
if (!try_module_get(card->module)) {
kfree(fmixer);
snd_card_file_remove(card, file);
+ snd_card_unref(card);
return -EFAULT;
}
return 0;
diff --git a/sound/core/oss/pcm_oss.c b/sound/core/oss/pcm_oss.c
index 08fde0060fd9..f337b66a020b 100644
--- a/sound/core/oss/pcm_oss.c
+++ b/sound/core/oss/pcm_oss.c
@@ -2441,6 +2441,10 @@ static int snd_pcm_oss_open(struct inode *inode, struct file *file)
mutex_unlock(&pcm->open_mutex);
schedule();
mutex_lock(&pcm->open_mutex);
+ if (pcm->card->shutdown) {
+ err = -ENODEV;
+ break;
+ }
if (signal_pending(current)) {
err = -ERESTARTSYS;
break;
@@ -2457,6 +2461,8 @@ static int snd_pcm_oss_open(struct inode *inode, struct file *file)
__error2:
snd_card_file_remove(pcm->card, file);
__error1:
+ if (pcm)
+ snd_card_unref(pcm->card);
return err;
}
diff --git a/sound/core/pcm.c b/sound/core/pcm.c
index f2991940b271..030102caeee9 100644
--- a/sound/core/pcm.c
+++ b/sound/core/pcm.c
@@ -1086,11 +1086,19 @@ static int snd_pcm_dev_disconnect(struct snd_device *device)
if (list_empty(&pcm->list))
goto unlock;
+ mutex_lock(&pcm->open_mutex);
+ wake_up(&pcm->open_wait);
list_del_init(&pcm->list);
for (cidx = 0; cidx < 2; cidx++)
- for (substream = pcm->streams[cidx].substream; substream; substream = substream->next)
- if (substream->runtime)
+ for (substream = pcm->streams[cidx].substream; substream; substream = substream->next) {
+ snd_pcm_stream_lock_irq(substream);
+ if (substream->runtime) {
substream->runtime->status->state = SNDRV_PCM_STATE_DISCONNECTED;
+ wake_up(&substream->runtime->sleep);
+ wake_up(&substream->runtime->tsleep);
+ }
+ snd_pcm_stream_unlock_irq(substream);
+ }
list_for_each_entry(notify, &snd_pcm_notify_list, list) {
notify->n_disconnect(pcm);
}
@@ -1110,6 +1118,7 @@ static int snd_pcm_dev_disconnect(struct snd_device *device)
pcm->streams[cidx].chmap_kctl = NULL;
}
}
+ mutex_unlock(&pcm->open_mutex);
unlock:
mutex_unlock(&register_mutex);
return 0;
diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c
index 5e12e5bacbba..6e8872de5ba0 100644
--- a/sound/core/pcm_native.c
+++ b/sound/core/pcm_native.c
@@ -369,6 +369,14 @@ static int period_to_usecs(struct snd_pcm_runtime *runtime)
return usecs;
}
+static void snd_pcm_set_state(struct snd_pcm_substream *substream, int state)
+{
+ snd_pcm_stream_lock_irq(substream);
+ if (substream->runtime->status->state != SNDRV_PCM_STATE_DISCONNECTED)
+ substream->runtime->status->state = state;
+ snd_pcm_stream_unlock_irq(substream);
+}
+
static int snd_pcm_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
@@ -452,7 +460,7 @@ static int snd_pcm_hw_params(struct snd_pcm_substream *substream,
runtime->boundary *= 2;
snd_pcm_timer_resolution_change(substream);
- runtime->status->state = SNDRV_PCM_STATE_SETUP;
+ snd_pcm_set_state(substream, SNDRV_PCM_STATE_SETUP);
if (pm_qos_request_active(&substream->latency_pm_qos_req))
pm_qos_remove_request(&substream->latency_pm_qos_req);
@@ -464,7 +472,7 @@ static int snd_pcm_hw_params(struct snd_pcm_substream *substream,
/* hardware might be unusable from this time,
so we force application to retry to set
the correct hardware parameter settings */
- runtime->status->state = SNDRV_PCM_STATE_OPEN;
+ snd_pcm_set_state(substream, SNDRV_PCM_STATE_OPEN);
if (substream->ops->hw_free != NULL)
substream->ops->hw_free(substream);
return err;
@@ -512,7 +520,7 @@ static int snd_pcm_hw_free(struct snd_pcm_substream *substream)
return -EBADFD;
if (substream->ops->hw_free)
result = substream->ops->hw_free(substream);
- runtime->status->state = SNDRV_PCM_STATE_OPEN;
+ snd_pcm_set_state(substream, SNDRV_PCM_STATE_OPEN);
pm_qos_remove_request(&substream->latency_pm_qos_req);
return result;
}
@@ -1320,7 +1328,7 @@ static void snd_pcm_post_prepare(struct snd_pcm_substream *substream, int state)
{
struct snd_pcm_runtime *runtime = substream->runtime;
runtime->control->appl_ptr = runtime->status->hw_ptr;
- runtime->status->state = SNDRV_PCM_STATE_PREPARED;
+ snd_pcm_set_state(substream, SNDRV_PCM_STATE_PREPARED);
}
static struct action_ops snd_pcm_action_prepare = {
@@ -1510,6 +1518,10 @@ static int snd_pcm_drain(struct snd_pcm_substream *substream,
down_read(&snd_pcm_link_rwsem);
snd_pcm_stream_lock_irq(substream);
remove_wait_queue(&to_check->sleep, &wait);
+ if (card->shutdown) {
+ result = -ENODEV;
+ break;
+ }
if (tout == 0) {
if (substream->runtime->status->state == SNDRV_PCM_STATE_SUSPENDED)
result = -ESTRPIPE;
@@ -1634,6 +1646,7 @@ static int snd_pcm_link(struct snd_pcm_substream *substream, int fd)
write_unlock_irq(&snd_pcm_link_rwlock);
up_write(&snd_pcm_link_rwsem);
_nolock:
+ snd_card_unref(substream1->pcm->card);
fput_light(file, fput_needed);
if (res < 0)
kfree(group);
@@ -2108,7 +2121,9 @@ static int snd_pcm_playback_open(struct inode *inode, struct file *file)
return err;
pcm = snd_lookup_minor_data(iminor(inode),
SNDRV_DEVICE_TYPE_PCM_PLAYBACK);
- return snd_pcm_open(file, pcm, SNDRV_PCM_STREAM_PLAYBACK);
+ err = snd_pcm_open(file, pcm, SNDRV_PCM_STREAM_PLAYBACK);
+ snd_card_unref(pcm->card);
+ return err;
}
static int snd_pcm_capture_open(struct inode *inode, struct file *file)
@@ -2119,7 +2134,9 @@ static int snd_pcm_capture_open(struct inode *inode, struct file *file)
return err;
pcm = snd_lookup_minor_data(iminor(inode),
SNDRV_DEVICE_TYPE_PCM_CAPTURE);
- return snd_pcm_open(file, pcm, SNDRV_PCM_STREAM_CAPTURE);
+ err = snd_pcm_open(file, pcm, SNDRV_PCM_STREAM_CAPTURE);
+ snd_card_unref(pcm->card);
+ return err;
}
static int snd_pcm_open(struct file *file, struct snd_pcm *pcm, int stream)
@@ -2156,6 +2173,10 @@ static int snd_pcm_open(struct file *file, struct snd_pcm *pcm, int stream)
mutex_unlock(&pcm->open_mutex);
schedule();
mutex_lock(&pcm->open_mutex);
+ if (pcm->card->shutdown) {
+ err = -ENODEV;
+ break;
+ }
if (signal_pending(current)) {
err = -ERESTARTSYS;
break;
diff --git a/sound/core/rawmidi.c b/sound/core/rawmidi.c
index ebf6e49ad3d4..1bb95aeea084 100644
--- a/sound/core/rawmidi.c
+++ b/sound/core/rawmidi.c
@@ -379,8 +379,10 @@ static int snd_rawmidi_open(struct inode *inode, struct file *file)
if (rmidi == NULL)
return -ENODEV;
- if (!try_module_get(rmidi->card->module))
+ if (!try_module_get(rmidi->card->module)) {
+ snd_card_unref(rmidi->card);
return -ENXIO;
+ }
mutex_lock(&rmidi->open_mutex);
card = rmidi->card;
@@ -422,6 +424,10 @@ static int snd_rawmidi_open(struct inode *inode, struct file *file)
mutex_unlock(&rmidi->open_mutex);
schedule();
mutex_lock(&rmidi->open_mutex);
+ if (rmidi->card->shutdown) {
+ err = -ENODEV;
+ break;
+ }
if (signal_pending(current)) {
err = -ERESTARTSYS;
break;
@@ -440,6 +446,7 @@ static int snd_rawmidi_open(struct inode *inode, struct file *file)
#endif
file->private_data = rawmidi_file;
mutex_unlock(&rmidi->open_mutex);
+ snd_card_unref(rmidi->card);
return 0;
__error:
@@ -447,6 +454,7 @@ static int snd_rawmidi_open(struct inode *inode, struct file *file)
__error_card:
mutex_unlock(&rmidi->open_mutex);
module_put(rmidi->card->module);
+ snd_card_unref(rmidi->card);
return err;
}
@@ -991,6 +999,8 @@ static ssize_t snd_rawmidi_read(struct file *file, char __user *buf, size_t coun
spin_unlock_irq(&runtime->lock);
schedule();
remove_wait_queue(&runtime->sleep, &wait);
+ if (rfile->rmidi->card->shutdown)
+ return -ENODEV;
if (signal_pending(current))
return result > 0 ? result : -ERESTARTSYS;
if (!runtime->avail)
@@ -1234,6 +1244,8 @@ static ssize_t snd_rawmidi_write(struct file *file, const char __user *buf,
spin_unlock_irq(&runtime->lock);
timeout = schedule_timeout(30 * HZ);
remove_wait_queue(&runtime->sleep, &wait);
+ if (rfile->rmidi->card->shutdown)
+ return -ENODEV;
if (signal_pending(current))
return result > 0 ? result : -ERESTARTSYS;
if (!runtime->avail && !timeout)
@@ -1609,9 +1621,20 @@ static int snd_rawmidi_dev_register(struct snd_device *device)
static int snd_rawmidi_dev_disconnect(struct snd_device *device)
{
struct snd_rawmidi *rmidi = device->device_data;
+ int dir;
mutex_lock(&register_mutex);
+ mutex_lock(&rmidi->open_mutex);
+ wake_up(&rmidi->open_wait);
list_del_init(&rmidi->list);
+ for (dir = 0; dir < 2; dir++) {
+ struct snd_rawmidi_substream *s;
+ list_for_each_entry(s, &rmidi->streams[dir].substreams, list) {
+ if (s->runtime)
+ wake_up(&s->runtime->sleep);
+ }
+ }
+
#ifdef CONFIG_SND_OSSEMUL
if (rmidi->ossreg) {
if ((int)rmidi->device == midi_map[rmidi->card->number]) {
@@ -1626,6 +1649,7 @@ static int snd_rawmidi_dev_disconnect(struct snd_device *device)
}
#endif /* CONFIG_SND_OSSEMUL */
snd_unregister_device(SNDRV_DEVICE_TYPE_RAWMIDI, rmidi->card, rmidi->device);
+ mutex_unlock(&rmidi->open_mutex);
mutex_unlock(&register_mutex);
return 0;
}
diff --git a/sound/core/sound.c b/sound/core/sound.c
index 643976000ce8..89780c323f19 100644
--- a/sound/core/sound.c
+++ b/sound/core/sound.c
@@ -98,6 +98,10 @@ static void snd_request_other(int minor)
*
* Checks that a minor device with the specified type is registered, and returns
* its user data pointer.
+ *
+ * This function increments the reference counter of the card instance
+ * if an associated instance with the given minor number and type is found.
+ * The caller must call snd_card_unref() appropriately later.
*/
void *snd_lookup_minor_data(unsigned int minor, int type)
{
@@ -108,9 +112,11 @@ void *snd_lookup_minor_data(unsigned int minor, int type)
return NULL;
mutex_lock(&sound_mutex);
mreg = snd_minors[minor];
- if (mreg && mreg->type == type)
+ if (mreg && mreg->type == type) {
private_data = mreg->private_data;
- else
+ if (mreg->card_ptr)
+ atomic_inc(&mreg->card_ptr->refcount);
+ } else
private_data = NULL;
mutex_unlock(&sound_mutex);
return private_data;
@@ -275,6 +281,7 @@ int snd_register_device_for_dev(int type, struct snd_card *card, int dev,
preg->device = dev;
preg->f_ops = f_ops;
preg->private_data = private_data;
+ preg->card_ptr = card;
mutex_lock(&sound_mutex);
#ifdef CONFIG_SND_DYNAMIC_MINORS
minor = snd_find_free_minor(type);
diff --git a/sound/core/sound_oss.c b/sound/core/sound_oss.c
index e9528333e36d..e1d79ee35906 100644
--- a/sound/core/sound_oss.c
+++ b/sound/core/sound_oss.c
@@ -40,6 +40,9 @@
static struct snd_minor *snd_oss_minors[SNDRV_OSS_MINORS];
static DEFINE_MUTEX(sound_oss_mutex);
+/* NOTE: This function increments the refcount of the associated card like
+ * snd_lookup_minor_data(); the caller must call snd_card_unref() appropriately
+ */
void *snd_lookup_oss_minor_data(unsigned int minor, int type)
{
struct snd_minor *mreg;
@@ -49,9 +52,11 @@ void *snd_lookup_oss_minor_data(unsigned int minor, int type)
return NULL;
mutex_lock(&sound_oss_mutex);
mreg = snd_oss_minors[minor];
- if (mreg && mreg->type == type)
+ if (mreg && mreg->type == type) {
private_data = mreg->private_data;
- else
+ if (mreg->card_ptr)
+ atomic_inc(&mreg->card_ptr->refcount);
+ } else
private_data = NULL;
mutex_unlock(&sound_oss_mutex);
return private_data;
@@ -123,6 +128,7 @@ int snd_register_oss_device(int type, struct snd_card *card, int dev,
preg->device = dev;
preg->f_ops = f_ops;
preg->private_data = private_data;
+ preg->card_ptr = card;
mutex_lock(&sound_oss_mutex);
snd_oss_minors[minor] = preg;
minor_unit = SNDRV_MINOR_OSS_DEVICE(minor);
diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c
index 770013ff556f..9ba8af056170 100644
--- a/sound/pci/hda/patch_sigmatel.c
+++ b/sound/pci/hda/patch_sigmatel.c
@@ -1763,6 +1763,8 @@ static const struct snd_pci_quirk stac92hd83xxx_cfg_tbl[] = {
"HP", STAC_HP_ZEPHYR),
SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x3660,
"HP Mini", STAC_92HD83XXX_HP_LED),
+ SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x144E,
+ "HP Pavilion dv5", STAC_92HD83XXX_HP_INV_LED),
{} /* terminator */
};
diff --git a/sound/pci/ice1712/ice1724.c b/sound/pci/ice1712/ice1724.c
index 3050a5279253..245d874891ba 100644
--- a/sound/pci/ice1712/ice1724.c
+++ b/sound/pci/ice1712/ice1724.c
@@ -2859,7 +2859,12 @@ static int snd_vt1724_resume(struct device *dev)
ice->set_spdif_clock(ice, 0);
} else {
/* internal on-card clock */
- snd_vt1724_set_pro_rate(ice, ice->pro_rate_default, 1);
+ int rate;
+ if (ice->cur_rate)
+ rate = ice->cur_rate;
+ else
+ rate = ice->pro_rate_default;
+ snd_vt1724_set_pro_rate(ice, rate, 1);
}
update_spdif_bits(ice, ice->pm_saved_spdif_ctrl);
diff --git a/sound/soc/omap/omap-dmic.c b/sound/soc/omap/omap-dmic.c
index 68f2cd1a9206..5a6aeaf552a8 100644
--- a/sound/soc/omap/omap-dmic.c
+++ b/sound/soc/omap/omap-dmic.c
@@ -464,9 +464,9 @@ static __devinit int asoc_dmic_probe(struct platform_device *pdev)
mutex_init(&dmic->mutex);
- dmic->fclk = clk_get(dmic->dev, "dmic_fck");
+ dmic->fclk = clk_get(dmic->dev, "fck");
if (IS_ERR(dmic->fclk)) {
- dev_err(dmic->dev, "cant get dmic_fck\n");
+ dev_err(dmic->dev, "cant get fck\n");
return -ENODEV;
}
diff --git a/sound/soc/omap/zoom2.c b/sound/soc/omap/zoom2.c
index 677b567935f8..1ff6bb9ade5c 100644
--- a/sound/soc/omap/zoom2.c
+++ b/sound/soc/omap/zoom2.c
@@ -21,15 +21,14 @@
#include <linux/clk.h>
#include <linux/platform_device.h>
+#include <linux/gpio.h>
#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/soc.h>
#include <asm/mach-types.h>
-#include <mach/hardware.h>
-#include <mach/gpio.h>
-#include <mach/board-zoom.h>
#include <linux/platform_data/asoc-ti-mcbsp.h>
+#include <linux/platform_data/gpio-omap.h>
/* Register descriptions for twl4030 codec part */
#include <linux/mfd/twl4030-audio.h>
diff --git a/sound/usb/card.c b/sound/usb/card.c
index 561bb74fd364..282f0fc9fed1 100644
--- a/sound/usb/card.c
+++ b/sound/usb/card.c
@@ -339,7 +339,7 @@ static int snd_usb_audio_create(struct usb_device *dev, int idx,
}
mutex_init(&chip->mutex);
- mutex_init(&chip->shutdown_mutex);
+ init_rwsem(&chip->shutdown_rwsem);
chip->index = idx;
chip->dev = dev;
chip->card = card;
@@ -560,7 +560,7 @@ static void snd_usb_audio_disconnect(struct usb_device *dev,
card = chip->card;
mutex_lock(&register_mutex);
- mutex_lock(&chip->shutdown_mutex);
+ down_write(&chip->shutdown_rwsem);
chip->shutdown = 1;
chip->num_interfaces--;
if (chip->num_interfaces <= 0) {
@@ -582,11 +582,11 @@ static void snd_usb_audio_disconnect(struct usb_device *dev,
snd_usb_mixer_disconnect(p);
}
usb_chip[chip->index] = NULL;
- mutex_unlock(&chip->shutdown_mutex);
+ up_write(&chip->shutdown_rwsem);
mutex_unlock(&register_mutex);
snd_card_free_when_closed(card);
} else {
- mutex_unlock(&chip->shutdown_mutex);
+ up_write(&chip->shutdown_rwsem);
mutex_unlock(&register_mutex);
}
}
@@ -618,16 +618,20 @@ int snd_usb_autoresume(struct snd_usb_audio *chip)
{
int err = -ENODEV;
+ down_read(&chip->shutdown_rwsem);
if (!chip->shutdown && !chip->probing)
err = usb_autopm_get_interface(chip->pm_intf);
+ up_read(&chip->shutdown_rwsem);
return err;
}
void snd_usb_autosuspend(struct snd_usb_audio *chip)
{
+ down_read(&chip->shutdown_rwsem);
if (!chip->shutdown && !chip->probing)
usb_autopm_put_interface(chip->pm_intf);
+ up_read(&chip->shutdown_rwsem);
}
static int usb_audio_suspend(struct usb_interface *intf, pm_message_t message)
diff --git a/sound/usb/card.h b/sound/usb/card.h
index afa4f9e9b27a..814cb357ff88 100644
--- a/sound/usb/card.h
+++ b/sound/usb/card.h
@@ -126,6 +126,7 @@ struct snd_usb_substream {
struct snd_usb_endpoint *sync_endpoint;
unsigned long flags;
bool need_setup_ep; /* (re)configure EP at prepare? */
+ unsigned int speed; /* USB_SPEED_XXX */
u64 formats; /* format bitmasks (all or'ed) */
unsigned int num_formats; /* number of supported audio formats (list) */
diff --git a/sound/usb/mixer.c b/sound/usb/mixer.c
index fe56c9da38e9..298070e8f2d4 100644
--- a/sound/usb/mixer.c
+++ b/sound/usb/mixer.c
@@ -287,25 +287,32 @@ static int get_ctl_value_v1(struct usb_mixer_elem_info *cval, int request, int v
unsigned char buf[2];
int val_len = cval->val_type >= USB_MIXER_S16 ? 2 : 1;
int timeout = 10;
- int err;
+ int idx = 0, err;
err = snd_usb_autoresume(cval->mixer->chip);
if (err < 0)
return -EIO;
+ down_read(&chip->shutdown_rwsem);
while (timeout-- > 0) {
+ if (chip->shutdown)
+ break;
+ idx = snd_usb_ctrl_intf(chip) | (cval->id << 8);
if (snd_usb_ctl_msg(chip->dev, usb_rcvctrlpipe(chip->dev, 0), request,
USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN,
- validx, snd_usb_ctrl_intf(chip) | (cval->id << 8),
- buf, val_len) >= val_len) {
+ validx, idx, buf, val_len) >= val_len) {
*value_ret = convert_signed_value(cval, snd_usb_combine_bytes(buf, val_len));
- snd_usb_autosuspend(cval->mixer->chip);
- return 0;
+ err = 0;
+ goto out;
}
}
- snd_usb_autosuspend(cval->mixer->chip);
snd_printdd(KERN_ERR "cannot get ctl value: req = %#x, wValue = %#x, wIndex = %#x, type = %d\n",
- request, validx, snd_usb_ctrl_intf(chip) | (cval->id << 8), cval->val_type);
- return -EINVAL;
+ request, validx, idx, cval->val_type);
+ err = -EINVAL;
+
+ out:
+ up_read(&chip->shutdown_rwsem);
+ snd_usb_autosuspend(cval->mixer->chip);
+ return err;
}
static int get_ctl_value_v2(struct usb_mixer_elem_info *cval, int request, int validx, int *value_ret)
@@ -313,7 +320,7 @@ static int get_ctl_value_v2(struct usb_mixer_elem_info *cval, int request, int v
struct snd_usb_audio *chip = cval->mixer->chip;
unsigned char buf[2 + 3*sizeof(__u16)]; /* enough space for one range */
unsigned char *val;
- int ret, size;
+ int idx = 0, ret, size;
__u8 bRequest;
if (request == UAC_GET_CUR) {
@@ -330,16 +337,22 @@ static int get_ctl_value_v2(struct usb_mixer_elem_info *cval, int request, int v
if (ret)
goto error;
- ret = snd_usb_ctl_msg(chip->dev, usb_rcvctrlpipe(chip->dev, 0), bRequest,
+ down_read(&chip->shutdown_rwsem);
+ if (chip->shutdown)
+ ret = -ENODEV;
+ else {
+ idx = snd_usb_ctrl_intf(chip) | (cval->id << 8);
+ ret = snd_usb_ctl_msg(chip->dev, usb_rcvctrlpipe(chip->dev, 0), bRequest,
USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN,
- validx, snd_usb_ctrl_intf(chip) | (cval->id << 8),
- buf, size);
+ validx, idx, buf, size);
+ }
+ up_read(&chip->shutdown_rwsem);
snd_usb_autosuspend(chip);
if (ret < 0) {
error:
snd_printk(KERN_ERR "cannot get ctl value: req = %#x, wValue = %#x, wIndex = %#x, type = %d\n",
- request, validx, snd_usb_ctrl_intf(chip) | (cval->id << 8), cval->val_type);
+ request, validx, idx, cval->val_type);
return ret;
}
@@ -417,7 +430,7 @@ int snd_usb_mixer_set_ctl_value(struct usb_mixer_elem_info *cval,
{
struct snd_usb_audio *chip = cval->mixer->chip;
unsigned char buf[2];
- int val_len, err, timeout = 10;
+ int idx = 0, val_len, err, timeout = 10;
if (cval->mixer->protocol == UAC_VERSION_1) {
val_len = cval->val_type >= USB_MIXER_S16 ? 2 : 1;
@@ -440,19 +453,27 @@ int snd_usb_mixer_set_ctl_value(struct usb_mixer_elem_info *cval,
err = snd_usb_autoresume(chip);
if (err < 0)
return -EIO;
- while (timeout-- > 0)
+ down_read(&chip->shutdown_rwsem);
+ while (timeout-- > 0) {
+ if (chip->shutdown)
+ break;
+ idx = snd_usb_ctrl_intf(chip) | (cval->id << 8);
if (snd_usb_ctl_msg(chip->dev,
usb_sndctrlpipe(chip->dev, 0), request,
USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_OUT,
- validx, snd_usb_ctrl_intf(chip) | (cval->id << 8),
- buf, val_len) >= 0) {
- snd_usb_autosuspend(chip);
- return 0;
+ validx, idx, buf, val_len) >= 0) {
+ err = 0;
+ goto out;
}
- snd_usb_autosuspend(chip);
+ }
snd_printdd(KERN_ERR "cannot set ctl value: req = %#x, wValue = %#x, wIndex = %#x, type = %d, data = %#x/%#x\n",
- request, validx, snd_usb_ctrl_intf(chip) | (cval->id << 8), cval->val_type, buf[0], buf[1]);
- return -EINVAL;
+ request, validx, idx, cval->val_type, buf[0], buf[1]);
+ err = -EINVAL;
+
+ out:
+ up_read(&chip->shutdown_rwsem);
+ snd_usb_autosuspend(chip);
+ return err;
}
static int set_cur_ctl_value(struct usb_mixer_elem_info *cval, int validx, int value)
diff --git a/sound/usb/mixer_quirks.c b/sound/usb/mixer_quirks.c
index 690000db0ec0..ae2b71435220 100644
--- a/sound/usb/mixer_quirks.c
+++ b/sound/usb/mixer_quirks.c
@@ -283,6 +283,11 @@ static int snd_audigy2nx_led_put(struct snd_kcontrol *kcontrol, struct snd_ctl_e
if (value > 1)
return -EINVAL;
changed = value != mixer->audigy2nx_leds[index];
+ down_read(&mixer->chip->shutdown_rwsem);
+ if (mixer->chip->shutdown) {
+ err = -ENODEV;
+ goto out;
+ }
if (mixer->chip->usb_id == USB_ID(0x041e, 0x3042))
err = snd_usb_ctl_msg(mixer->chip->dev,
usb_sndctrlpipe(mixer->chip->dev, 0), 0x24,
@@ -299,6 +304,8 @@ static int snd_audigy2nx_led_put(struct snd_kcontrol *kcontrol, struct snd_ctl_e
usb_sndctrlpipe(mixer->chip->dev, 0), 0x24,
USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_OTHER,
value, index + 2, NULL, 0);
+ out:
+ up_read(&mixer->chip->shutdown_rwsem);
if (err < 0)
return err;
mixer->audigy2nx_leds[index] = value;
@@ -392,11 +399,16 @@ static void snd_audigy2nx_proc_read(struct snd_info_entry *entry,
for (i = 0; jacks[i].name; ++i) {
snd_iprintf(buffer, "%s: ", jacks[i].name);
- err = snd_usb_ctl_msg(mixer->chip->dev,
+ down_read(&mixer->chip->shutdown_rwsem);
+ if (mixer->chip->shutdown)
+ err = 0;
+ else
+ err = snd_usb_ctl_msg(mixer->chip->dev,
usb_rcvctrlpipe(mixer->chip->dev, 0),
UAC_GET_MEM, USB_DIR_IN | USB_TYPE_CLASS |
USB_RECIP_INTERFACE, 0,
jacks[i].unitid << 8, buf, 3);
+ up_read(&mixer->chip->shutdown_rwsem);
if (err == 3 && (buf[0] == 3 || buf[0] == 6))
snd_iprintf(buffer, "%02x %02x\n", buf[1], buf[2]);
else
@@ -426,10 +438,15 @@ static int snd_xonar_u1_switch_put(struct snd_kcontrol *kcontrol,
else
new_status = old_status & ~0x02;
changed = new_status != old_status;
- err = snd_usb_ctl_msg(mixer->chip->dev,
+ down_read(&mixer->chip->shutdown_rwsem);
+ if (mixer->chip->shutdown)
+ err = -ENODEV;
+ else
+ err = snd_usb_ctl_msg(mixer->chip->dev,
usb_sndctrlpipe(mixer->chip->dev, 0), 0x08,
USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_OTHER,
50, 0, &new_status, 1);
+ up_read(&mixer->chip->shutdown_rwsem);
if (err < 0)
return err;
mixer->xonar_u1_status = new_status;
@@ -468,11 +485,17 @@ static int snd_nativeinstruments_control_get(struct snd_kcontrol *kcontrol,
u8 bRequest = (kcontrol->private_value >> 16) & 0xff;
u16 wIndex = kcontrol->private_value & 0xffff;
u8 tmp;
+ int ret;
- int ret = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), bRequest,
+ down_read(&mixer->chip->shutdown_rwsem);
+ if (mixer->chip->shutdown)
+ ret = -ENODEV;
+ else
+ ret = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), bRequest,
USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
0, cpu_to_le16(wIndex),
&tmp, sizeof(tmp), 1000);
+ up_read(&mixer->chip->shutdown_rwsem);
if (ret < 0) {
snd_printk(KERN_ERR
@@ -493,11 +516,17 @@ static int snd_nativeinstruments_control_put(struct snd_kcontrol *kcontrol,
u8 bRequest = (kcontrol->private_value >> 16) & 0xff;
u16 wIndex = kcontrol->private_value & 0xffff;
u16 wValue = ucontrol->value.integer.value[0];
+ int ret;
- int ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), bRequest,
+ down_read(&mixer->chip->shutdown_rwsem);
+ if (mixer->chip->shutdown)
+ ret = -ENODEV;
+ else
+ ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), bRequest,
USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_OUT,
cpu_to_le16(wValue), cpu_to_le16(wIndex),
NULL, 0, 1000);
+ up_read(&mixer->chip->shutdown_rwsem);
if (ret < 0) {
snd_printk(KERN_ERR
@@ -656,11 +685,16 @@ static int snd_ftu_eff_switch_get(struct snd_kcontrol *kctl,
return -EINVAL;
- err = snd_usb_ctl_msg(chip->dev,
+ down_read(&mixer->chip->shutdown_rwsem);
+ if (mixer->chip->shutdown)
+ err = -ENODEV;
+ else
+ err = snd_usb_ctl_msg(chip->dev,
usb_rcvctrlpipe(chip->dev, 0), UAC_GET_CUR,
USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN,
validx << 8, snd_usb_ctrl_intf(chip) | (id << 8),
value, val_len);
+ up_read(&mixer->chip->shutdown_rwsem);
if (err < 0)
return err;
@@ -703,11 +737,16 @@ static int snd_ftu_eff_switch_put(struct snd_kcontrol *kctl,
if (!pval->is_cached) {
/* Read current value */
- err = snd_usb_ctl_msg(chip->dev,
+ down_read(&mixer->chip->shutdown_rwsem);
+ if (mixer->chip->shutdown)
+ err = -ENODEV;
+ else
+ err = snd_usb_ctl_msg(chip->dev,
usb_rcvctrlpipe(chip->dev, 0), UAC_GET_CUR,
USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN,
validx << 8, snd_usb_ctrl_intf(chip) | (id << 8),
value, val_len);
+ up_read(&mixer->chip->shutdown_rwsem);
if (err < 0)
return err;
@@ -719,11 +758,16 @@ static int snd_ftu_eff_switch_put(struct snd_kcontrol *kctl,
if (cur_val != new_val) {
value[0] = new_val;
value[1] = 0;
- err = snd_usb_ctl_msg(chip->dev,
+ down_read(&mixer->chip->shutdown_rwsem);
+ if (mixer->chip->shutdown)
+ err = -ENODEV;
+ else
+ err = snd_usb_ctl_msg(chip->dev,
usb_sndctrlpipe(chip->dev, 0), UAC_SET_CUR,
USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_OUT,
validx << 8, snd_usb_ctrl_intf(chip) | (id << 8),
value, val_len);
+ up_read(&mixer->chip->shutdown_rwsem);
if (err < 0)
return err;
diff --git a/sound/usb/pcm.c b/sound/usb/pcm.c
index 55e19e1b80ec..37428f74dbb6 100644
--- a/sound/usb/pcm.c
+++ b/sound/usb/pcm.c
@@ -71,6 +71,8 @@ static snd_pcm_uframes_t snd_usb_pcm_pointer(struct snd_pcm_substream *substream
unsigned int hwptr_done;
subs = (struct snd_usb_substream *)substream->runtime->private_data;
+ if (subs->stream->chip->shutdown)
+ return SNDRV_PCM_POS_XRUN;
spin_lock(&subs->lock);
hwptr_done = subs->hwptr_done;
substream->runtime->delay = snd_usb_pcm_delay(subs,
@@ -444,7 +446,6 @@ static int configure_endpoint(struct snd_usb_substream *subs)
{
int ret;
- mutex_lock(&subs->stream->chip->shutdown_mutex);
/* format changed */
stop_endpoints(subs, 0, 0, 0);
ret = snd_usb_endpoint_set_params(subs->data_endpoint,
@@ -455,7 +456,7 @@ static int configure_endpoint(struct snd_usb_substream *subs)
subs->cur_audiofmt,
subs->sync_endpoint);
if (ret < 0)
- goto unlock;
+ return ret;
if (subs->sync_endpoint)
ret = snd_usb_endpoint_set_params(subs->data_endpoint,
@@ -465,9 +466,6 @@ static int configure_endpoint(struct snd_usb_substream *subs)
subs->cur_rate,
subs->cur_audiofmt,
NULL);
-
-unlock:
- mutex_unlock(&subs->stream->chip->shutdown_mutex);
return ret;
}
@@ -505,7 +503,13 @@ static int snd_usb_hw_params(struct snd_pcm_substream *substream,
return -EINVAL;
}
- if ((ret = set_format(subs, fmt)) < 0)
+ down_read(&subs->stream->chip->shutdown_rwsem);
+ if (subs->stream->chip->shutdown)
+ ret = -ENODEV;
+ else
+ ret = set_format(subs, fmt);
+ up_read(&subs->stream->chip->shutdown_rwsem);
+ if (ret < 0)
return ret;
subs->interface = fmt->iface;
@@ -527,10 +531,12 @@ static int snd_usb_hw_free(struct snd_pcm_substream *substream)
subs->cur_audiofmt = NULL;
subs->cur_rate = 0;
subs->period_bytes = 0;
- mutex_lock(&subs->stream->chip->shutdown_mutex);
- stop_endpoints(subs, 0, 1, 1);
- deactivate_endpoints(subs);
- mutex_unlock(&subs->stream->chip->shutdown_mutex);
+ down_read(&subs->stream->chip->shutdown_rwsem);
+ if (!subs->stream->chip->shutdown) {
+ stop_endpoints(subs, 0, 1, 1);
+ deactivate_endpoints(subs);
+ }
+ up_read(&subs->stream->chip->shutdown_rwsem);
return snd_pcm_lib_free_vmalloc_buffer(substream);
}
@@ -552,12 +558,19 @@ static int snd_usb_pcm_prepare(struct snd_pcm_substream *substream)
return -ENXIO;
}
- if (snd_BUG_ON(!subs->data_endpoint))
- return -EIO;
+ down_read(&subs->stream->chip->shutdown_rwsem);
+ if (subs->stream->chip->shutdown) {
+ ret = -ENODEV;
+ goto unlock;
+ }
+ if (snd_BUG_ON(!subs->data_endpoint)) {
+ ret = -EIO;
+ goto unlock;
+ }
ret = set_format(subs, subs->cur_audiofmt);
if (ret < 0)
- return ret;
+ goto unlock;
iface = usb_ifnum_to_if(subs->dev, subs->cur_audiofmt->iface);
alts = &iface->altsetting[subs->cur_audiofmt->altset_idx];
@@ -567,12 +580,12 @@ static int snd_usb_pcm_prepare(struct snd_pcm_substream *substream)
subs->cur_audiofmt,
subs->cur_rate);
if (ret < 0)
- return ret;
+ goto unlock;
if (subs->need_setup_ep) {
ret = configure_endpoint(subs);
if (ret < 0)
- return ret;
+ goto unlock;
subs->need_setup_ep = false;
}
@@ -592,9 +605,11 @@ static int snd_usb_pcm_prepare(struct snd_pcm_substream *substream)
/* for playback, submit the URBs now; otherwise, the first hwptr_done
* updates for all URBs would happen at the same time when starting */
if (subs->direction == SNDRV_PCM_STREAM_PLAYBACK)
- return start_endpoints(subs, 1);
+ ret = start_endpoints(subs, 1);
- return 0;
+ unlock:
+ up_read(&subs->stream->chip->shutdown_rwsem);
+ return ret;
}
static struct snd_pcm_hardware snd_usb_hardware =
@@ -647,7 +662,7 @@ static int hw_check_valid_format(struct snd_usb_substream *subs,
return 0;
}
/* check whether the period time is >= the data packet interval */
- if (snd_usb_get_speed(subs->dev) != USB_SPEED_FULL) {
+ if (subs->speed != USB_SPEED_FULL) {
ptime = 125 * (1 << fp->datainterval);
if (ptime > pt->max || (ptime == pt->max && pt->openmax)) {
hwc_debug(" > check: ptime %u > max %u\n", ptime, pt->max);
@@ -925,7 +940,7 @@ static int setup_hw_info(struct snd_pcm_runtime *runtime, struct snd_usb_substre
return err;
param_period_time_if_needed = SNDRV_PCM_HW_PARAM_PERIOD_TIME;
- if (snd_usb_get_speed(subs->dev) == USB_SPEED_FULL)
+ if (subs->speed == USB_SPEED_FULL)
/* full speed devices have fixed data packet interval */
ptmin = 1000;
if (ptmin == 1000)
diff --git a/sound/usb/proc.c b/sound/usb/proc.c
index ebc1a5b5b3f1..d218f763501f 100644
--- a/sound/usb/proc.c
+++ b/sound/usb/proc.c
@@ -108,7 +108,7 @@ static void proc_dump_substream_formats(struct snd_usb_substream *subs, struct s
}
snd_iprintf(buffer, "\n");
}
- if (snd_usb_get_speed(subs->dev) != USB_SPEED_FULL)
+ if (subs->speed != USB_SPEED_FULL)
snd_iprintf(buffer, " Data packet interval: %d us\n",
125 * (1 << fp->datainterval));
// snd_iprintf(buffer, " Max Packet Size = %d\n", fp->maxpacksize);
@@ -124,7 +124,7 @@ static void proc_dump_ep_status(struct snd_usb_substream *subs,
return;
snd_iprintf(buffer, " Packet Size = %d\n", ep->curpacksize);
snd_iprintf(buffer, " Momentary freq = %u Hz (%#x.%04x)\n",
- snd_usb_get_speed(subs->dev) == USB_SPEED_FULL
+ subs->speed == USB_SPEED_FULL
? get_full_speed_hz(ep->freqm)
: get_high_speed_hz(ep->freqm),
ep->freqm >> 16, ep->freqm & 0xffff);
diff --git a/sound/usb/stream.c b/sound/usb/stream.c
index 083ed81160e5..1de0c8c002a8 100644
--- a/sound/usb/stream.c
+++ b/sound/usb/stream.c
@@ -90,6 +90,7 @@ static void snd_usb_init_substream(struct snd_usb_stream *as,
subs->direction = stream;
subs->dev = as->chip->dev;
subs->txfr_quirk = as->chip->txfr_quirk;
+ subs->speed = snd_usb_get_speed(subs->dev);
snd_usb_set_pcm_ops(as->pcm, stream);
diff --git a/sound/usb/usbaudio.h b/sound/usb/usbaudio.h
index b8233ebe250f..ef42797f56fb 100644
--- a/sound/usb/usbaudio.h
+++ b/sound/usb/usbaudio.h
@@ -37,7 +37,7 @@ struct snd_usb_audio {
struct usb_interface *pm_intf;
u32 usb_id;
struct mutex mutex;
- struct mutex shutdown_mutex;
+ struct rw_semaphore shutdown_rwsem;
unsigned int shutdown:1;
unsigned int probing:1;
unsigned int autosuspended:1;
diff --git a/tools/testing/ktest/ktest.pl b/tools/testing/ktest/ktest.pl
index b51d787176d3..c7ba7614061b 100755
--- a/tools/testing/ktest/ktest.pl
+++ b/tools/testing/ktest/ktest.pl
@@ -1740,8 +1740,10 @@ sub install {
open(IN, "$output_config") or dodie("Can't read config file");
while (<IN>) {
if (/CONFIG_MODULES(=y)?/) {
- $install_mods = 1 if (defined($1));
- last;
+ if (defined($1)) {
+ $install_mods = 1;
+ last;
+ }
}
}
close(IN);